- implement SetRenderState D3DRS_FOGENABLE/D3DRS_RANGEFOGENABLE
[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       !GL_SUPPORT_DEV(EXT_PALETTED_TEXTURE, This->Device)) {
479     /**
480      * wanted a paletted texture and not really support it in HW 
481      * so software emulation code begin
482      */
483     UINT i;
484     PALETTEENTRY* pal = This->Device->palettes[This->Device->currentPalette];
485     VOID* surface = (VOID*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->myDesc.Width * This->myDesc.Height * sizeof(DWORD));
486     BYTE* dst = (BYTE*) surface;
487     BYTE* src = (BYTE*) This->allocatedMemory;
488           
489     for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
490       BYTE color = *src++;
491       *dst++ = pal[color].peRed;
492       *dst++ = pal[color].peGreen;
493       *dst++ = pal[color].peBlue;
494       if (This->myDesc.Format == D3DFMT_A8P8)
495         *dst++ = pal[color].peFlags; 
496       else
497         *dst++ = 0xFF; 
498     }
499
500     ENTER_GL();
501     
502     TRACE("Calling glTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
503           gl_target,
504           gl_level, 
505           GL_RGBA,
506           This->myDesc.Width, 
507           This->myDesc.Height, 
508           0, 
509           GL_RGBA,
510           GL_UNSIGNED_BYTE,
511           surface);
512     glTexImage2D(gl_target,
513                  gl_level, 
514                  GL_RGBA,
515                  This->myDesc.Width,
516                  This->myDesc.Height,
517                  0,
518                  GL_RGBA,
519                  GL_UNSIGNED_BYTE,
520                  surface);
521     checkGLcall("glTexImage2D");
522     HeapFree(GetProcessHeap(), 0, surface);
523
524     LEAVE_GL();
525
526     return D3D_OK;    
527   }
528
529   if (This->myDesc.Format == D3DFMT_DXT1 || 
530       This->myDesc.Format == D3DFMT_DXT3 || 
531       This->myDesc.Format == D3DFMT_DXT5) {
532     if (GL_SUPPORT_DEV(EXT_TEXTURE_COMPRESSION_S3TC, This->Device)) {
533       TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
534             gl_target, 
535             gl_level, 
536             D3DFmt2GLIntFmt(This->Device, This->myDesc.Format), 
537             This->myDesc.Width, 
538             This->myDesc.Height, 
539             0, 
540             This->myDesc.Size,
541             This->allocatedMemory);
542       
543       ENTER_GL();
544
545       glCompressedTexImage2D(gl_target, 
546                              gl_level, 
547                              D3DFmt2GLIntFmt(This->Device, This->myDesc.Format),
548                              This->myDesc.Width,
549                              This->myDesc.Height,
550                              0,
551                              This->myDesc.Size,
552                              This->allocatedMemory);
553       checkGLcall("glCommpressedTexTexImage2D");
554
555       LEAVE_GL();
556     } else {
557       FIXME("Using DXT1/3/5 without advertized support\n");
558     }
559   } else {
560     TRACE("Calling glTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
561           gl_target, 
562           gl_level, 
563           D3DFmt2GLIntFmt(This->Device, This->myDesc.Format),
564           This->myDesc.Width, 
565           This->myDesc.Height, 
566           0, 
567           D3DFmt2GLFmt(This->Device, This->myDesc.Format), 
568           D3DFmt2GLType(This->Device, This->myDesc.Format),
569           This->allocatedMemory);
570
571     ENTER_GL();
572
573     glTexImage2D(gl_target, 
574                  gl_level,
575                  D3DFmt2GLIntFmt(This->Device, This->myDesc.Format),
576                  This->myDesc.Width,
577                  This->myDesc.Height,
578                  0,
579                  D3DFmt2GLFmt(This->Device, This->myDesc.Format),
580                  D3DFmt2GLType(This->Device, This->myDesc.Format),
581                  This->allocatedMemory);
582     checkGLcall("glTexImage2D");
583
584     LEAVE_GL();
585
586 #if 0
587     {
588       static unsigned int gen = 0;
589       char buffer[4096];
590       ++gen;
591       if ((gen % 10) == 0) {
592         snprintf(buffer, sizeof(buffer), "/tmp/surface%u_level%u_%u.ppm", gl_target, gl_level, gen);
593         IDirect3DSurface8Impl_SaveSnapshot((LPDIRECT3DSURFACE8) This, buffer);
594       }
595     }
596 #endif
597   }
598
599   return D3D_OK;
600 }
601
602 #include <errno.h>
603 HRESULT WINAPI IDirect3DSurface8Impl_SaveSnapshot(LPDIRECT3DSURFACE8 iface, const char* filename) {
604   FILE* f = NULL;
605   ULONG i;
606   ICOM_THIS(IDirect3DSurface8Impl,iface);
607
608   f = fopen(filename, "w+");
609   if (NULL == f) {
610     ERR("opening of %s failed with: %s\n", filename, strerror(errno));
611     return D3DERR_INVALIDCALL;
612   }
613
614   TRACE("opened %s with format %s\n", filename, debug_d3dformat(This->myDesc.Format));
615
616   fprintf(f, "P6\n%u %u\n255\n", This->myDesc.Width, This->myDesc.Height);
617   switch (This->myDesc.Format) {
618   case D3DFMT_X8R8G8B8:
619   case D3DFMT_A8R8G8B8:
620     {
621       DWORD color;
622       for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
623         color = ((DWORD*) This->allocatedMemory)[i];
624         fputc((color >> 16) & 0xFF, f);
625         fputc((color >>  8) & 0xFF, f);
626         fputc((color >>  0) & 0xFF, f);
627       }
628     }
629     break;
630   case D3DFMT_R8G8B8:
631     {
632       BYTE* color;
633       for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
634         color = ((BYTE*) This->allocatedMemory) + (3 * i);
635         fputc((color[0]) & 0xFF, f);
636         fputc((color[1]) & 0xFF, f);
637         fputc((color[2]) & 0xFF, f);
638       }
639     }
640     break;
641   case D3DFMT_A1R5G5B5: 
642     {
643       WORD color;
644       for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
645         color = ((WORD*) This->allocatedMemory)[i];
646         fputc(((color >> 10) & 0x1F) * 255 / 31, f);
647         fputc(((color >>  5) & 0x1F) * 255 / 31, f);
648         fputc(((color >>  0) & 0x1F) * 255 / 31, f);
649       }
650     }
651     break;
652   case D3DFMT_A4R4G4B4:
653     {
654       WORD color;
655       for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
656         color = ((WORD*) This->allocatedMemory)[i];
657         fputc(((color >>  8) & 0x0F) * 255 / 15, f);
658         fputc(((color >>  4) & 0x0F) * 255 / 15, f);
659         fputc(((color >>  0) & 0x0F) * 255 / 15, f);
660       }
661     }
662     break;
663
664   case D3DFMT_R5G6B5: 
665     {
666       WORD color;
667       for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
668         color = ((WORD*) This->allocatedMemory)[i];
669         fputc(((color >> 11) & 0x1F) * 255 / 31, f);
670         fputc(((color >>  5) & 0x3F) * 255 / 63, f);
671         fputc(((color >>  0) & 0x1F) * 255 / 31, f);
672       }
673     }
674     break;
675   default: 
676     FIXME("Unimplemented dump mode format(%u,%s)\n", This->myDesc.Format, debug_d3dformat(This->myDesc.Format));
677   }
678   fclose(f);
679   return D3D_OK;
680 }
681
682 HRESULT WINAPI IDirect3DSurface8Impl_CleanDirtyRect(LPDIRECT3DSURFACE8 iface) {
683   ICOM_THIS(IDirect3DSurface8Impl,iface);
684   This->Dirty = FALSE;
685   This->dirtyRect.left   = This->myDesc.Width;
686   This->dirtyRect.top    = This->myDesc.Height;
687   This->dirtyRect.right  = 0;
688   This->dirtyRect.bottom = 0;
689   return D3D_OK;
690 }
691
692 /**
693  * Raphael:
694  *   very stupid way to handle multiple dirty rects but it works :)
695  */
696 extern HRESULT WINAPI IDirect3DSurface8Impl_AddDirtyRect(LPDIRECT3DSURFACE8 iface, CONST RECT* pDirtyRect) {
697   ICOM_THIS(IDirect3DSurface8Impl,iface);
698   This->Dirty = TRUE;
699   if (NULL != pDirtyRect) {
700     This->dirtyRect.left   = min(This->dirtyRect.left,   pDirtyRect->left);
701     This->dirtyRect.top    = min(This->dirtyRect.top,    pDirtyRect->top);
702     This->dirtyRect.right  = max(This->dirtyRect.right,  pDirtyRect->right);
703     This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
704   } else {
705     This->dirtyRect.left   = 0;
706     This->dirtyRect.top    = 0;
707     This->dirtyRect.right  = This->myDesc.Width;
708     This->dirtyRect.bottom = This->myDesc.Height;
709   }
710   return D3D_OK;
711 }