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