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