win32 Pico work nearly done
[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 = m_pddsFrontBuffer->Blt(&FrameRectMy, m_pddsBackBuffer, &EmuScreenRect, DDBLT_WAIT, NULL);\r
164   if (ret) { LOGFAIL(); return 1; }\r
165   return 0;\r
166 }\r
167 \r
168 \r
169 /* D3D */\r
170 \r
171 int DirectInit()\r
172 {\r
173 #if USE_D3D\r
174   D3DPRESENT_PARAMETERS d3dpp;\r
175   D3DDISPLAYMODE mode;\r
176   int i,u,ret=0;\r
177 \r
178   memset(&d3dpp,0,sizeof(d3dpp));\r
179   memset(&mode,0,sizeof(mode));\r
180 \r
181   Direct3D=Direct3DCreate8(D3D_SDK_VERSION); if (Direct3D==NULL) return 1;\r
182 \r
183   // Set up the structure used to create the D3D device:\r
184   d3dpp.BackBufferWidth =MainWidth;\r
185   d3dpp.BackBufferHeight=MainHeight;\r
186   d3dpp.BackBufferCount =1;\r
187   d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;\r
188   d3dpp.MultiSampleType =D3DMULTISAMPLE_NONE;\r
189 \r
190 #ifdef _XBOX\r
191   d3dpp.BackBufferFormat=D3DFMT_X8R8G8B8;\r
192   d3dpp.FullScreen_RefreshRateInHz=60;\r
193 #else\r
194   Direct3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&mode);\r
195   d3dpp.BackBufferFormat=mode.Format;\r
196   d3dpp.Windowed=1;\r
197   d3dpp.hDeviceWindow=FrameWnd;\r
198 #endif\r
199 \r
200   // Try to create a device with hardware vertex processing:\r
201   for (i=0;i<3;i++)\r
202   {\r
203     int behave=D3DCREATE_HARDWARE_VERTEXPROCESSING;\r
204 \r
205     // Try software vertex processing:\r
206     if (i==1) behave=D3DCREATE_MIXED_VERTEXPROCESSING;\r
207     if (i==2) behave=D3DCREATE_SOFTWARE_VERTEXPROCESSING;\r
208 \r
209     Direct3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,FrameWnd,\r
210         behave|D3DCREATE_MULTITHREADED,&d3dpp,&Device);\r
211     if (Device) break;\r
212   }\r
213 \r
214   if (Device==NULL)\r
215   {\r
216 #if 0\r
217     // try ref\r
218     Direct3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_REF,FrameWnd,\r
219         D3DCREATE_SOFTWARE_VERTEXPROCESSING|D3DCREATE_MULTITHREADED,&d3dpp,&Device);\r
220     if (Device==NULL) goto fail0;\r
221     HMODULE test = LoadLibrary("d3d8d.dll");\r
222     if (test != NULL) FreeLibrary(test);\r
223     else {\r
224       error("Sorry, but this program requires Direct3D with hardware acceleration.\n\n"\r
225             "You can try using Direct3D software emulation, but you have to install "\r
226             "DirectX SDK for it to work\n(it seems to be missing now).");\r
227       goto fail1;\r
228     }\r
229 #else\r
230     goto fail1;\r
231 #endif\r
232   }\r
233 \r
234   Device->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&DirectBack);\r
235   if (DirectBack==NULL) goto fail1;\r
236 \r
237   Device->CreateVertexBuffer(sizeof(VertexList),0,D3DFVF_CUSTOMVERTEX,D3DPOOL_DEFAULT,&VertexBuffer);\r
238   if (VertexBuffer==NULL) goto fail2;\r
239 \r
240   ret=TexScreenInit(); if (ret) goto fail3;\r
241 \r
242   //FontInit();\r
243 \r
244   Device->SetRenderState(D3DRS_LIGHTING,0); // Turn off lighting\r
245 \r
246   // Set up texture modes:\r
247   Device->SetTextureStageState(0,D3DTSS_ADDRESSU,D3DTADDRESS_CLAMP);\r
248   Device->SetTextureStageState(0,D3DTSS_ADDRESSV,D3DTADDRESS_CLAMP);\r
249 \r
250   return 0;\r
251 \r
252 fail3:\r
253   RELEASE(VertexBuffer)\r
254 fail2:\r
255   RELEASE(DirectBack)\r
256 fail1:\r
257   RELEASE(Device)\r
258 fail0:\r
259   RELEASE(Direct3D)\r
260 \r
261   // error("Failed to use Direct3D, trying DirectDraw..");\r
262 #endif\r
263   // try DirectDraw\r
264   return DirectDrawInit();\r
265 }\r
266 \r
267 void DirectExit()\r
268 {\r
269 #ifdef USE_D3D\r
270   TexScreenExit();\r
271 \r
272   // d3d\r
273   RELEASE(VertexBuffer)\r
274   RELEASE(DirectBack)\r
275   RELEASE(Device)\r
276   RELEASE(Direct3D)\r
277 #endif\r
278   DirectExitDDraw();\r
279 }\r
280 \r
281 int DirectClear(unsigned int colour)\r
282 {\r
283 #ifdef USE_D3D\r
284   if (Device != NULL) {\r
285     Device->Clear(0,NULL,D3DCLEAR_TARGET,colour,1.0f,0);\r
286     return 0;\r
287   }\r
288 #endif\r
289 \r
290   return DirectClearDDraw(colour);\r
291 }\r
292 \r
293 int DirectPresent()\r
294 {\r
295 #ifdef USE_D3D\r
296   if (Device != NULL) {\r
297     Device->Present(NULL,NULL,NULL,NULL);\r
298     return 0;\r
299   }\r
300 #endif\r
301 \r
302   return DirectPresentDDraw();\r
303 }\r
304 \r
305 #ifdef USE_D3D\r
306 static int MakeVertexList()\r
307 {\r
308   struct CustomVertex *vert=NULL,*pv=NULL;\r
309   float dist=0.0f;\r
310   float scalex=0.0f,scaley=0.0f;\r
311   unsigned int colour=0xffffff;\r
312   float right=0.0f,bottom=0.0f;\r
313 \r
314   if (LoopMode!=8) colour=0x102040;\r
315 \r
316   dist=10.0f; scalex=dist*1.3333f; scaley=dist;\r
317 \r
318   scalex*=640.0f/(float)MainWidth;\r
319   scaley*=448.0f/(float)MainHeight;\r
320 \r
321   vert=VertexList;\r
322 \r
323   // Put the vertices for the corners of the screen:\r
324   pv=vert;\r
325   pv->z=dist;\r
326   pv->x=-scalex; pv->y=scaley;\r
327   pv->colour=colour; pv++;\r
328 \r
329   *pv=vert[0]; pv->x= scalex; pv->y= scaley; pv++;\r
330   *pv=vert[0]; pv->x=-scalex; pv->y=-scaley; pv++;\r
331   *pv=vert[0]; pv->x= scalex; pv->y=-scaley; pv++;\r
332 \r
333   // Find where the screen images ends on the texture\r
334   right =(float)EmuWidth /(float)TexWidth;\r
335   bottom=(float)EmuHeight/(float)TexHeight;\r
336 \r
337   // Write texture coordinates:\r
338   pv=vert;\r
339   pv->u=0.0f;  pv->v=0.00f;  pv++;\r
340   pv->u=right; pv->v=0.00f;  pv++;\r
341   pv->u=0.0f;  pv->v=bottom; pv++;\r
342   pv->u=right; pv->v=bottom; pv++;\r
343 \r
344   return 0;\r
345 }\r
346 \r
347 static int SetupMatrices()\r
348 {\r
349   D3DXVECTOR3 eye ( 0.0f, 0.0f, 0.0f );\r
350   D3DXVECTOR3 look( 0.0f, 0.0f, 0.0f );\r
351   D3DXVECTOR3 up  ( 0.0f, 1.0f, 0.0f );\r
352   D3DXMATRIX mat;\r
353   float nudgex=0.0f,nudgey=0.0f;\r
354 \r
355   memset(&mat,0,sizeof(mat));\r
356 \r
357   mat.m[0][0]=mat.m[1][1]=mat.m[2][2]=mat.m[3][3]=1.0f;\r
358   Device->SetTransform(D3DTS_WORLD,&mat);\r
359 \r
360   look.x=(float)Inp.axis[2]/2457.6f;\r
361   look.y=(float)Inp.axis[3]/2457.6f;\r
362   look.z=10.0f;\r
363 \r
364   // Nudge pixels to the centre of each screen pixel:\r
365   nudgex=13.3333f/(float)(MainWidth <<1);\r
366   nudgey=10.0000f/(float)(MainHeight<<1);\r
367   eye.x +=nudgex; eye.y +=nudgey;\r
368   look.x+=nudgex; look.y+=nudgey;\r
369 \r
370   D3DXMatrixLookAtLH(&mat,&eye,&look,&up);\r
371   Device->SetTransform(D3DTS_VIEW,&mat);\r
372 \r
373   D3DXMatrixPerspectiveFovLH(&mat, 0.5f*PI, 1.3333f, 0.2f, 1000.0f);\r
374   Device->SetTransform(D3DTS_PROJECTION,&mat);\r
375   return 0;\r
376 }\r
377 \r
378 int DirectScreen()\r
379 {\r
380   unsigned char *lock=NULL;\r
381   int ret;\r
382 \r
383   if (Device == NULL)\r
384     return DirectScreenDDraw();\r
385 \r
386   // Copy the screen to the screen texture:\r
387 #ifdef _XBOX\r
388   TexScreenSwizzle();\r
389 #else\r
390   ret=TexScreenLinear();\r
391   if (ret) lprintf("TexScreenLinear failed\n");\r
392 #endif\r
393 \r
394   SetupMatrices();\r
395 \r
396   MakeVertexList();\r
397 \r
398   // Copy vertices in:\r
399   VertexBuffer->Lock(0,sizeof(VertexList),&lock,0);\r
400   if (lock==NULL) { lprintf("VertexBuffer->Lock failed\n"); return 1; }\r
401   memcpy(lock,VertexList,sizeof(VertexList));\r
402   VertexBuffer->Unlock();\r
403 \r
404   Device->BeginScene();\r
405   Device->SetTexture(0,TexScreen);\r
406   Device->SetStreamSource(0,VertexBuffer,sizeof(CustomVertex));\r
407   Device->SetVertexShader(D3DFVF_CUSTOMVERTEX);\r
408   Device->DrawPrimitive(D3DPT_TRIANGLESTRIP,0,2);\r
409   Device->EndScene();\r
410 \r
411   return 0;\r
412 }\r
413 #else\r
414 int DirectScreen()\r
415 {\r
416   return DirectScreenDDraw();\r
417 }\r
418 #endif\r
419 \r