the old-new win32 port
[picodrive.git] / platform / win32 / GenaDrive / Direct.cpp
1 #include "app.h"\r
2 \r
3 #ifdef USE_D3D\r
4 // d3d\r
5 static IDirect3D8 *Direct3D=NULL;\r
6 IDirect3DDevice8 *Device=NULL;\r
7 IDirect3DSurface8 *DirectBack=NULL; // Back Buffer\r
8 \r
9 static IDirect3DVertexBuffer8 *VertexBuffer=NULL;\r
10 \r
11 struct CustomVertex\r
12 {\r
13   float x,y,z; // Vertex cordinates\r
14   unsigned int colour;\r
15   float u,v; // Texture coordinates\r
16 };\r
17 #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)\r
18 \r
19 static CustomVertex VertexList[4];\r
20 #endif\r
21 \r
22 // ddraw\r
23 #include <ddraw.h>\r
24 \r
25 LPDIRECTDRAW7        m_pDD = NULL;\r
26 LPDIRECTDRAWSURFACE7 m_pddsFrontBuffer = NULL;\r
27 LPDIRECTDRAWSURFACE7 m_pddsBackBuffer = NULL;\r
28 \r
29 // quick and dirty stuff..\r
30 static void DirectExitDDraw()\r
31 {\r
32   RELEASE(m_pddsBackBuffer);\r
33   RELEASE(m_pddsFrontBuffer);\r
34   RELEASE(m_pDD);\r
35 }\r
36 \r
37 static int DirectDrawInit()\r
38 {\r
39   HRESULT ret;\r
40   LPDIRECTDRAWCLIPPER pcClipper = NULL;\r
41   DDSURFACEDESC2 ddsd;\r
42 \r
43   ret = DirectDrawCreateEx(NULL, (VOID**)&m_pDD, IID_IDirectDraw7, NULL);\r
44   if (ret) { LOGFAIL(); return 1; }\r
45 \r
46   // Set cooperative level\r
47   ret = m_pDD->SetCooperativeLevel( FrameWnd, DDSCL_NORMAL );\r
48   if (ret) { LOGFAIL(); goto fail; }\r
49 \r
50   // Create the primary surface\r
51   ZeroMemory( &ddsd, sizeof( ddsd ) );\r
52   ddsd.dwSize         = sizeof( ddsd );\r
53   ddsd.dwFlags        = DDSD_CAPS;\r
54   ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;\r
55 \r
56   ret = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL );\r
57   if (ret) { LOGFAIL(); goto fail; }\r
58 \r
59   // Create the backbuffer surface\r
60   ddsd.dwFlags        = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;\r
61   ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;\r
62   ddsd.dwWidth        = EmuWidth;\r
63   ddsd.dwHeight       = EmuHeight;\r
64 \r
65   ret = m_pDD->CreateSurface( &ddsd, &m_pddsBackBuffer, NULL );\r
66   if (ret) { LOGFAIL(); goto fail; }\r
67 \r
68   // clipper\r
69   ret = m_pDD->CreateClipper( 0, &pcClipper, NULL );\r
70   if (ret) { LOGFAIL(); goto fail; }\r
71 \r
72   ret = pcClipper->SetHWnd( 0, FrameWnd );\r
73   if (ret) { LOGFAIL(); goto fail; }\r
74 \r
75   ret = m_pddsFrontBuffer->SetClipper( pcClipper );\r
76   if (ret) { LOGFAIL(); goto fail; }\r
77 \r
78   RELEASE(pcClipper);\r
79   return 0;\r
80 \r
81 fail:\r
82   RELEASE(pcClipper);\r
83   DirectExitDDraw();\r
84   return 1;\r
85 }\r
86 \r
87 static int DirectScreenDDraw()\r
88 {\r
89   DDSURFACEDESC2 sd;\r
90   unsigned short *ps=EmuScreen;\r
91   int ret, x, y;\r
92 \r
93   memset(&sd, 0, sizeof(sd));\r
94   sd.dwSize = sizeof(sd);\r
95   ret = m_pddsBackBuffer->Lock(NULL, &sd, DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_WRITEONLY, NULL);\r
96   if (ret) { LOGFAIL(); return 1; }\r
97 \r
98   //lprintf("w: %i h: %i pi: %i pf: %i\n", sd.dwWidth, sd.dwHeight, sd.lPitch, sd.ddpfPixelFormat.dwRGBBitCount);\r
99 \r
100   if (sd.ddpfPixelFormat.dwRGBBitCount == 32)\r
101   {\r
102     int *dst = (int *)sd.lpSurface;\r
103     for (y = 0; y < EmuHeight; y++)\r
104     {\r
105       for (x = 0; x < EmuWidth; x++)\r
106       {\r
107         int s = *ps++;\r
108         dst[x] = ((s&0xf800)<<8) | ((s&0x07e0)<<5) | ((s&0x001f)<<3);\r
109       }\r
110       dst = (int *)((char *)dst + sd.lPitch);\r
111     }\r
112   }\r
113   else if (sd.ddpfPixelFormat.dwRGBBitCount == 24) /* wine uses this for me */\r
114   {\r
115     void *dst = sd.lpSurface;\r
116     for (y = 0; y < EmuHeight; y++)\r
117     {\r
118       unsigned char *dst1 = (unsigned char *) dst;\r
119       for (x = 0; x < EmuWidth; x++, dst1 += 3)\r
120       {\r
121         int s = *ps++;\r
122         dst1[2] = (s&0xf800)>>8; dst1[1] = (s&0x07e0)>>3; dst1[0] = s<<3; // BGR\r
123       }\r
124       dst = (void *)((char *)dst + sd.lPitch);\r
125     }\r
126   }\r
127   else if (sd.ddpfPixelFormat.dwRGBBitCount == 16)\r
128   {\r
129     unsigned short *dst = (unsigned short *)sd.lpSurface;\r
130     for (y = 0; y < EmuHeight; y++)\r
131     {\r
132       memcpy(dst, ps, EmuWidth*2);\r
133       ps += EmuWidth;\r
134       dst = (unsigned short *)((char *)dst + sd.lPitch);\r
135     }\r
136   }\r
137   else\r
138   {\r
139     LOGFAIL();\r
140   }\r
141 \r
142   ret = m_pddsBackBuffer->Unlock(NULL);\r
143   if (ret) { LOGFAIL(); return 1; }\r
144   return 0;\r
145 }\r
146 \r
147 static int DirectClearDDraw(unsigned int colour)\r
148 {\r
149   int ret;\r
150   DDBLTFX ddbltfx;\r
151   ZeroMemory( &ddbltfx, sizeof(ddbltfx) );\r
152   ddbltfx.dwSize      = sizeof(ddbltfx);\r
153   ddbltfx.dwFillColor = colour;\r
154 \r
155   if (m_pddsBackBuffer != NULL)\r
156     ret = m_pddsBackBuffer->Blt( NULL, NULL, NULL, DDBLT_COLORFILL, &ddbltfx );\r
157   if (ret) { LOGFAIL(); return 1; }\r
158   return 0;\r
159 }\r
160 \r
161 static int DirectPresentDDraw()\r
162 {\r
163   int ret = 0;\r
164   if (FrameRectMy.right - FrameRectMy.left > 0 && FrameRectMy.bottom - FrameRectMy.top > 0)\r
165     ret = m_pddsFrontBuffer->Blt(&FrameRectMy, m_pddsBackBuffer, &EmuScreenRect, DDBLT_WAIT, NULL);\r
166   if (ret) { LOGFAIL(); return 1; }\r
167   return 0;\r
168 }\r
169 \r
170 \r
171 /* D3D */\r
172 \r
173 int DirectInit()\r
174 {\r
175 #if USE_D3D\r
176   D3DPRESENT_PARAMETERS d3dpp;\r
177   D3DDISPLAYMODE mode;\r
178   int i,u,ret=0;\r
179 \r
180   memset(&d3dpp,0,sizeof(d3dpp));\r
181   memset(&mode,0,sizeof(mode));\r
182 \r
183   Direct3D=Direct3DCreate8(D3D_SDK_VERSION); if (Direct3D==NULL) return 1;\r
184 \r
185   // Set up the structure used to create the D3D device:\r
186   d3dpp.BackBufferWidth =MainWidth;\r
187   d3dpp.BackBufferHeight=MainHeight;\r
188   d3dpp.BackBufferCount =1;\r
189   d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;\r
190   d3dpp.MultiSampleType =D3DMULTISAMPLE_NONE;\r
191 \r
192 #ifdef _XBOX\r
193   d3dpp.BackBufferFormat=D3DFMT_X8R8G8B8;\r
194   d3dpp.FullScreen_RefreshRateInHz=60;\r
195 #else\r
196   Direct3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&mode);\r
197   d3dpp.BackBufferFormat=mode.Format;\r
198   d3dpp.Windowed=1;\r
199   d3dpp.hDeviceWindow=FrameWnd;\r
200 #endif\r
201 \r
202   // Try to create a device with hardware vertex processing:\r
203   for (i=0;i<3;i++)\r
204   {\r
205     int behave=D3DCREATE_HARDWARE_VERTEXPROCESSING;\r
206 \r
207     // Try software vertex processing:\r
208     if (i==1) behave=D3DCREATE_MIXED_VERTEXPROCESSING;\r
209     if (i==2) behave=D3DCREATE_SOFTWARE_VERTEXPROCESSING;\r
210 \r
211     Direct3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,FrameWnd,\r
212         behave|D3DCREATE_MULTITHREADED,&d3dpp,&Device);\r
213     if (Device) break;\r
214   }\r
215 \r
216   if (Device==NULL)\r
217   {\r
218 #if 0\r
219     // try ref\r
220     Direct3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_REF,FrameWnd,\r
221         D3DCREATE_SOFTWARE_VERTEXPROCESSING|D3DCREATE_MULTITHREADED,&d3dpp,&Device);\r
222     if (Device==NULL) goto fail0;\r
223     HMODULE test = LoadLibrary("d3d8d.dll");\r
224     if (test != NULL) FreeLibrary(test);\r
225     else {\r
226       error("Sorry, but this program requires Direct3D with hardware acceleration.\n\n"\r
227             "You can try using Direct3D software emulation, but you have to install "\r
228             "DirectX SDK for it to work\n(it seems to be missing now).");\r
229       goto fail1;\r
230     }\r
231 #else\r
232     goto fail1;\r
233 #endif\r
234   }\r
235 \r
236   Device->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&DirectBack);\r
237   if (DirectBack==NULL) goto fail1;\r
238 \r
239   Device->CreateVertexBuffer(sizeof(VertexList),0,D3DFVF_CUSTOMVERTEX,D3DPOOL_DEFAULT,&VertexBuffer);\r
240   if (VertexBuffer==NULL) goto fail2;\r
241 \r
242   ret=TexScreenInit(); if (ret) goto fail3;\r
243 \r
244   //FontInit();\r
245 \r
246   Device->SetRenderState(D3DRS_LIGHTING,0); // Turn off lighting\r
247 \r
248   // Set up texture modes:\r
249   Device->SetTextureStageState(0,D3DTSS_ADDRESSU,D3DTADDRESS_CLAMP);\r
250   Device->SetTextureStageState(0,D3DTSS_ADDRESSV,D3DTADDRESS_CLAMP);\r
251 \r
252   return 0;\r
253 \r
254 fail3:\r
255   RELEASE(VertexBuffer)\r
256 fail2:\r
257   RELEASE(DirectBack)\r
258 fail1:\r
259   RELEASE(Device)\r
260 fail0:\r
261   RELEASE(Direct3D)\r
262 \r
263   // error("Failed to use Direct3D, trying DirectDraw..");\r
264 #endif\r
265   // try DirectDraw\r
266   return DirectDrawInit();\r
267 }\r
268 \r
269 void DirectExit()\r
270 {\r
271 #ifdef USE_D3D\r
272   TexScreenExit();\r
273 \r
274   // d3d\r
275   RELEASE(VertexBuffer)\r
276   RELEASE(DirectBack)\r
277   RELEASE(Device)\r
278   RELEASE(Direct3D)\r
279 #endif\r
280   DirectExitDDraw();\r
281 }\r
282 \r
283 int DirectClear(unsigned int colour)\r
284 {\r
285 #ifdef USE_D3D\r
286   if (Device != NULL) {\r
287     Device->Clear(0,NULL,D3DCLEAR_TARGET,colour,1.0f,0);\r
288     return 0;\r
289   }\r
290 #endif\r
291 \r
292   return DirectClearDDraw(colour);\r
293 }\r
294 \r
295 int DirectPresent()\r
296 {\r
297 #ifdef USE_D3D\r
298   if (Device != NULL) {\r
299     Device->Present(NULL,NULL,NULL,NULL);\r
300     return 0;\r
301   }\r
302 #endif\r
303 \r
304   return DirectPresentDDraw();\r
305 }\r
306 \r
307 #ifdef USE_D3D\r
308 #define PI 3.14159265f\r
309 \r
310 static int MakeVertexList()\r
311 {\r
312   struct CustomVertex *vert=NULL,*pv=NULL;\r
313   float dist=0.0f;\r
314   float scalex=0.0f,scaley=0.0f;\r
315   unsigned int colour=0xffffff;\r
316   float right=0.0f,bottom=0.0f;\r
317 \r
318   if (LoopMode!=8) colour=0x102040;\r
319 \r
320   dist=10.0f; scalex=dist*1.3333f; scaley=dist;\r
321 \r
322   scalex*=640.0f/(float)MainWidth;\r
323   scaley*=448.0f/(float)MainHeight;\r
324 \r
325   vert=VertexList;\r
326 \r
327   // Put the vertices for the corners of the screen:\r
328   pv=vert;\r
329   pv->z=dist;\r
330   pv->x=-scalex; pv->y=scaley;\r
331   pv->colour=colour; pv++;\r
332 \r
333   *pv=vert[0]; pv->x= scalex; pv->y= scaley; pv++;\r
334   *pv=vert[0]; pv->x=-scalex; pv->y=-scaley; pv++;\r
335   *pv=vert[0]; pv->x= scalex; pv->y=-scaley; pv++;\r
336 \r
337   // Find where the screen images ends on the texture\r
338   right =(float)EmuWidth /(float)TexWidth;\r
339   bottom=(float)EmuHeight/(float)TexHeight;\r
340 \r
341   // Write texture coordinates:\r
342   pv=vert;\r
343   pv->u=0.0f;  pv->v=0.00f;  pv++;\r
344   pv->u=right; pv->v=0.00f;  pv++;\r
345   pv->u=0.0f;  pv->v=bottom; pv++;\r
346   pv->u=right; pv->v=bottom; pv++;\r
347 \r
348   return 0;\r
349 }\r
350 \r
351 static int SetupMatrices()\r
352 {\r
353   D3DXVECTOR3 eye ( 0.0f, 0.0f, 0.0f );\r
354   D3DXVECTOR3 look( 0.0f, 0.0f, 0.0f );\r
355   D3DXVECTOR3 up  ( 0.0f, 1.0f, 0.0f );\r
356   D3DXMATRIX mat;\r
357   float nudgex=0.0f,nudgey=0.0f;\r
358 \r
359   memset(&mat,0,sizeof(mat));\r
360 \r
361   mat.m[0][0]=mat.m[1][1]=mat.m[2][2]=mat.m[3][3]=1.0f;\r
362   Device->SetTransform(D3DTS_WORLD,&mat);\r
363 \r
364   look.x=(float)Inp.axis[2]/2457.6f;\r
365   look.y=(float)Inp.axis[3]/2457.6f;\r
366   look.z=10.0f;\r
367 \r
368   // Nudge pixels to the centre of each screen pixel:\r
369   nudgex=13.3333f/(float)(MainWidth <<1);\r
370   nudgey=10.0000f/(float)(MainHeight<<1);\r
371   eye.x +=nudgex; eye.y +=nudgey;\r
372   look.x+=nudgex; look.y+=nudgey;\r
373 \r
374   D3DXMatrixLookAtLH(&mat,&eye,&look,&up);\r
375   Device->SetTransform(D3DTS_VIEW,&mat);\r
376 \r
377   D3DXMatrixPerspectiveFovLH(&mat, 0.5f*PI, 1.3333f, 0.2f, 1000.0f);\r
378   Device->SetTransform(D3DTS_PROJECTION,&mat);\r
379   return 0;\r
380 }\r
381 \r
382 int DirectScreen()\r
383 {\r
384   unsigned char *lock=NULL;\r
385   int ret;\r
386 \r
387   if (Device == NULL)\r
388     return DirectScreenDDraw();\r
389 \r
390   // Copy the screen to the screen texture:\r
391 #ifdef _XBOX\r
392   TexScreenSwizzle();\r
393 #else\r
394   ret=TexScreenLinear();\r
395   if (ret) lprintf("TexScreenLinear failed\n");\r
396 #endif\r
397 \r
398   SetupMatrices();\r
399 \r
400   MakeVertexList();\r
401 \r
402   // Copy vertices in:\r
403   VertexBuffer->Lock(0,sizeof(VertexList),&lock,0);\r
404   if (lock==NULL) { lprintf("VertexBuffer->Lock failed\n"); return 1; }\r
405   memcpy(lock,VertexList,sizeof(VertexList));\r
406   VertexBuffer->Unlock();\r
407 \r
408   Device->BeginScene();\r
409   Device->SetTexture(0,TexScreen);\r
410   Device->SetStreamSource(0,VertexBuffer,sizeof(CustomVertex));\r
411   Device->SetVertexShader(D3DFVF_CUSTOMVERTEX);\r
412   Device->DrawPrimitive(D3DPT_TRIANGLESTRIP,0,2);\r
413   Device->EndScene();\r
414 \r
415   return 0;\r
416 }\r
417 #else\r
418 int DirectScreen()\r
419 {\r
420   return DirectScreenDDraw();\r
421 }\r
422 #endif\r
423 \r