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