final fixes for UIQ3
[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 static int MakeVertexList()\r
309 {\r
310   struct CustomVertex *vert=NULL,*pv=NULL;\r
311   float dist=0.0f;\r
312   float scalex=0.0f,scaley=0.0f;\r
313   unsigned int colour=0xffffff;\r
314   float right=0.0f,bottom=0.0f;\r
315 \r
316   if (LoopMode!=8) colour=0x102040;\r
317 \r
318   dist=10.0f; scalex=dist*1.3333f; scaley=dist;\r
319 \r
320   scalex*=640.0f/(float)MainWidth;\r
321   scaley*=448.0f/(float)MainHeight;\r
322 \r
323   vert=VertexList;\r
324 \r
325   // Put the vertices for the corners of the screen:\r
326   pv=vert;\r
327   pv->z=dist;\r
328   pv->x=-scalex; pv->y=scaley;\r
329   pv->colour=colour; pv++;\r
330 \r
331   *pv=vert[0]; pv->x= scalex; pv->y= scaley; pv++;\r
332   *pv=vert[0]; pv->x=-scalex; pv->y=-scaley; pv++;\r
333   *pv=vert[0]; pv->x= scalex; pv->y=-scaley; pv++;\r
334 \r
335   // Find where the screen images ends on the texture\r
336   right =(float)EmuWidth /(float)TexWidth;\r
337   bottom=(float)EmuHeight/(float)TexHeight;\r
338 \r
339   // Write texture coordinates:\r
340   pv=vert;\r
341   pv->u=0.0f;  pv->v=0.00f;  pv++;\r
342   pv->u=right; pv->v=0.00f;  pv++;\r
343   pv->u=0.0f;  pv->v=bottom; pv++;\r
344   pv->u=right; pv->v=bottom; pv++;\r
345 \r
346   return 0;\r
347 }\r
348 \r
349 static int SetupMatrices()\r
350 {\r
351   D3DXVECTOR3 eye ( 0.0f, 0.0f, 0.0f );\r
352   D3DXVECTOR3 look( 0.0f, 0.0f, 0.0f );\r
353   D3DXVECTOR3 up  ( 0.0f, 1.0f, 0.0f );\r
354   D3DXMATRIX mat;\r
355   float nudgex=0.0f,nudgey=0.0f;\r
356 \r
357   memset(&mat,0,sizeof(mat));\r
358 \r
359   mat.m[0][0]=mat.m[1][1]=mat.m[2][2]=mat.m[3][3]=1.0f;\r
360   Device->SetTransform(D3DTS_WORLD,&mat);\r
361 \r
362   look.x=(float)Inp.axis[2]/2457.6f;\r
363   look.y=(float)Inp.axis[3]/2457.6f;\r
364   look.z=10.0f;\r
365 \r
366   // Nudge pixels to the centre of each screen pixel:\r
367   nudgex=13.3333f/(float)(MainWidth <<1);\r
368   nudgey=10.0000f/(float)(MainHeight<<1);\r
369   eye.x +=nudgex; eye.y +=nudgey;\r
370   look.x+=nudgex; look.y+=nudgey;\r
371 \r
372   D3DXMatrixLookAtLH(&mat,&eye,&look,&up);\r
373   Device->SetTransform(D3DTS_VIEW,&mat);\r
374 \r
375   D3DXMatrixPerspectiveFovLH(&mat, 0.5f*PI, 1.3333f, 0.2f, 1000.0f);\r
376   Device->SetTransform(D3DTS_PROJECTION,&mat);\r
377   return 0;\r
378 }\r
379 \r
380 int DirectScreen()\r
381 {\r
382   unsigned char *lock=NULL;\r
383   int ret;\r
384 \r
385   if (Device == NULL)\r
386     return DirectScreenDDraw();\r
387 \r
388   // Copy the screen to the screen texture:\r
389 #ifdef _XBOX\r
390   TexScreenSwizzle();\r
391 #else\r
392   ret=TexScreenLinear();\r
393   if (ret) lprintf("TexScreenLinear failed\n");\r
394 #endif\r
395 \r
396   SetupMatrices();\r
397 \r
398   MakeVertexList();\r
399 \r
400   // Copy vertices in:\r
401   VertexBuffer->Lock(0,sizeof(VertexList),&lock,0);\r
402   if (lock==NULL) { lprintf("VertexBuffer->Lock failed\n"); return 1; }\r
403   memcpy(lock,VertexList,sizeof(VertexList));\r
404   VertexBuffer->Unlock();\r
405 \r
406   Device->BeginScene();\r
407   Device->SetTexture(0,TexScreen);\r
408   Device->SetStreamSource(0,VertexBuffer,sizeof(CustomVertex));\r
409   Device->SetVertexShader(D3DFVF_CUSTOMVERTEX);\r
410   Device->DrawPrimitive(D3DPT_TRIANGLESTRIP,0,2);\r
411   Device->EndScene();\r
412 \r
413   return 0;\r
414 }\r
415 #else\r
416 int DirectScreen()\r
417 {\r
418   return DirectScreenDDraw();\r
419 }\r
420 #endif\r
421 \r