Assorted spelling fixes.
[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     if (This->inTexture && This->inPBuffer) {
133         FIXME("Warning: Surface is in texture memory or pbuffer\n");
134         This->inTexture = 0;
135         This->inPBuffer = 0;
136     }
137     
138     if (FALSE == This->lockable) {
139       /* Note: UpdateTextures calls CopyRects which calls this routine to populate the 
140             texture regions, and since the destination is an unlockable region we need
141             to tolerate this                                                           */
142       TRACE("Warning: trying to lock unlockable surf@%p\n", This);  
143       /*return D3DERR_INVALIDCALL; */
144     }
145
146     if (This == This->Device->backBuffer || This == This->Device->renderTarget || This == This->Device->frontBuffer || This->Device->depthStencilBuffer) {
147       if (This == This->Device->backBuffer) {
148         TRACE("(%p, backBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
149       } else if (This == This->Device->frontBuffer) {
150         TRACE("(%p, frontBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
151       } else if (This == This->Device->renderTarget) {
152         TRACE("(%p, renderTarget) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
153       } else if (This == This->Device->depthStencilBuffer) {
154         TRACE("(%p, stencilBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
155       }
156     } else {
157       TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
158     }
159
160     /* DXTn formats don't have exact pitches as they are to the new row of blocks,
161          where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt3/5)      
162           ie pitch = (width/4) * bytes per block                                  */
163     if (This->myDesc.Format == D3DFMT_DXT1) /* DXT1 is 8 bytes per block */
164         pLockedRect->Pitch = (This->myDesc.Width/4) * 8;
165     else if (This->myDesc.Format == D3DFMT_DXT3 || This->myDesc.Format == D3DFMT_DXT5) /* DXT3/5 is 16 bytes per block */
166         pLockedRect->Pitch = (This->myDesc.Width/4) * 16;
167     else
168         pLockedRect->Pitch = This->bytesPerPixel * This->myDesc.Width;  /* Bytes / row */    
169
170     if (NULL == pRect) {
171       pLockedRect->pBits = This->allocatedMemory;
172       This->lockedRect.left   = 0;
173       This->lockedRect.top    = 0;
174       This->lockedRect.right  = This->myDesc.Width;
175       This->lockedRect.bottom = This->myDesc.Height;
176       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);
177     } else {
178       TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
179
180       if (This->myDesc.Format == D3DFMT_DXT1) { /* DXT1 is half byte per pixel */
181           pLockedRect->pBits = This->allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel/2));
182       } else {
183           pLockedRect->pBits = This->allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
184       }
185       This->lockedRect.left   = pRect->left;
186       This->lockedRect.top    = pRect->top;
187       This->lockedRect.right  = pRect->right;
188       This->lockedRect.bottom = pRect->bottom;
189     }
190
191
192     if (0 == This->myDesc.Usage) { /* classic surface */
193
194       /* Nothing to do ;) */
195
196     } else if (D3DUSAGE_RENDERTARGET & This->myDesc.Usage) { /* render surfaces */
197       
198       if (This == This->Device->backBuffer || This == This->Device->renderTarget || This == This->Device->frontBuffer) {
199         GLint  prev_store;
200         GLenum prev_read;
201         
202         ENTER_GL();
203
204         /**
205          * for render->surface copy begin to begin of allocatedMemory
206          * unlock can be more easy
207          */
208         pLockedRect->pBits = This->allocatedMemory;
209         
210         glFlush();
211         vcheckGLcall("glFlush");
212         glGetIntegerv(GL_READ_BUFFER, &prev_read);
213         vcheckGLcall("glIntegerv");
214         glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
215         vcheckGLcall("glIntegerv");
216
217         if (This == This->Device->backBuffer) {
218           glReadBuffer(GL_BACK);
219         } else if (This == This->Device->frontBuffer || This == This->Device->renderTarget) {
220           glReadBuffer(GL_FRONT);
221         } else if (This == This->Device->depthStencilBuffer) {
222           ERR("Stencil Buffer lock unsupported for now\n");
223         }
224         vcheckGLcall("glReadBuffer");
225
226         {
227           long j;
228           GLenum format = D3DFmt2GLFmt(This->Device, This->myDesc.Format);
229           GLenum type   = D3DFmt2GLType(This->Device, This->myDesc.Format);
230           for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
231             glReadPixels(This->lockedRect.left, 
232                          This->lockedRect.bottom - j - 1, 
233                          This->lockedRect.right - This->lockedRect.left, 
234                          1,
235                          format, 
236                          type, 
237                          (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
238             vcheckGLcall("glReadPixels");
239           }
240         }
241
242         glReadBuffer(prev_read);
243         vcheckGLcall("glReadBuffer");
244
245         LEAVE_GL();
246
247       } else {
248         FIXME("unsupported locking to Rendering surface surf@%p usage(%lu)\n", This, This->myDesc.Usage);
249       }
250
251     } else if (D3DUSAGE_DEPTHSTENCIL & This->myDesc.Usage) { /* stencil surfaces */
252
253       FIXME("TODO stencil depth surface locking surf@%p usage(%lu)\n", This, This->myDesc.Usage);
254
255     } else {
256       FIXME("unsupported locking to surface surf@%p usage(%lu)\n", This, This->myDesc.Usage);
257     }
258
259     if (Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY)) {
260       /* Don't dirtify */
261     } else {
262       /**
263        * Dirtify on lock
264        * as seen in msdn docs
265        */
266       IDirect3DSurface8Impl_AddDirtyRect(iface, &This->lockedRect);
267
268       /** Dirtify Container if needed */
269       if (NULL != This->Container) {
270         IDirect3DBaseTexture8* cont = NULL;
271         hr = IUnknown_QueryInterface(This->Container, &IID_IDirect3DBaseTexture8, (void**)(char*) &cont);
272         
273         if (SUCCEEDED(hr) && NULL != cont) {
274           IDirect3DBaseTexture8Impl_SetDirty(cont, TRUE);
275           IDirect3DBaseTexture8_Release(cont);
276           cont = NULL;
277         }
278       }
279     }
280
281     TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Dirty);
282
283     This->locked = TRUE;
284     return D3D_OK;
285 }
286
287 HRESULT WINAPI IDirect3DSurface8Impl_UnlockRect(LPDIRECT3DSURFACE8 iface) {
288     GLint skipBytes = 0;
289     ICOM_THIS(IDirect3DSurface8Impl,iface);
290
291     if (FALSE == This->locked) {
292       ERR("trying to Unlock an unlocked surf@%p\n", This);  
293       return D3DERR_INVALIDCALL;
294     }
295
296     if (This == This->Device->backBuffer || This == This->Device->frontBuffer || This->Device->depthStencilBuffer) {
297       if (This == This->Device->backBuffer) {
298         TRACE("(%p, backBuffer) : dirtyfied(%d)\n", This, This->Dirty);
299       } else if (This == This->Device->frontBuffer) {
300         TRACE("(%p, frontBuffer) : dirtyfied(%d)\n", This, This->Dirty);
301       } else if (This == This->Device->depthStencilBuffer) {
302         TRACE("(%p, stencilBuffer) : dirtyfied(%d)\n", This, This->Dirty);
303       }
304     } else {
305       TRACE("(%p) : dirtyfied(%d)\n", This, This->Dirty);
306     }
307     /*TRACE("(%p) see if behavior is correct\n", This);*/
308
309     if (FALSE == This->Dirty) {
310       TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
311       goto unlock_end;
312     }
313
314     if (0 == This->myDesc.Usage) { /* classic surface */
315       /**
316        * nothing to do
317        * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
318        */
319     } else if (D3DUSAGE_RENDERTARGET & This->myDesc.Usage) { /* render surfaces */
320
321       if (This == This->Device->backBuffer || This == This->Device->frontBuffer) {
322         GLint  prev_store;
323         GLenum prev_draw;
324         GLint  prev_rasterpos[4];
325
326         ENTER_GL();
327         
328         glFlush();
329         vcheckGLcall("glFlush");
330         glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
331         vcheckGLcall("glIntegerv");
332         glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
333         vcheckGLcall("glIntegerv");
334         glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
335         vcheckGLcall("glIntegerv");
336         glPixelZoom(1.0, -1.0);
337         vcheckGLcall("glPixelZoom");
338
339         /* glDrawPixels transforms the raster position as though it was a vertex -
340            we want to draw at screen position 0,0 - Set up ortho (rhw) mode as   
341            per drawprim (and leave set - it will sort itself out due to last_was_rhw */
342         if (!This->Device->last_was_rhw) {
343
344             double X, Y, height, width, minZ, maxZ;
345             This->Device->last_was_rhw = TRUE;
346
347             /* Transformed already into viewport coordinates, so we do not need transform
348                matrices. Reset all matrices to identity and leave the default matrix in world 
349                mode.                                                                         */
350             glMatrixMode(GL_MODELVIEW);
351             checkGLcall("glMatrixMode");
352             glLoadIdentity();
353             checkGLcall("glLoadIdentity");
354
355             glMatrixMode(GL_PROJECTION);
356             checkGLcall("glMatrixMode");
357             glLoadIdentity();
358             checkGLcall("glLoadIdentity");
359
360             /* Set up the viewport to be full viewport */
361             X      = This->Device->StateBlock->viewport.X;
362             Y      = This->Device->StateBlock->viewport.Y;
363             height = This->Device->StateBlock->viewport.Height;
364             width  = This->Device->StateBlock->viewport.Width;
365             minZ   = This->Device->StateBlock->viewport.MinZ;
366             maxZ   = This->Device->StateBlock->viewport.MaxZ;
367             TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
368             glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
369             checkGLcall("glOrtho");
370
371             /* Window Coord 0 is the middle of the first pixel, so translate by half
372                a pixel (See comment above glTranslate below)                         */
373             glTranslatef(0.5, 0.5, 0);
374             checkGLcall("glTranslatef(0.5, 0.5, 0)");
375         }
376
377         if (This == This->Device->backBuffer) {
378           glDrawBuffer(GL_BACK);
379         } else if (This == This->Device->frontBuffer) {
380           glDrawBuffer(GL_FRONT);
381         }
382         vcheckGLcall("glDrawBuffer");
383
384     /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
385     glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
386     glPixelStorei(GL_UNPACK_ROW_LENGTH, This->myDesc.Width);
387
388     /* And back buffers are not blended */
389     glDisable(GL_BLEND);
390
391         glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
392         vcheckGLcall("glRasterPos2f");
393         switch (This->myDesc.Format) {
394         case D3DFMT_R5G6B5:
395           {
396             glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
397                          GL_RGB, GL_UNSIGNED_SHORT_5_6_5, This->allocatedMemory);
398             vcheckGLcall("glDrawPixels");
399           }
400           break;
401         case D3DFMT_R8G8B8:
402           {
403             glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
404                          GL_RGB, GL_UNSIGNED_BYTE, This->allocatedMemory);
405             vcheckGLcall("glDrawPixels");
406           }
407           break;
408         case D3DFMT_A8R8G8B8:
409           {
410             glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
411             vcheckGLcall("glPixelStorei");
412             glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
413                          GL_BGRA, GL_UNSIGNED_BYTE, This->allocatedMemory);
414             vcheckGLcall("glDrawPixels");
415             glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
416             vcheckGLcall("glPixelStorei");
417           }
418           break;
419         default:
420           FIXME("Unsupported Format %u in locking func\n", This->myDesc.Format);
421         }
422
423         glPixelZoom(1.0,1.0);
424         vcheckGLcall("glPixelZoom");
425         glDrawBuffer(prev_draw);
426         vcheckGLcall("glDrawBuffer");
427         glRasterPos3iv(&prev_rasterpos[0]);
428         vcheckGLcall("glRasterPos3iv");
429
430     /* Reset to previous pack row length / blending state */
431     glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
432     if (This->Device->StateBlock->renderstate[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
433
434         LEAVE_GL();
435
436         /** restore clean dirty state */
437         IDirect3DSurface8Impl_CleanDirtyRect(iface);
438
439       } else {
440         FIXME("unsupported unlocking to Rendering surface surf@%p usage(%lu)\n", This, This->myDesc.Usage);
441       }
442
443     } else if (D3DUSAGE_DEPTHSTENCIL & This->myDesc.Usage) { /* stencil surfaces */
444     
445       if (This == This->Device->depthStencilBuffer) {
446         FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This, This->myDesc.Usage);
447       } else {
448         FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->myDesc.Usage);
449       }
450
451     } else {
452       FIXME("unsupported unlocking to surface surf@%p usage(%lu)\n", This, This->myDesc.Usage);
453     }
454
455 unlock_end:
456     This->locked = FALSE;
457     memset(&This->lockedRect, 0, sizeof(RECT));
458     return D3D_OK;
459 }
460
461
462 ICOM_VTABLE(IDirect3DSurface8) Direct3DSurface8_Vtbl =
463 {
464     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
465     IDirect3DSurface8Impl_QueryInterface,
466     IDirect3DSurface8Impl_AddRef,
467     IDirect3DSurface8Impl_Release,
468     IDirect3DSurface8Impl_GetDevice,
469     IDirect3DSurface8Impl_SetPrivateData,
470     IDirect3DSurface8Impl_GetPrivateData,
471     IDirect3DSurface8Impl_FreePrivateData,
472     IDirect3DSurface8Impl_GetContainer,
473     IDirect3DSurface8Impl_GetDesc,
474     IDirect3DSurface8Impl_LockRect,
475     IDirect3DSurface8Impl_UnlockRect,
476 };
477
478
479 HRESULT WINAPI IDirect3DSurface8Impl_LoadTexture(LPDIRECT3DSURFACE8 iface, GLenum gl_target, GLenum gl_level) {
480   ICOM_THIS(IDirect3DSurface8Impl,iface);
481
482   if (This->inTexture)
483     return D3D_OK;
484   if (This->inPBuffer) {
485     ENTER_GL();
486     if (gl_level != 0)
487       FIXME("Surface in texture is only supported for level 0\n");
488     else if (This->myDesc.Format == D3DFMT_P8 || This->myDesc.Format == D3DFMT_A8P8 ||
489         This->myDesc.Format == D3DFMT_DXT1 || This->myDesc.Format == D3DFMT_DXT3 ||
490         This->myDesc.Format == D3DFMT_DXT5)
491       FIXME("Format %d not supported\n", This->myDesc.Format);
492     else {
493         glCopyTexImage2D(gl_target,
494                          0,
495                          D3DFmt2GLIntFmt(This->Device,
496                          This->myDesc.Format),
497                          0,
498                          0,/*This->surfaces[j][i]->myDesc.Height-1,*/
499                          This->myDesc.Width,
500                          This->myDesc.Height,
501                          0);
502         TRACE("Updating target %d\n", gl_target);
503         This->inTexture = TRUE;
504     }
505     LEAVE_GL();
506     return D3D_OK;
507   }
508   
509   if ((This->myDesc.Format == D3DFMT_P8 || This->myDesc.Format == D3DFMT_A8P8) && 
510       !GL_SUPPORT_DEV(EXT_PALETTED_TEXTURE, This->Device)) {
511     /**
512      * wanted a paletted texture and not really support it in HW 
513      * so software emulation code begin
514      */
515     UINT i;
516     PALETTEENTRY* pal = This->Device->palettes[This->Device->currentPalette];
517     VOID* surface = (VOID*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->myDesc.Width * This->myDesc.Height * sizeof(DWORD));
518     BYTE* dst = (BYTE*) surface;
519     BYTE* src = (BYTE*) This->allocatedMemory;
520           
521     for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
522       BYTE color = *src++;
523       *dst++ = pal[color].peRed;
524       *dst++ = pal[color].peGreen;
525       *dst++ = pal[color].peBlue;
526       if (This->myDesc.Format == D3DFMT_A8P8)
527         *dst++ = pal[color].peFlags; 
528       else
529         *dst++ = 0xFF; 
530     }
531
532     ENTER_GL();
533     
534     TRACE("Calling glTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
535           gl_target,
536           gl_level, 
537           GL_RGBA,
538           This->myDesc.Width, 
539           This->myDesc.Height, 
540           0, 
541           GL_RGBA,
542           GL_UNSIGNED_BYTE,
543           surface);
544     glTexImage2D(gl_target,
545                  gl_level, 
546                  GL_RGBA,
547                  This->myDesc.Width,
548                  This->myDesc.Height,
549                  0,
550                  GL_RGBA,
551                  GL_UNSIGNED_BYTE,
552                  surface);
553     checkGLcall("glTexImage2D");
554     HeapFree(GetProcessHeap(), 0, surface);
555
556     LEAVE_GL();
557
558     return D3D_OK;    
559   }
560
561   if (This->myDesc.Format == D3DFMT_DXT1 || 
562       This->myDesc.Format == D3DFMT_DXT3 || 
563       This->myDesc.Format == D3DFMT_DXT5) {
564     if (GL_SUPPORT_DEV(EXT_TEXTURE_COMPRESSION_S3TC, This->Device)) {
565       TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, 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             This->myDesc.Size,
573             This->allocatedMemory);
574       
575       ENTER_GL();
576
577       glCompressedTexImage2D(gl_target, 
578                              gl_level, 
579                              D3DFmt2GLIntFmt(This->Device, This->myDesc.Format),
580                              This->myDesc.Width,
581                              This->myDesc.Height,
582                              0,
583                              This->myDesc.Size,
584                              This->allocatedMemory);
585       checkGLcall("glCommpressedTexTexImage2D");
586
587       LEAVE_GL();
588     } else {
589       FIXME("Using DXT1/3/5 without advertized support\n");
590     }
591   } else {
592     TRACE("Calling glTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
593           gl_target, 
594           gl_level, 
595           D3DFmt2GLIntFmt(This->Device, This->myDesc.Format),
596           This->myDesc.Width, 
597           This->myDesc.Height, 
598           0, 
599           D3DFmt2GLFmt(This->Device, This->myDesc.Format), 
600           D3DFmt2GLType(This->Device, This->myDesc.Format),
601           This->allocatedMemory);
602
603     ENTER_GL();
604
605     glTexImage2D(gl_target, 
606                  gl_level,
607                  D3DFmt2GLIntFmt(This->Device, This->myDesc.Format),
608                  This->myDesc.Width,
609                  This->myDesc.Height,
610                  0,
611                  D3DFmt2GLFmt(This->Device, This->myDesc.Format),
612                  D3DFmt2GLType(This->Device, This->myDesc.Format),
613                  This->allocatedMemory);
614     checkGLcall("glTexImage2D");
615
616     LEAVE_GL();
617
618 #if 0
619     {
620       static unsigned int gen = 0;
621       char buffer[4096];
622       ++gen;
623       if ((gen % 10) == 0) {
624         snprintf(buffer, sizeof(buffer), "/tmp/surface%u_level%u_%u.ppm", gl_target, gl_level, gen);
625         IDirect3DSurface8Impl_SaveSnapshot((LPDIRECT3DSURFACE8) This, buffer);
626       }
627     }
628 #endif
629   }
630
631   return D3D_OK;
632 }
633
634 #include <errno.h>
635 HRESULT WINAPI IDirect3DSurface8Impl_SaveSnapshot(LPDIRECT3DSURFACE8 iface, const char* filename) {
636   FILE* f = NULL;
637   ULONG i;
638   ICOM_THIS(IDirect3DSurface8Impl,iface);
639
640   f = fopen(filename, "w+");
641   if (NULL == f) {
642     ERR("opening of %s failed with: %s\n", filename, strerror(errno));
643     return D3DERR_INVALIDCALL;
644   }
645
646   TRACE("opened %s with format %s\n", filename, debug_d3dformat(This->myDesc.Format));
647
648   fprintf(f, "P6\n%u %u\n255\n", This->myDesc.Width, This->myDesc.Height);
649   switch (This->myDesc.Format) {
650   case D3DFMT_X8R8G8B8:
651   case D3DFMT_A8R8G8B8:
652     {
653       DWORD color;
654       for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
655         color = ((DWORD*) This->allocatedMemory)[i];
656         fputc((color >> 16) & 0xFF, f);
657         fputc((color >>  8) & 0xFF, f);
658         fputc((color >>  0) & 0xFF, f);
659       }
660     }
661     break;
662   case D3DFMT_R8G8B8:
663     {
664       BYTE* color;
665       for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
666         color = ((BYTE*) This->allocatedMemory) + (3 * i);
667         fputc((color[0]) & 0xFF, f);
668         fputc((color[1]) & 0xFF, f);
669         fputc((color[2]) & 0xFF, f);
670       }
671     }
672     break;
673   case D3DFMT_A1R5G5B5: 
674     {
675       WORD color;
676       for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
677         color = ((WORD*) This->allocatedMemory)[i];
678         fputc(((color >> 10) & 0x1F) * 255 / 31, f);
679         fputc(((color >>  5) & 0x1F) * 255 / 31, f);
680         fputc(((color >>  0) & 0x1F) * 255 / 31, f);
681       }
682     }
683     break;
684   case D3DFMT_A4R4G4B4:
685     {
686       WORD color;
687       for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
688         color = ((WORD*) This->allocatedMemory)[i];
689         fputc(((color >>  8) & 0x0F) * 255 / 15, f);
690         fputc(((color >>  4) & 0x0F) * 255 / 15, f);
691         fputc(((color >>  0) & 0x0F) * 255 / 15, f);
692       }
693     }
694     break;
695
696   case D3DFMT_R5G6B5: 
697     {
698       WORD color;
699       for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
700         color = ((WORD*) This->allocatedMemory)[i];
701         fputc(((color >> 11) & 0x1F) * 255 / 31, f);
702         fputc(((color >>  5) & 0x3F) * 255 / 63, f);
703         fputc(((color >>  0) & 0x1F) * 255 / 31, f);
704       }
705     }
706     break;
707   default: 
708     FIXME("Unimplemented dump mode format(%u,%s)\n", This->myDesc.Format, debug_d3dformat(This->myDesc.Format));
709   }
710   fclose(f);
711   return D3D_OK;
712 }
713
714 HRESULT WINAPI IDirect3DSurface8Impl_CleanDirtyRect(LPDIRECT3DSURFACE8 iface) {
715   ICOM_THIS(IDirect3DSurface8Impl,iface);
716   This->Dirty = FALSE;
717   This->dirtyRect.left   = This->myDesc.Width;
718   This->dirtyRect.top    = This->myDesc.Height;
719   This->dirtyRect.right  = 0;
720   This->dirtyRect.bottom = 0;
721   return D3D_OK;
722 }
723
724 /**
725  * Raphael:
726  *   very stupid way to handle multiple dirty rects but it works :)
727  */
728 extern HRESULT WINAPI IDirect3DSurface8Impl_AddDirtyRect(LPDIRECT3DSURFACE8 iface, CONST RECT* pDirtyRect) {
729   ICOM_THIS(IDirect3DSurface8Impl,iface);
730   This->Dirty = TRUE;
731   if (NULL != pDirtyRect) {
732     This->dirtyRect.left   = min(This->dirtyRect.left,   pDirtyRect->left);
733     This->dirtyRect.top    = min(This->dirtyRect.top,    pDirtyRect->top);
734     This->dirtyRect.right  = max(This->dirtyRect.right,  pDirtyRect->right);
735     This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
736   } else {
737     This->dirtyRect.left   = 0;
738     This->dirtyRect.top    = 0;
739     This->dirtyRect.right  = This->myDesc.Width;
740     This->dirtyRect.bottom = This->myDesc.Height;
741   }
742   return D3D_OK;
743 }