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