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