- cleaning of volume.c/volumetexture.c as done previously for
[wine] / dlls / d3d8 / surface.c
1 /*
2  * IDirect3DSurface8 implementation
3  *
4  * Copyright 2002 Jason Edmeades
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "wingdi.h"
27 #include "wine/debug.h"
28 #include <stdio.h>
29
30 #include "d3d8_private.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
33
34 /* trace: */
35 #if 0
36 # define VTRACE(A) TRACE A
37 #else 
38 # define VTRACE(A) 
39 #endif
40
41
42 /* IDirect3DVolume IUnknown parts follow: */
43 HRESULT WINAPI IDirect3DSurface8Impl_QueryInterface(LPDIRECT3DSURFACE8 iface,REFIID riid,LPVOID *ppobj)
44 {
45     ICOM_THIS(IDirect3DSurface8Impl,iface);
46
47     if (IsEqualGUID(riid, &IID_IUnknown)
48         || IsEqualGUID(riid, &IID_IDirect3DSurface8)) {
49         IDirect3DSurface8Impl_AddRef(iface);
50         *ppobj = This;
51         return D3D_OK;
52     }
53
54     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
55     return E_NOINTERFACE;
56 }
57
58 ULONG WINAPI IDirect3DSurface8Impl_AddRef(LPDIRECT3DSURFACE8 iface) {
59     ICOM_THIS(IDirect3DSurface8Impl,iface);
60     TRACE("(%p) : AddRef from %ld\n", This, This->ref);
61     return ++(This->ref);
62 }
63
64 ULONG WINAPI IDirect3DSurface8Impl_Release(LPDIRECT3DSURFACE8 iface) {
65     ICOM_THIS(IDirect3DSurface8Impl,iface);
66     ULONG ref = --This->ref;
67     TRACE("(%p) : ReleaseRef to %ld\n", This, This->ref);
68     if (ref == 0) {
69       HeapFree(GetProcessHeap(), 0, This->allocatedMemory);
70       HeapFree(GetProcessHeap(), 0, This);
71     }
72     return ref;
73 }
74
75 /* IDirect3DSurface8: */
76 HRESULT WINAPI IDirect3DSurface8Impl_GetDevice(LPDIRECT3DSURFACE8 iface, IDirect3DDevice8** ppDevice) {
77     ICOM_THIS(IDirect3DSurface8Impl,iface);
78     TRACE("(%p) : returning %p\n", This, This->Device);
79     *ppDevice = (LPDIRECT3DDEVICE8) This->Device;
80     /**
81      * Note  Calling this method will increase the internal reference count 
82      * on the IDirect3DDevice8 interface. 
83      */
84     IDirect3DDevice8Impl_AddRef(*ppDevice);
85     return D3D_OK;
86 }
87 HRESULT WINAPI IDirect3DSurface8Impl_SetPrivateData(LPDIRECT3DSURFACE8 iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
88     ICOM_THIS(IDirect3DSurface8Impl,iface);
89     FIXME("(%p) : stub\n", This);    
90     return D3D_OK;
91 }
92 HRESULT WINAPI IDirect3DSurface8Impl_GetPrivateData(LPDIRECT3DSURFACE8 iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
93     ICOM_THIS(IDirect3DSurface8Impl,iface);
94     FIXME("(%p) : stub\n", This);    
95     return D3D_OK;
96 }
97 HRESULT WINAPI IDirect3DSurface8Impl_FreePrivateData(LPDIRECT3DSURFACE8 iface, REFGUID refguid) {
98     ICOM_THIS(IDirect3DSurface8Impl,iface);
99     FIXME("(%p) : stub\n", This);    
100     return D3D_OK;
101 }
102 HRESULT WINAPI IDirect3DSurface8Impl_GetContainer(LPDIRECT3DSURFACE8 iface, REFIID riid, void** ppContainer) {
103     ICOM_THIS(IDirect3DSurface8Impl,iface);
104     HRESULT res;
105     res = IUnknown_QueryInterface(This->Container, riid, ppContainer);
106     if (E_NOINTERFACE == res) { 
107       /**
108        * If the surface is created using CreateImageSurface, CreateRenderTarget, 
109        * or CreateDepthStencilSurface, the surface is considered stand alone. In this case, 
110        * GetContainer will return the Direct3D device used to create the surface. 
111        */
112       res = IUnknown_QueryInterface(This->Container, &IID_IDirect3DDevice8, ppContainer);
113     }
114     TRACE("(%p) : returning %p\n", This, *ppContainer);
115     return res;
116 }
117 HRESULT WINAPI IDirect3DSurface8Impl_GetDesc(LPDIRECT3DSURFACE8 iface, D3DSURFACE_DESC *pDesc) {
118     ICOM_THIS(IDirect3DSurface8Impl,iface);
119
120     TRACE("(%p) : copying into %p\n", This, pDesc);
121     memcpy(pDesc, &This->myDesc, sizeof(D3DSURFACE_DESC));
122     return D3D_OK;
123 }
124 HRESULT WINAPI IDirect3DSurface8Impl_LockRect(LPDIRECT3DSURFACE8 iface, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
125     HRESULT hr;
126     ICOM_THIS(IDirect3DSurface8Impl,iface);
127   
128     /* fixme: should we really lock as such? */
129
130     if (FALSE == This->lockable) {
131       ERR("trying to lock unlockable surf@%p\n", This);  
132       return D3DERR_INVALIDCALL;
133     }
134
135     if (This == This->Device->backBuffer || This == This->Device->renderTarget || This == This->Device->frontBuffer || This->Device->depthStencilBuffer) {
136       if (This == This->Device->backBuffer) {
137         TRACE("(%p, backBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
138       } else if (This == This->Device->frontBuffer) {
139         TRACE("(%p, frontBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
140       } else if (This == This->Device->renderTarget) {
141         TRACE("(%p, renderTarget) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
142       } else if (This == This->Device->depthStencilBuffer) {
143         TRACE("(%p, stencilBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
144       }
145     } else {
146       TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
147     }
148
149     pLockedRect->Pitch = This->bytesPerPixel * This->myDesc.Width;  /* Bytes / row */    
150     
151     if (NULL == pRect) {
152       pLockedRect->pBits = This->allocatedMemory;
153       This->lockedRect.left   = 0;
154       This->lockedRect.top    = 0;
155       This->lockedRect.right  = This->myDesc.Width;
156       This->lockedRect.bottom = This->myDesc.Height;
157       TRACE("Locked Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", &This->lockedRect, This->lockedRect.left, This->lockedRect.top, This->lockedRect.right, This->lockedRect.bottom);
158     } else {
159       TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
160       pLockedRect->pBits = This->allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
161       This->lockedRect.left   = pRect->left;
162       This->lockedRect.top    = pRect->top;
163       This->lockedRect.right  = pRect->right;
164       This->lockedRect.bottom = pRect->bottom;
165     }
166
167
168     if (0 == This->myDesc.Usage) { /* classic surface */
169
170       /* Nothing to do ;) */
171
172     } else if (D3DUSAGE_RENDERTARGET & This->myDesc.Usage) { /* render surfaces */
173       
174       if (This == This->Device->backBuffer || This == This->Device->renderTarget || This == This->Device->frontBuffer) {
175         GLint  prev_store;
176         GLenum prev_read;
177         
178         ENTER_GL();
179
180         /**
181          * for render->surface copy begin to begin of allocatedMemory
182          * unlock can be more easy
183          */
184         pLockedRect->pBits = This->allocatedMemory;
185         
186         glFlush();
187         vcheckGLcall("glFlush");
188         glGetIntegerv(GL_READ_BUFFER, &prev_read);
189         vcheckGLcall("glIntegerv");
190         glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
191         vcheckGLcall("glIntegerv");
192
193         if (This == This->Device->backBuffer) {
194           glReadBuffer(GL_BACK);
195         } else if (This == This->Device->frontBuffer || This == This->Device->renderTarget) {
196           glReadBuffer(GL_FRONT);
197         } else if (This == This->Device->depthStencilBuffer) {
198           ERR("Stencil Buffer lock unsupported for now\n");
199         }
200         vcheckGLcall("glReadBuffer");
201
202         {
203           long j;
204           for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
205             glReadPixels(This->lockedRect.left, 
206                          This->lockedRect.bottom - j - 1, 
207                          This->lockedRect.right - This->lockedRect.left, 
208                          1,
209                          D3DFmt2GLFmt(This->Device, This->myDesc.Format), 
210                          D3DFmt2GLType(This->Device, This->myDesc.Format), 
211                          (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
212             vcheckGLcall("glReadPixels");
213           }
214         }
215
216         glReadBuffer(prev_read);
217         vcheckGLcall("glReadBuffer");
218         LEAVE_GL();
219       } else {
220         FIXME("unsupported locking to Rendering surface surf@%p usage(%lu)\n", This, This->myDesc.Usage);
221       }
222
223     } else if (D3DUSAGE_DEPTHSTENCIL & This->myDesc.Usage) { /* stencil surfaces */
224
225       FIXME("TODO stencil depth surface locking surf@%p usage(%lu)\n", This, This->myDesc.Usage);
226
227     } else {
228       FIXME("unsupported locking to surface surf@%p usage(%lu)\n", This, This->myDesc.Usage);
229     }
230
231     if (Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY)) {
232       /* Dont dirtify */
233     } else {
234       /**
235        * Dirtify on lock
236        * as seen in msdn docs
237        */
238       IDirect3DSurface8Impl_AddDirtyRect(iface, &This->lockedRect);
239
240       /** Dirtify Container if needed */
241       if (NULL != This->Container) {
242         IDirect3DBaseTexture8* cont = NULL;
243         hr = IUnknown_QueryInterface(This->Container, &IID_IDirect3DBaseTexture8, (void**) &cont);
244         
245         if (SUCCEEDED(hr) && NULL != cont) {
246           IDirect3DBaseTexture8Impl_SetDirty(cont, TRUE);
247           IDirect3DBaseTexture8_Release(cont);
248           cont = NULL;
249         }
250       }
251     }
252
253     TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Dirty);
254
255     This->locked = TRUE;
256     return D3D_OK;
257 }
258 HRESULT WINAPI IDirect3DSurface8Impl_UnlockRect(LPDIRECT3DSURFACE8 iface) {
259     ICOM_THIS(IDirect3DSurface8Impl,iface);
260     
261     if (FALSE == This->locked) {
262       ERR("trying to lock unlocked surf@%p\n", This);  
263       return D3DERR_INVALIDCALL;
264     }
265
266     if (This == This->Device->backBuffer || This == This->Device->frontBuffer || This->Device->depthStencilBuffer) {
267       if (This == This->Device->backBuffer) {
268         TRACE("(%p, backBuffer) : dirtyfied(%d)\n", This, This->Dirty);
269       } else if (This == This->Device->frontBuffer) {
270         TRACE("(%p, frontBuffer) : dirtyfied(%d)\n", This, This->Dirty);
271       } else if (This == This->Device->depthStencilBuffer) {
272         TRACE("(%p, stencilBuffer) : dirtyfied(%d)\n", This, This->Dirty);
273       }
274     } else {
275       TRACE("(%p) : dirtyfied(%d)\n", This, This->Dirty);
276     }
277     /*TRACE("(%p) see if behavior is correct\n", This);*/
278
279     if (FALSE == This->Dirty) {
280       TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
281       goto unlock_end;
282     }
283
284     if (0 == This->myDesc.Usage) { /* classic surface */
285       /**
286        * nothing to do
287        * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
288        */
289     } else if (D3DUSAGE_RENDERTARGET & This->myDesc.Usage) { /* render surfaces */
290
291       if (This == This->Device->backBuffer || This == This->Device->frontBuffer) {
292         GLint  prev_store;
293         GLenum prev_draw;
294         GLint  prev_rasterpos[4];
295
296         ENTER_GL();
297         
298         glFlush();
299         vcheckGLcall("glFlush");
300         glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
301         vcheckGLcall("glIntegerv");
302         glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
303         vcheckGLcall("glIntegerv");
304         glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
305         vcheckGLcall("glIntegerv");
306
307         if (This == This->Device->backBuffer) {
308           glDrawBuffer(GL_BACK);
309         } else if (This == This->Device->frontBuffer) {
310           glDrawBuffer(GL_FRONT);
311         }
312         vcheckGLcall("glDrawBuffer");
313
314         glRasterPos2i(This->lockedRect.left, This->lockedRect.top);
315         vcheckGLcall("glRasterPos2f");
316         switch (This->myDesc.Format) {
317         case D3DFMT_R5G6B5:
318           {
319             glDrawPixels(This->lockedRect.right - This->lockedRect.left, This->lockedRect.bottom - This->lockedRect.top,
320                          GL_RGB, GL_UNSIGNED_SHORT_5_6_5, This->allocatedMemory);
321             vcheckGLcall("glDrawPixels");
322           }
323           break;
324         case D3DFMT_R8G8B8:
325           {
326             glDrawPixels(This->lockedRect.right - This->lockedRect.left, This->lockedRect.bottom - This->lockedRect.top,
327                          GL_RGB, GL_UNSIGNED_BYTE, This->allocatedMemory);
328             vcheckGLcall("glDrawPixels");
329           }
330           break;
331         case D3DFMT_A8R8G8B8:
332           {
333             glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
334             vcheckGLcall("glPixelStorei");
335             glDrawPixels(This->lockedRect.right - This->lockedRect.left, This->lockedRect.bottom - This->lockedRect.top,
336                          GL_BGRA, GL_UNSIGNED_BYTE, This->allocatedMemory);
337             vcheckGLcall("glDrawPixels");
338             glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
339             vcheckGLcall("glPixelStorei");
340           }
341           break;
342         default:
343           FIXME("Unsupported Format %u in locking func\n", This->myDesc.Format);
344         }
345
346         glDrawBuffer(prev_draw);
347         vcheckGLcall("glDrawBuffer");
348         glRasterPos3iv(&prev_rasterpos[0]);
349         vcheckGLcall("glRasterPos3iv");
350         LEAVE_GL();
351
352         /** restore clean dirty state */
353         IDirect3DSurface8Impl_CleanDirtyRect(iface);
354
355       } else {
356         FIXME("unsupported unlocking to Rendering surface surf@%p usage(%lu)\n", This, This->myDesc.Usage);
357       }
358
359     } else if (D3DUSAGE_DEPTHSTENCIL & This->myDesc.Usage) { /* stencil surfaces */
360     
361       if (This == This->Device->depthStencilBuffer) {
362         FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This, This->myDesc.Usage);
363       } else {
364         FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->myDesc.Usage);
365       }
366
367     } else {
368       FIXME("unsupported unlocking to surface surf@%p usage(%lu)\n", This, This->myDesc.Usage);
369     }
370
371 unlock_end:
372     This->locked = FALSE;
373     memset(&This->lockedRect, 0, sizeof(RECT));
374     return D3D_OK;
375 }
376
377 ICOM_VTABLE(IDirect3DSurface8) Direct3DSurface8_Vtbl =
378 {
379     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
380     IDirect3DSurface8Impl_QueryInterface,
381     IDirect3DSurface8Impl_AddRef,
382     IDirect3DSurface8Impl_Release,
383     IDirect3DSurface8Impl_GetDevice,
384     IDirect3DSurface8Impl_SetPrivateData,
385     IDirect3DSurface8Impl_GetPrivateData,
386     IDirect3DSurface8Impl_FreePrivateData,
387     IDirect3DSurface8Impl_GetContainer,
388     IDirect3DSurface8Impl_GetDesc,
389     IDirect3DSurface8Impl_LockRect,
390     IDirect3DSurface8Impl_UnlockRect,
391 };
392
393 HRESULT WINAPI IDirect3DSurface8Impl_LoadTexture(LPDIRECT3DSURFACE8 iface, GLenum gl_target, GLenum gl_level) {
394   ICOM_THIS(IDirect3DSurface8Impl,iface);
395
396   if ((This->myDesc.Format == D3DFMT_P8 || This->myDesc.Format == D3DFMT_A8P8) 
397 #if defined(GL_EXT_paletted_texture)
398       && !GL_SUPPORT_DEV(EXT_PALETTED_TEXTURE, This->Device)
399 #endif
400       ) {
401     /**
402      * wanted a paletted texture and not really support it in HW 
403      * so software emulation code begin
404      */
405     UINT i;
406     PALETTEENTRY* pal = This->Device->palettes[This->Device->currentPalette];
407     VOID* surface = (VOID*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->myDesc.Width * This->myDesc.Height * sizeof(DWORD));
408     BYTE* dst = (BYTE*) surface;
409     BYTE* src = (BYTE*) This->allocatedMemory;
410           
411     for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
412       BYTE color = *src++;
413       *dst++ = pal[color].peRed;
414       *dst++ = pal[color].peGreen;
415       *dst++ = pal[color].peBlue;
416       if (This->myDesc.Format == D3DFMT_A8P8)
417         *dst++ = pal[color].peFlags; 
418       else
419         *dst++ = 0xFF; 
420     }
421     
422     TRACE("Calling glTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
423           gl_target,
424           gl_level, 
425           GL_RGBA,
426           This->myDesc.Width, 
427           This->myDesc.Height, 
428           0, 
429           GL_RGBA,
430           GL_UNSIGNED_BYTE,
431           surface);
432     glTexImage2D(gl_target,
433                  gl_level, 
434                  GL_RGBA,
435                  This->myDesc.Width,
436                  This->myDesc.Height,
437                  0,
438                  GL_RGBA,
439                  GL_UNSIGNED_BYTE,
440                  surface);
441     checkGLcall("glTexImage2D");
442     HeapFree(GetProcessHeap(), 0, surface);
443
444     return D3D_OK;    
445   }
446
447   if (This->myDesc.Format == D3DFMT_DXT1 || 
448       This->myDesc.Format == D3DFMT_DXT3 || 
449       This->myDesc.Format == D3DFMT_DXT5) {
450 #if defined(GL_EXT_texture_compression_s3tc)
451     if (GL_SUPPORT_DEV(EXT_TEXTURE_COMPRESSION_S3TC, This->Device)) {
452       TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
453             gl_target, 
454             gl_level, 
455             D3DFmt2GLIntFmt(This->Device, This->myDesc.Format), 
456             This->myDesc.Width, 
457             This->myDesc.Height, 
458             0, 
459             This->myDesc.Size,
460             This->allocatedMemory);
461       glCompressedTexImage2DARB(gl_target, 
462                                 gl_level, 
463                                 D3DFmt2GLIntFmt(This->Device, This->myDesc.Format),
464                                 This->myDesc.Width,
465                                 This->myDesc.Height,
466                                 0,
467                                 This->myDesc.Size,
468                                 This->allocatedMemory);
469       checkGLcall("glCommpressedTexTexImage2D");
470     }
471 #endif
472   } else {
473     TRACE("Calling glTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
474           gl_target, 
475           gl_level, 
476           D3DFmt2GLIntFmt(This->Device, This->myDesc.Format),
477           This->myDesc.Width, 
478           This->myDesc.Height, 
479           0, 
480           D3DFmt2GLFmt(This->Device, This->myDesc.Format), 
481           D3DFmt2GLType(This->Device, This->myDesc.Format),
482           This->allocatedMemory);
483     glTexImage2D(gl_target, 
484                  gl_level,
485                  D3DFmt2GLIntFmt(This->Device, This->myDesc.Format),
486                  This->myDesc.Width,
487                  This->myDesc.Height,
488                  0,
489                  D3DFmt2GLFmt(This->Device, This->myDesc.Format),
490                  D3DFmt2GLType(This->Device, This->myDesc.Format),
491                  This->allocatedMemory);
492     checkGLcall("glTexImage2D");
493
494 #if 0
495     {
496       static unsigned int gen = 0;
497       char buffer[4096];
498       ++gen;
499       if ((gen % 10) == 0) {
500         snprintf(buffer, sizeof(buffer), "/tmp/surface%u_level%u_%u.ppm", gl_target, gl_level, gen);
501         IDirect3DSurface8Impl_SaveSnapshot((LPDIRECT3DSURFACE8) This, buffer);
502       }
503     }
504 #endif
505   }
506
507   return D3D_OK;
508 }
509
510 #include <errno.h>
511 HRESULT WINAPI IDirect3DSurface8Impl_SaveSnapshot(LPDIRECT3DSURFACE8 iface, const char* filename) {
512   FILE* f = NULL;
513   ULONG i;
514   ICOM_THIS(IDirect3DSurface8Impl,iface);
515
516   f = fopen(filename, "w+");
517   if (NULL == f) {
518     ERR("opening of %s failed with: %s\n", filename, strerror(errno));
519     return D3DERR_INVALIDCALL;
520   }
521
522   TRACE("opened %s with format %s\n", filename, debug_d3dformat(This->myDesc.Format));
523
524   fprintf(f, "P6\n%u %u\n255\n", This->myDesc.Width, This->myDesc.Height);
525   switch (This->myDesc.Format) {
526   case D3DFMT_X8R8G8B8:
527   case D3DFMT_A8R8G8B8:
528     {
529       DWORD color;
530       for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
531         color = ((DWORD*) This->allocatedMemory)[i];
532         fputc((color >> 16) & 0xFF, f);
533         fputc((color >>  8) & 0xFF, f);
534         fputc((color >>  0) & 0xFF, f);
535       }
536     }
537     break;
538   case D3DFMT_R8G8B8:
539     {
540       BYTE* color;
541       for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
542         color = ((BYTE*) This->allocatedMemory) + (3 * i);
543         fputc((color[0]) & 0xFF, f);
544         fputc((color[1]) & 0xFF, f);
545         fputc((color[2]) & 0xFF, f);
546       }
547     }
548     break;
549   case D3DFMT_A1R5G5B5: 
550     {
551       WORD color;
552       for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
553         color = ((WORD*) This->allocatedMemory)[i];
554         fputc(((color >> 10) & 0x1F) * 255 / 31, f);
555         fputc(((color >>  5) & 0x1F) * 255 / 31, f);
556         fputc(((color >>  0) & 0x1F) * 255 / 31, f);
557       }
558     }
559     break;
560   case D3DFMT_A4R4G4B4:
561     {
562       WORD color;
563       for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
564         color = ((WORD*) This->allocatedMemory)[i];
565         fputc(((color >>  8) & 0x0F) * 255 / 15, f);
566         fputc(((color >>  4) & 0x0F) * 255 / 15, f);
567         fputc(((color >>  0) & 0x0F) * 255 / 15, f);
568       }
569     }
570     break;
571
572   case D3DFMT_R5G6B5: 
573     {
574       WORD color;
575       for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
576         color = ((WORD*) This->allocatedMemory)[i];
577         fputc(((color >> 11) & 0x1F) * 255 / 31, f);
578         fputc(((color >>  5) & 0x3F) * 255 / 63, f);
579         fputc(((color >>  0) & 0x1F) * 255 / 31, f);
580       }
581     }
582     break;
583   default: 
584     FIXME("Unimplemented dump mode format(%u,%s)\n", This->myDesc.Format, debug_d3dformat(This->myDesc.Format));
585   }
586   fclose(f);
587   return D3D_OK;
588 }
589
590 HRESULT WINAPI IDirect3DSurface8Impl_CleanDirtyRect(LPDIRECT3DSURFACE8 iface) {
591   ICOM_THIS(IDirect3DSurface8Impl,iface);
592   This->Dirty = FALSE;
593   This->dirtyRect.left   = This->myDesc.Width;
594   This->dirtyRect.top    = This->myDesc.Height;
595   This->dirtyRect.right  = 0;
596   This->dirtyRect.bottom = 0;
597   return D3D_OK;
598 }
599
600 /**
601  * Raphael:
602  *   very stupid way to handle multiple dirty rects but it works :)
603  */
604 extern HRESULT WINAPI IDirect3DSurface8Impl_AddDirtyRect(LPDIRECT3DSURFACE8 iface, CONST RECT* pDirtyRect) {
605   ICOM_THIS(IDirect3DSurface8Impl,iface);
606   This->Dirty = TRUE;
607   This->dirtyRect.left   = min(This->dirtyRect.left,   pDirtyRect->left);
608   This->dirtyRect.top    = min(This->dirtyRect.top,    pDirtyRect->top);
609   This->dirtyRect.right  = max(This->dirtyRect.right,  pDirtyRect->right);
610   This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
611   return D3D_OK;
612 }