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