bugfix
[picodrive.git] / platform / win32 / direct.cpp
CommitLineData
823b9004 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
13static LPDIRECTDRAW7 m_pDD = NULL;\r
14static LPDIRECTDRAWSURFACE7 m_pddsFrontBuffer = NULL;\r
15static LPDIRECTDRAWSURFACE7 m_pddsBackBuffer = NULL;\r
16\r
17// quick and dirty stuff..\r
18void DirectExit(void)\r
19{\r
20 RELEASE(m_pddsBackBuffer);\r
21 RELEASE(m_pddsFrontBuffer);\r
22 RELEASE(m_pDD);\r
23}\r
24\r
25int 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
69fail:\r
70 RELEASE(pcClipper);\r
71 DirectExit();\r
72 return 1;\r
73}\r
74\r
75int 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
135int 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
149int 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
161static IDirect3D8 *Direct3D=NULL;\r
162IDirect3DDevice8 *Device=NULL;\r
163IDirect3DSurface8 *DirectBack=NULL; // Back Buffer\r
164\r
165static IDirect3DVertexBuffer8 *VertexBuffer=NULL;\r
166\r
167struct 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
175static CustomVertex VertexList[4];\r
176\r
177int 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
257fail3:\r
258 RELEASE(VertexBuffer)\r
259fail2:\r
260 RELEASE(DirectBack)\r
261fail1:\r
262 RELEASE(Device)\r
263fail0:\r
264 RELEASE(Direct3D)\r
265\r
266 return 1;\r
267}\r
268\r
269void 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
280int 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
290int 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
302static 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
343static 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
374int 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