#![allow(dead_code)]
use crate::*;
use crate::d3d9::*;
use winapi::Interface;
use winapi::shared::d3d9::{IDirect3DSurface9, IDirect3DResource9};
use winapi::shared::d3d9types::*;
use winapi::shared::windef::HDC;
use winapi::um::unknwnbase::IUnknown;
use std::ptr::{null, null_mut};
#[derive(Clone)] #[repr(transparent)]
pub struct Surface(pub(crate) mcom::Rc<IDirect3DSurface9>);
unsafe impl AsSafe<IUnknown > for Surface { fn as_safe(&self) -> &IUnknown { &***self.0 } }
unsafe impl AsSafe<IDirect3DResource9 > for Surface { fn as_safe(&self) -> &IDirect3DResource9 { &**self.0 } }
unsafe impl AsSafe<IDirect3DSurface9 > for Surface { fn as_safe(&self) -> &IDirect3DSurface9 { &*self.0 } }
pub trait IDirect3DSurface9Ext : AsSafe<IDirect3DSurface9> {
fn get_container<C: Raw>(&self) -> Result<C, MethodError> where C::Raw : Interface {
let mut container = null_mut();
let hr = unsafe { self.as_winapi().GetContainer(&C::Raw::uuidof(), &mut container) };
MethodError::check("IDirect3DVolume9::GetContainer", hr)?;
Ok(unsafe { C::from_raw(container.cast()) })
}
fn get_dc(&self) -> Result<HDC, MethodError> {
let mut hdc = null_mut();
let hr = unsafe { self.as_winapi().GetDC(&mut hdc) };
MethodError::check("IDirect3DSurface9::GetDC", hr)?;
Ok(hdc)
}
fn get_desc(&self) -> Result<SurfaceDesc, MethodError> {
let mut desc = SurfaceDesc::default();
let hr = unsafe { self.as_winapi().GetDesc(&mut *desc) };
MethodError::check("IDirect3DSurface9::GetDesc", hr)?;
Ok(desc)
}
unsafe fn lock_rect_unchecked(&self, rect: impl IntoRectOrFull, flags: impl Into<Lock>) -> Result<D3DLOCKED_RECT, MethodError> {
let rect = rect.into_rect();
let rect = rect.as_ref().map_or(null(), |b| &**b);
let mut locked = std::mem::zeroed::<D3DLOCKED_RECT>();
let hr = self.as_winapi().LockRect(&mut locked, rect.cast(), flags.into().into());
MethodError::check("IDirect3DSurface9::LockRect", hr)?;
Ok(locked)
}
fn release_dc(&self, hdc: HDC) -> Result<(), MethodError> {
let hr = unsafe { self.as_winapi().ReleaseDC(hdc) };
MethodError::check("IDirect3DSurface9::ReleaseDC", hr)
}
fn unlock_rect(&self) -> Result<(), MethodError> {
let hr = unsafe { self.as_winapi().UnlockRect() };
MethodError::check("IDirect3DSurface9::UnlockRect", hr)
}
}
impl<T: AsSafe<IDirect3DSurface9>> IDirect3DSurface9Ext for T {}
#[cfg(test)] mod tests {
use dev::d3d9::*;
#[test] fn get_set_depth_stencil_surface() {
let device = device_test_pp(false, |pp, _| {
pp.EnableAutoDepthStencil = true.into();
pp.AutoDepthStencilFormat = Format::D24S8.into();
}).unwrap();
let ds = device.get_depth_stencil_surface().unwrap().unwrap();
assert_eq!(ds.as_raw(), device.get_depth_stencil_surface().unwrap().unwrap().as_raw());
device.set_depth_stencil_surface(Some(&ds)).unwrap();
assert_eq!(ds.as_raw(), device.get_depth_stencil_surface().unwrap().unwrap().as_raw());
device.set_depth_stencil_surface(None).unwrap();
assert!(device.get_depth_stencil_surface().unwrap().is_none());
}
#[test] fn get_set_render_target() {
let device = device_test();
let max_rts = 4;
let rt0 = device.get_render_target(0).expect("RT0 inaccessable").expect("RT0 null");
device.set_render_target(0, Some(&rt0)).unwrap();
assert_eq!(rt0.as_raw(), device.get_render_target(0).expect("RT0 inaccessable").expect("RT0 null").as_raw());
assert_eq!(D3DERR::INVALIDCALL, device.set_render_target(0, None));
assert_eq!(rt0.as_raw(), device.get_render_target(0).expect("RT0 inaccessable").expect("RT0 null").as_raw());
device.set_render_target(0, Some(&rt0)).unwrap();
assert_eq!(rt0.as_raw(), device.get_render_target(0).expect("RT0 inaccessable").expect("RT0 null").as_raw());
for _i in 1..max_rts {
}
for i in [100, 1000, 100000, !0].iter().copied() {
assert_eq!(D3DERR::INVALIDCALL, device.set_render_target(i, Some(&rt0)));
}
}
#[test] fn clear() {
for (ds_fmt, has_depth, has_sten, require ) in [
(None, false, false, true ),
(Some(Format::D24S8), true, true, true ),
(Some(Format::D24X8), true, false, true ),
(Some(Format::D16), true, false, true ),
(Some(Format::D15S1), true, true, false ),
(Some(Format::D24X4S4), true, true, false ),
(Some(Format::D16_LOCKABLE), true, false, false ), (Some(Format::D24FS8), true, true, false ),
(Some(Format::D32), true, false, false ),
(Some(Format::D32_LOCKABLE), true, false, false ),
(Some(Format::D32F_LOCKABLE), true, false, false ), (Some(Format::X8_LOCKABLE), false, false, false ),
].iter().copied() {
let device = device_test_pp(false, |pp, _| {
if let Some(ds_fmt) = ds_fmt {
pp.EnableAutoDepthStencil = true.into();
pp.AutoDepthStencilFormat = ds_fmt.into();
}
});
if device.is_err() && !require { continue }
let device = device.unwrap_or_else(|err| panic!("bad depth-stencil: {:?} {:?}", ds_fmt, err));
for remove_ds in [false, true].iter().copied() {
let autods = device.get_depth_stencil_surface().unwrap();
if remove_ds {
if autods.is_none() { continue }
device.set_depth_stencil_surface(None).unwrap();
}
let has_depth = has_depth && !remove_ds;
let has_sten = has_sten && !remove_ds;
for (target, depth, stencil ) in [
(None, None, None ), (Some(Color::argb(0xFF112233)), Some(0.5), Some(0xFFFF)), (Some(Color::argb(0xFF112233)), None, None ),
(None, Some(-1.0), None ),
(None, Some(-0.5), None ),
(None, Some( 0.0), None ),
(None, Some( 0.5), None ),
(None, Some( 1.0), None ),
(None, Some( 1.5), None ),
(None, Some( 2.0), None ),
(None, Some( 2.0), None ),
(None, Some(f32::MIN), None ),
(None, Some(f32::MIN_POSITIVE), None ),
(None, Some(f32::NAN), None ),
(None, Some(f32::INFINITY), None ),
(None, None, Some(0) ),
(None, None, Some(0xFF) ),
(None, None, Some(!0) ),
].iter().copied() {
println!("ds_fmt={:?} target={:?} depth={:?} stencil={:?}", ds_fmt, target, depth, stencil);
for rects in [
None,
Some(&[][..]),
Some(&[Rect::from([0..0, 0..0])][..]), Some(&[Rect::from([0..100, 0..100])][..]), Some(&[Rect::from([100..10000, 100..10000])][..]), Some(&[Rect::from([-10000..10000, -10000..10000])][..]), Some(&[Rect::from([10000..-10000, 10000..-10000])][..]), Some(&[Rect::from([0..100, 0..100]), Rect::from([0..100, 0..100])][..]), ].iter().copied() {
let result = device.clear(rects, target, depth, stencil);
println!(" rects: {: <70} == {:?}", format!("{:?}", rects), result);
if target.is_none() && depth.is_none() && stencil.is_none() {
assert_eq!(D3DERR::INVALIDCALL, result, "expected failure - target=depth=stencil=None - nothing to clear");
} else if depth.is_some() && !has_depth {
assert_eq!(D3DERR::INVALIDCALL, result, "expected failure - depth={:?} was specified but no depth buffer was bound", depth);
} else if stencil.is_some() && !has_sten {
assert_eq!(D3DERR::INVALIDCALL, result, "expected failure - stencil={:?} was specified but no stencil buffer was bound", stencil);
} else {
result.expect("expected success, got");
}
}
}
device.set_depth_stencil_surface(autods.as_ref()).unwrap();
}
}
}
#[test] fn color_fill() {
let device = device_test();
let rt0 = device.get_render_target(0).unwrap().unwrap();
device.color_fill(&rt0, None, Color::argb(0xFF112233)).unwrap();
device.color_fill(&rt0, Some(Rect::from([0..1, 0..1])), Color::argb(0xFF112233)).unwrap();
assert_eq!(D3DERR::INVALIDCALL, device.color_fill(&rt0, Some( Rect::from([-1..1, -1..1]) ), Color::argb(0xFF112233)));
assert_eq!(D3DERR::INVALIDCALL, device.color_fill(&rt0, Some( Rect::from([0..100000, 0..100000]) ), Color::argb(0xFF112233)));
assert_eq!(D3DERR::INVALIDCALL, device.color_fill(&rt0, Some( Rect::from([10000..-10000, 10000..-10000]) ), Color::argb(0xFF112233)));
assert_eq!(D3DERR::INVALIDCALL, device.color_fill(&rt0, Some( Rect::from([-10000..10000, -10000..10000]) ), Color::argb(0xFF112233)));
}
}