1 /* -*- c++ -*-
2 FILE: WrapD3D.cpp
3 RCS REVISION: $Revision: 1.8 $
4 
5 COPYRIGHT: (c) 1999 -- 2003 Melinda Green, Don Hatch, and Jay Berkenbilt - Superliminal Software
6 
7 LICENSE: Free to use and modify for non-commercial purposes as long as the
8     following conditions are adhered to:
9     1) Obvious credit for the source of this code and the designs it embodies
10        are clearly made, and
11     2) Ports and derived versions of 4D Magic Cube programs are not distributed
12        without the express written permission of the authors.
13 
14 DESCRIPTION:
15     Abstraction on top of DirectX
16 */
17 
18 #include "WrapDx.h"
19 
20 #define RELEASE(x) if (x != NULL) {x->Release(); x = NULL;}
21 
22 
23 static bool s_software_render_only = true;  // hack to pass preference to
24                                             // enum callback
25 
WrapD3D()26 WrapD3D::WrapD3D()
27 {
28     m_pDirect3D = 0;
29     m_pDirect3DDevice = 0;
30     m_bTexturesDisabled = FALSE;
31     m_pCurrentDeviceInfo = 0;
32     m_deviceInfoCount = 0;
33 }
34 
~WrapD3D()35 WrapD3D::~WrapD3D()
36 {
37     Destroy();
38 }
39 
40 BOOL
Create(HWND hWnd,BOOL fullScreen,int width,int height,int bpp,const PALETTEENTRY * pPaletteEntries,int paletteEntryCount,bool software_render_only)41 WrapD3D::Create(HWND hWnd, BOOL fullScreen,
42                 int width, int height, int bpp,
43                 const PALETTEENTRY * pPaletteEntries,
44                 int paletteEntryCount, bool software_render_only)
45 {
46     s_software_render_only = software_render_only;  // passing parameter
47                                                     // through global -
48                                                     // dirty, I know
49 
50     if (!WrapDD::Create(hWnd,
51                         fullScreen, width, height, bpp,
52                         pPaletteEntries, paletteEntryCount))
53     {
54         return FALSE;
55     }
56 
57     return (D3DCreate() && D3DInit() && D3DSetMode());
58 }
59 
60 void
Destroy()61 WrapD3D::Destroy()
62 {
63     RELEASE(m_pDirect3DDevice);
64     RELEASE(m_pDirect3D);
65     WrapDD::Destroy();
66 
67     // ??? or in Create()
68     m_pCurrentDeviceInfo = 0;
69     m_deviceInfoCount = 0;
70 }
71 
72 void
DestroyButNotDirectDraw()73 WrapD3D::DestroyButNotDirectDraw()
74 {
75     RELEASE(m_pDirect3DDevice);
76     RELEASE(m_pDirect3D);
77     WrapDD::DestroyButNotDirectDraw();
78 
79     // ??? or in Create()
80     m_pCurrentDeviceInfo = 0;
81     m_deviceInfoCount = 0;
82 }
83 
84 BOOL
D3DCreate()85 WrapD3D::D3DCreate()
86 {
87     HRESULT result;
88 
89     result =
90         DirectDraw()->QueryInterface(IID_IDirect3D, (void **)&m_pDirect3D);
91     if (result != DD_OK)
92     {
93         Error("Creation of IDirect3D failed", result);
94         return FALSE;
95     }
96     return TRUE;
97 }
98 
99 BOOL
D3DInit()100 WrapD3D::D3DInit()
101 {
102     HRESULT result;
103 
104     result = m_pDirect3D->EnumDevices(EnumDevicesCallback, this);
105     if (result != DD_OK)
106     {
107         Error("EnumDevices failed", result);
108     }
109 
110     return (result == DD_OK);
111 }
112 
113 // Initialize the D3D objects which change when the mode changes.
114 BOOL
D3DSetMode()115 WrapD3D::D3DSetMode()
116 {
117     HRESULT result;
118 
119     // Create the viewport and device objects.
120     if (m_pCurrentDeviceInfo->HWDesc.dcmColorModel)
121     {
122         // Hardware driver
123         if (m_bOnlySoftRender)
124         {
125             Error
126                 ("Failed to place vital surfaces in video memory for hardware driver",
127                  DDERR_GENERIC);
128             return FALSE;
129         }
130         if (m_pCurrentDeviceInfo->HWDesc.dpcTriCaps.
131             dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE)
132         {
133             m_bTexturesDisabled = FALSE;
134         }
135         else
136         {
137             m_bTexturesDisabled = TRUE;
138         }
139 
140         if (!CreateZBuffer
141             (DDSCAPS_VIDEOMEMORY, ZBufferDepth(m_pCurrentDeviceInfo)))
142         {
143             return FALSE;
144         }
145     }
146     else
147     {
148         // Software driver
149         if (m_pCurrentDeviceInfo->HELDesc.dpcTriCaps.
150             dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE)
151         {
152             m_bTexturesDisabled = FALSE;
153         }
154         else
155         {
156             m_bTexturesDisabled = TRUE;
157         }
158 
159         if (!CreateZBuffer
160             (DDSCAPS_SYSTEMMEMORY, ZBufferDepth(m_pCurrentDeviceInfo)))
161         {
162             return FALSE;
163         }
164     }
165 
166     result = BackBuffer()->QueryInterface(m_pCurrentDeviceInfo->Guid,
167                                           (void **)&m_pDirect3DDevice);
168     if (result != DD_OK)
169     {
170         Error("Create D3D device failed", result);
171         return FALSE;
172     }
173 
174     {
175         Mode
176             mode = CurrentMode();
177 
178         // enumerate display modes again - m_pCurrentDeviceInfo is now set
179         if (!EnumerateDisplayModes())
180         {
181             return FALSE;
182         }
183 
184         // NOTE: the current mode may have been removed
185         if (IsFullScreen())
186         {
187             if (!IsSupportedMode(mode.width, mode.height, mode.bitsPerPixel))
188             {
189                 Error("This device cannot support the current display mode",
190                       DDERR_GENERIC);
191                 return FALSE;
192             }
193         }
194     }
195 
196     return TRUE;
197 }
198 
199 BOOL
FilterDisplayModes(LPDDSURFACEDESC pddsd)200 WrapD3D::FilterDisplayModes(LPDDSURFACEDESC pddsd)
201 {
202     if (m_pCurrentDeviceInfo)
203     {
204         DWORD
205             deviceDepth;
206 
207         if (m_pCurrentDeviceInfo->HWDesc.dwFlags & D3DDD_DEVICERENDERBITDEPTH)
208         {
209             deviceDepth = m_pCurrentDeviceInfo->HWDesc.dwDeviceRenderBitDepth;
210         }
211         else
212         {
213             deviceDepth =
214                 m_pCurrentDeviceInfo->HELDesc.dwDeviceRenderBitDepth;
215         }
216 
217         return (((pddsd->ddpfPixelFormat.dwRGBBitCount == 8UL) &&
218                  (deviceDepth & DDBD_8)) ||
219                 ((pddsd->ddpfPixelFormat.dwRGBBitCount == 16UL) &&
220                  (deviceDepth & DDBD_16)));
221     }
222 
223     return TRUE;
224 }
225 
226 int
ZBufferDepth(Direct3DDeviceInfo * pDeviceInfo)227 WrapD3D::ZBufferDepth(Direct3DDeviceInfo * pDeviceInfo)
228 {
229     int
230         depth;
231     DWORD
232         deviceDepth;
233 
234     if (pDeviceInfo->HWDesc.dwFlags & D3DDD_DEVICEZBUFFERBITDEPTH)
235     {
236         deviceDepth = pDeviceInfo->HWDesc.dwDeviceZBufferBitDepth;
237     }
238     else
239     {
240         deviceDepth = pDeviceInfo->HELDesc.dwDeviceZBufferBitDepth;
241     }
242 
243     if (deviceDepth & DDBD_32)
244         depth = 32;
245     else if (deviceDepth & DDBD_24)
246         depth = 24;
247     else if (deviceDepth & DDBD_16)
248         depth = 16;
249     else if (deviceDepth & DDBD_8)
250         depth = 8;
251     else
252         depth = -1;
253 
254     return depth;
255 }
256 
257 HRESULT
EnumDevicesCallback(GUID * pGuid,char * pDeviceDescription,char * pDeviceName,LPD3DDEVICEDESC pHWDesc,LPD3DDEVICEDESC pHELDesc)258 WrapD3D::EnumDevicesCallback(GUID * pGuid,
259                              char *pDeviceDescription,
260                              char *pDeviceName,
261                              LPD3DDEVICEDESC pHWDesc,
262                              LPD3DDEVICEDESC pHELDesc)
263 {
264     m_deviceInfo[m_deviceInfoCount].Initialize(pGuid,
265                                                pDeviceDescription,
266                                                pDeviceName,
267                                                pHWDesc, pHELDesc);
268 
269     // Chooses hardware over software, RGB lights over mono lights
270     // If software only, choose Ramp over RGB.
271 
272     if (!m_pCurrentDeviceInfo)
273     {
274         // chooses anything over nothing
275         m_pCurrentDeviceInfo = &m_deviceInfo[m_deviceInfoCount];
276     }
277     else
278     {
279         // this block copied from below to all SW preference
280         if (s_software_render_only)
281         {
282             if (!m_pCurrentDeviceInfo->HWDesc.dcmColorModel)
283             {
284                 if (!m_pCurrentDeviceInfo->HELDesc.dcmColorModel)
285                 {
286                     m_pCurrentDeviceInfo = &m_deviceInfo[m_deviceInfoCount];
287                 }
288                 else if (pHELDesc->dcmColorModel & D3DCOLOR_MONO &&
289                          m_pCurrentDeviceInfo->HELDesc.
290                          dcmColorModel & D3DCOLOR_RGB)
291                 {
292                     m_pCurrentDeviceInfo = &m_deviceInfo[m_deviceInfoCount];
293                 }
294             }
295         }
296         else if (pHWDesc->dcmColorModel && !m_bOnlySoftRender)
297         {
298             // hardware device found
299             if (!m_pCurrentDeviceInfo->HWDesc.dcmColorModel)
300             {
301                 m_pCurrentDeviceInfo = &m_deviceInfo[m_deviceInfoCount];
302             }
303             else if (pHWDesc->dcmColorModel & D3DCOLOR_RGB &&
304                      m_pCurrentDeviceInfo->HWDesc.
305                      dcmColorModel & D3DCOLOR_MONO)
306             {
307                 m_pCurrentDeviceInfo = &m_deviceInfo[m_deviceInfoCount];
308             }
309         }
310         else if (!m_pCurrentDeviceInfo->HWDesc.dcmColorModel)
311         {
312             if (!m_pCurrentDeviceInfo->HELDesc.dcmColorModel)
313             {
314                 m_pCurrentDeviceInfo = &m_deviceInfo[m_deviceInfoCount];
315             }
316             else if (pHELDesc->dcmColorModel & D3DCOLOR_MONO &&
317                      m_pCurrentDeviceInfo->HELDesc.
318                      dcmColorModel & D3DCOLOR_RGB)
319             {
320                 m_pCurrentDeviceInfo = &m_deviceInfo[m_deviceInfoCount];
321             }
322         }
323     }
324     m_deviceInfoCount++;
325 
326     if (m_deviceInfoCount == maxDeviceInfoCount)
327     {
328         return (D3DENUMRET_CANCEL);
329     }
330 
331     return (D3DENUMRET_OK);
332 }
333 
334 HRESULT CALLBACK
EnumDevicesCallback(GUID * pGuid,char * pDeviceDescription,char * pDeviceName,LPD3DDEVICEDESC pHWDesc,LPD3DDEVICEDESC pHELDesc,void * pContext)335 WrapD3D::EnumDevicesCallback(GUID * pGuid,
336                              char *pDeviceDescription,
337                              char *pDeviceName,
338                              LPD3DDEVICEDESC pHWDesc,
339                              LPD3DDEVICEDESC pHELDesc, void *pContext)
340 {
341     WrapD3D    *
342         pDirect3D = (WrapD3D *) pContext;
343 
344     return pDirect3D->EnumDevicesCallback(pGuid,
345                                           pDeviceDescription,
346                                           pDeviceName, pHWDesc, pHELDesc);
347 }
348 
349 // Returns a string describing the given error code.
350 const char *
ErrorToString(HRESULT error)351 WrapD3D::ErrorToString(HRESULT error)
352 {
353     switch (error)
354     {
355     case DD_OK:
356         return "No error.\0";
357     case D3DERR_BADMAJORVERSION:
358         return "D3DERR_BADMAJORVERSION\0";
359     case D3DERR_BADMINORVERSION:
360         return "D3DERR_BADMINORVERSION\0";
361     case D3DERR_EXECUTE_LOCKED:
362         return "D3DERR_EXECUTE_LOCKED\0";
363     case D3DERR_EXECUTE_NOT_LOCKED:
364         return "D3DERR_EXECUTE_NOT_LOCKED\0";
365     case D3DERR_EXECUTE_CREATE_FAILED:
366         return "D3DERR_EXECUTE_CREATE_FAILED\0";
367     case D3DERR_EXECUTE_DESTROY_FAILED:
368         return "D3DERR_EXECUTE_DESTROY_FAILED\0";
369     case D3DERR_EXECUTE_LOCK_FAILED:
370         return "D3DERR_EXECUTE_LOCK_FAILED\0";
371     case D3DERR_EXECUTE_UNLOCK_FAILED:
372         return "D3DERR_EXECUTE_UNLOCK_FAILED\0";
373     case D3DERR_EXECUTE_FAILED:
374         return "D3DERR_EXECUTE_FAILED\0";
375     case D3DERR_EXECUTE_CLIPPED_FAILED:
376         return "D3DERR_EXECUTE_CLIPPED_FAILED\0";
377     case D3DERR_TEXTURE_NO_SUPPORT:
378         return "D3DERR_TEXTURE_NO_SUPPORT\0";
379     case D3DERR_TEXTURE_NOT_LOCKED:
380         return "D3DERR_TEXTURE_NOT_LOCKED\0";
381     case D3DERR_TEXTURE_LOCKED:
382         return "D3DERR_TEXTURELOCKED\0";
383     case D3DERR_TEXTURE_CREATE_FAILED:
384         return "D3DERR_TEXTURE_CREATE_FAILED\0";
385     case D3DERR_TEXTURE_DESTROY_FAILED:
386         return "D3DERR_TEXTURE_DESTROY_FAILED\0";
387     case D3DERR_TEXTURE_LOCK_FAILED:
388         return "D3DERR_TEXTURE_LOCK_FAILED\0";
389     case D3DERR_TEXTURE_UNLOCK_FAILED:
390         return "D3DERR_TEXTURE_UNLOCK_FAILED\0";
391     case D3DERR_TEXTURE_LOAD_FAILED:
392         return "D3DERR_TEXTURE_LOAD_FAILED\0";
393     case D3DERR_MATRIX_CREATE_FAILED:
394         return "D3DERR_MATRIX_CREATE_FAILED\0";
395     case D3DERR_MATRIX_DESTROY_FAILED:
396         return "D3DERR_MATRIX_DESTROY_FAILED\0";
397     case D3DERR_MATRIX_SETDATA_FAILED:
398         return "D3DERR_MATRIX_SETDATA_FAILED\0";
399     case D3DERR_SETVIEWPORTDATA_FAILED:
400         return "D3DERR_SETVIEWPORTDATA_FAILED\0";
401     case D3DERR_MATERIAL_CREATE_FAILED:
402         return "D3DERR_MATERIAL_CREATE_FAILED\0";
403     case D3DERR_MATERIAL_DESTROY_FAILED:
404         return "D3DERR_MATERIAL_DESTROY_FAILED\0";
405     case D3DERR_MATERIAL_SETDATA_FAILED:
406         return "D3DERR_MATERIAL_SETDATA_FAILED\0";
407     case D3DERR_LIGHT_SET_FAILED:
408         return "D3DERR_LIGHT_SET_FAILED\0";
409     default:
410         return WrapDD::ErrorToString(error);
411     }
412 }
413 
414 // Local Variables:
415 // c-basic-offset: 4
416 // c-comment-only-line-offset: 0
417 // c-file-offsets: ((defun-block-intro . +) (block-open . 0) (substatement-open . 0) (statement-cont . +) (statement-case-open . +4) (arglist-intro . +) (arglist-close . +) (inline-open . 0))
418 // indent-tabs-mode: nil
419 // End:
420