- New implementation of SendMessage, ReceiveMessage, ReplyMessage functions
[wine] / graphics / d3dtexture.c
1 /* Direct3D Texture
2    (c) 1998 Lionel ULMER
3    
4    This files contains the implementation of interface Direct3DTexture2. */
5
6
7 #include "config.h"
8 #include "windows.h"
9 #include "wintypes.h"
10 #include "winerror.h"
11 #include "wine/obj_base.h"
12 #include "heap.h"
13 #include "ddraw.h"
14 #include "d3d.h"
15 #include "debug.h"
16 #include "objbase.h"
17
18 #include "d3d_private.h"
19
20 #ifdef HAVE_MESAGL
21
22 /* Define this if you want to save to a file all the textures used by a game
23    (can be funny to see how they managed to cram all the pictures in
24    texture memory) */
25 #undef TEXTURE_SNOOP
26
27 static IDirect3DTexture2_VTable texture2_vtable;
28 static IDirect3DTexture_VTable texture_vtable;
29
30 /*******************************************************************************
31  *                              Texture2 Creation functions
32  */
33 LPDIRECT3DTEXTURE2 d3dtexture2_create(LPDIRECTDRAWSURFACE4 surf)
34 {
35   LPDIRECT3DTEXTURE2 mat;
36   
37   mat = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirect3DTexture2));
38   mat->ref = 1;
39   mat->lpvtbl = &texture2_vtable;
40   mat->surface = surf;
41   
42   return mat;
43 }
44
45 /*******************************************************************************
46  *                              Texture Creation functions
47  */
48 LPDIRECT3DTEXTURE d3dtexture_create(LPDIRECTDRAWSURFACE4 surf)
49 {
50   LPDIRECT3DTEXTURE mat;
51   
52   mat = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirect3DTexture));
53   mat->ref = 1;
54   mat->lpvtbl = (IDirect3DTexture2_VTable*) &texture_vtable;
55   mat->surface = surf;
56   
57   return mat;
58 }
59
60
61 /*******************************************************************************
62  *                              IDirect3DTexture2 methods
63  */
64
65 static HRESULT WINAPI IDirect3DTexture2_QueryInterface(LPDIRECT3DTEXTURE2 this,
66                                                         REFIID riid,
67                                                         LPVOID* ppvObj)
68 {
69   char xrefiid[50];
70   
71   WINE_StringFromCLSID((LPCLSID)riid,xrefiid);
72   FIXME(ddraw, "(%p)->(%s,%p): stub\n", this, xrefiid,ppvObj);
73   
74   return S_OK;
75 }
76
77
78
79 static ULONG WINAPI IDirect3DTexture2_AddRef(LPDIRECT3DTEXTURE2 this)
80 {
81   TRACE(ddraw, "(%p)->()incrementing from %lu.\n", this, this->ref );
82   
83   return ++(this->ref);
84 }
85
86
87
88 static ULONG WINAPI IDirect3DTexture2_Release(LPDIRECT3DTEXTURE2 this)
89 {
90   FIXME( ddraw, "(%p)->() decrementing from %lu.\n", this, this->ref );
91   
92   if (!--(this->ref)) {
93     /* Delete texture from OpenGL */
94     glDeleteTextures(1, &(this->tex_name));
95     
96     /* Release surface */
97     this->surface->lpvtbl->fnRelease(this->surface);
98     
99     HeapFree(GetProcessHeap(),0,this);
100     return 0;
101   }
102   
103   return this->ref;
104 }
105
106 /*** IDirect3DTexture methods ***/
107 static HRESULT WINAPI IDirect3DTexture_GetHandle(LPDIRECT3DTEXTURE this,
108                                                  LPDIRECT3DDEVICE lpD3DDevice,
109                                                  LPD3DTEXTUREHANDLE lpHandle)
110 {
111   FIXME(ddraw, "(%p)->(%p,%p): stub\n", this, lpD3DDevice, lpHandle);
112
113   *lpHandle = (DWORD) this;
114   
115   /* Now, bind a new texture */
116   lpD3DDevice->set_context(lpD3DDevice);
117   this->D3Ddevice = (void *) lpD3DDevice;
118   if (this->tex_name == 0)
119     glGenTextures(1, &(this->tex_name));
120
121   TRACE(ddraw, "OpenGL texture handle is : %d\n", this->tex_name);
122   
123   return D3D_OK;
124 }
125
126 static HRESULT WINAPI IDirect3DTexture_Initialize(LPDIRECT3DTEXTURE this,
127                                                   LPDIRECT3DDEVICE lpD3DDevice,
128                                                   LPDIRECTDRAWSURFACE lpSurface)
129 {
130   TRACE(ddraw, "(%p)->(%p,%p)\n", this, lpD3DDevice, lpSurface);
131
132   return DDERR_ALREADYINITIALIZED;
133 }
134
135 static HRESULT WINAPI IDirect3DTexture_Unload(LPDIRECT3DTEXTURE this)
136 {
137   FIXME(ddraw, "(%p)->(): stub\n", this);
138
139   return D3D_OK;
140 }
141
142 /*** IDirect3DTexture2 methods ***/
143 static HRESULT WINAPI IDirect3DTexture2_GetHandle(LPDIRECT3DTEXTURE2 this,
144                                                   LPDIRECT3DDEVICE2 lpD3DDevice2,
145                                                   LPD3DTEXTUREHANDLE lpHandle)
146 {
147   TRACE(ddraw, "(%p)->(%p,%p)\n", this, lpD3DDevice2, lpHandle);
148
149   /* For 32 bits OSes, handles = pointers */
150   *lpHandle = (DWORD) this;
151   
152   /* Now, bind a new texture */
153   lpD3DDevice2->set_context(lpD3DDevice2);
154   this->D3Ddevice = (void *) lpD3DDevice2;
155   if (this->tex_name == 0)
156   glGenTextures(1, &(this->tex_name));
157
158   TRACE(ddraw, "OpenGL texture handle is : %d\n", this->tex_name);
159   
160   return D3D_OK;
161 }
162
163 /* Common methods */
164 static HRESULT WINAPI IDirect3DTexture2_PaletteChanged(LPDIRECT3DTEXTURE2 this,
165                                                        DWORD dwStart,
166                                                        DWORD dwCount)
167 {
168   FIXME(ddraw, "(%p)->(%8ld,%8ld): stub\n", this, dwStart, dwCount);
169
170   return D3D_OK;
171 }
172
173 /* NOTE : if you experience crashes in this function, you must have a buggy
174           version of Mesa. See the file d3dtexture.c for a cure */
175 static HRESULT WINAPI IDirect3DTexture2_Load(LPDIRECT3DTEXTURE2 this,
176                                              LPDIRECT3DTEXTURE2 lpD3DTexture2)
177 {
178   DDSURFACEDESC *src_d, *dst_d;
179   TRACE(ddraw, "(%p)->(%p)\n", this, lpD3DTexture2);
180
181   TRACE(ddraw, "Copied to surface %p, surface %p\n", this->surface, lpD3DTexture2->surface);
182
183   /* Suppress the ALLOCONLOAD flag */
184   this->surface->s.surface_desc.ddsCaps.dwCaps &= ~DDSCAPS_ALLOCONLOAD;
185
186   /* Copy one surface on the other */
187   dst_d = &(this->surface->s.surface_desc);
188   src_d = &(lpD3DTexture2->surface->s.surface_desc);
189
190   if ((src_d->dwWidth != dst_d->dwWidth) || (src_d->dwHeight != dst_d->dwHeight)) {
191     /* Should also check for same pixel format, lPitch, ... */
192     ERR(ddraw, "Error in surface sizes\n");
193     return D3DERR_TEXTURE_LOAD_FAILED;
194   } else {
195     /* LPDIRECT3DDEVICE2 d3dd = (LPDIRECT3DDEVICE2) this->D3Ddevice; */
196     /* I should put a macro for the calculus of bpp */
197     int bpp = (src_d->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8 ?
198                1 /* 8 bit of palette index */:
199                src_d->ddpfPixelFormat.x.dwRGBBitCount / 8 /* RGB bits for each colors */ );
200     GLuint current_texture;
201
202     /* Not sure if this is usefull ! */
203     memcpy(dst_d->y.lpSurface, src_d->y.lpSurface, src_d->dwWidth * src_d->dwHeight * bpp);
204
205     /* Now, load the texture */
206     /* d3dd->set_context(d3dd); We need to set the context somehow.... */
207     glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture);
208
209     /* If the GetHandle was not done, get the texture name here */
210     if (this->tex_name == 0)
211       glGenTextures(1, &(this->tex_name));
212     glBindTexture(GL_TEXTURE_2D, this->tex_name);
213
214     if (src_d->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) {
215       /* ****************
216          Paletted Texture
217          **************** */
218       LPDIRECTDRAWPALETTE pal = this->surface->s.palette;
219       BYTE table[256][4];
220       int i;
221       
222       if (pal == NULL) {
223         ERR(ddraw, "Palettized texture Loading with a NULL palette !\n");
224         return D3DERR_TEXTURE_LOAD_FAILED;
225       }
226
227       /* Get the surface's palette */
228       for (i = 0; i < 256; i++) {
229         table[i][0] = pal->palents[i].peRed;
230         table[i][1] = pal->palents[i].peGreen;
231         table[i][2] = pal->palents[i].peBlue;
232         if ((this->surface->s.surface_desc.dwFlags & DDSD_CKSRCBLT) &&
233             (i >= this->surface->s.surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue) &&
234             (i <= this->surface->s.surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue))
235           table[i][3] = 0x00;
236         else
237         table[i][3] = 0xFF;
238       }
239       
240 #ifdef TEXTURE_SNOOP
241       {
242         FILE *f;
243         char buf[32];
244         int x, y;
245         
246         sprintf(buf, "%d.pnm", this->tex_name);
247         f = fopen(buf, "wb");
248         fprintf(f, "P6\n%d %d\n255\n", src_d->dwWidth, src_d->dwHeight);
249         for (y = 0; y < src_d->dwHeight; y++) {
250           for (x = 0; x < src_d->dwWidth; x++) {
251             unsigned char c = ((unsigned char *) src_d->y.lpSurface)[y * src_d->dwWidth + x];
252             fputc(table[c][0], f);
253             fputc(table[c][1], f);
254             fputc(table[c][2], f);
255           }
256         }
257         fclose(f);
258       }
259 #endif 
260       /* Use Paletted Texture Extension */
261       glColorTableEXT(GL_TEXTURE_2D,    /* target */
262                       GL_RGBA,          /* internal format */
263                       256,              /* table size */
264                       GL_RGBA,          /* table format */
265                       GL_UNSIGNED_BYTE, /* table type */
266                       table);           /* the color table */
267
268       glTexImage2D(GL_TEXTURE_2D,       /* target */
269                    0,                   /* level */
270                    GL_COLOR_INDEX8_EXT, /* internal format */
271                    src_d->dwWidth, src_d->dwHeight, /* width, height */
272                    0,                   /* border */
273                    GL_COLOR_INDEX,      /* texture format */
274                    GL_UNSIGNED_BYTE,    /* texture type */
275                    src_d->y.lpSurface); /* the texture */
276     } else if (src_d->ddpfPixelFormat.dwFlags & DDPF_RGB) {
277       /* ************
278          RGB Textures
279          ************ */
280       if (src_d->ddpfPixelFormat.x.dwRGBBitCount == 8) {
281         /* **********************
282            GL_UNSIGNED_BYTE_3_3_2 
283            ********************** */
284         glTexImage2D(GL_TEXTURE_2D,
285                      0,
286                      GL_RGB,
287                      src_d->dwWidth, src_d->dwHeight,
288                      0,
289                      GL_RGB,
290                      GL_UNSIGNED_BYTE_3_3_2,
291                      src_d->y.lpSurface);
292       } else if (src_d->ddpfPixelFormat.x.dwRGBBitCount == 16) {
293         if (src_d->ddpfPixelFormat.xy.dwRGBAlphaBitMask == 0x00000000) {
294 #ifdef TEXTURE_SNOOP
295           {
296             FILE *f;
297             char buf[32];
298             int x, y;
299             
300             sprintf(buf, "%d.pnm", this->tex_name);
301             f = fopen(buf, "wb");
302             fprintf(f, "P6\n%d %d\n255\n", src_d->dwWidth, src_d->dwHeight);
303             for (y = 0; y < src_d->dwHeight; y++) {
304               for (x = 0; x < src_d->dwWidth; x++) {
305                 unsigned short c = ((unsigned short *) src_d->y.lpSurface)[y * src_d->dwWidth + x];
306                 fputc((c & 0xF800) >> 8, f);
307                 fputc((c & 0x07E0) >> 3, f);
308                 fputc((c & 0x001F) << 3, f);
309               }
310             }
311             fclose(f);
312           }
313 #endif
314           glTexImage2D(GL_TEXTURE_2D,
315                        0,
316                        GL_RGB,
317                        src_d->dwWidth, src_d->dwHeight,
318                        0,
319                        GL_RGB,
320                        GL_UNSIGNED_SHORT_5_6_5,
321                        src_d->y.lpSurface);
322         } else if (src_d->ddpfPixelFormat.xy.dwRGBAlphaBitMask == 0x00000001) {
323 #ifdef TEXTURE_SNOOP
324           {
325             FILE *f;
326             char buf[32];
327             int x, y;
328             
329             sprintf(buf, "%d.pnm", this->tex_name);
330             f = fopen(buf, "wb");
331             fprintf(f, "P6\n%d %d\n255\n", src_d->dwWidth, src_d->dwHeight);
332             for (y = 0; y < src_d->dwHeight; y++) {
333               for (x = 0; x < src_d->dwWidth; x++) {
334                 unsigned short c = ((unsigned short *) src_d->y.lpSurface)[y * src_d->dwWidth + x];
335                 fputc((c & 0xF800) >> 8, f);
336                 fputc((c & 0x07C0) >> 3, f);
337                 fputc((c & 0x003E) << 2, f);
338               }
339             }
340             fclose(f);
341           }
342 #endif
343           
344           glTexImage2D(GL_TEXTURE_2D,
345                        0,
346                        GL_RGBA,
347                        src_d->dwWidth, src_d->dwHeight,
348                        0,
349                        GL_RGBA,
350                        GL_UNSIGNED_SHORT_5_5_5_1,
351                        src_d->y.lpSurface);
352         } else if (src_d->ddpfPixelFormat.xy.dwRGBAlphaBitMask == 0x0000000F) {
353           glTexImage2D(GL_TEXTURE_2D,
354                        0,
355                        GL_RGBA,
356                        src_d->dwWidth, src_d->dwHeight,
357                        0,
358                        GL_RGBA,
359                        GL_UNSIGNED_SHORT_4_4_4_4,
360                        src_d->y.lpSurface);
361         } else {
362           ERR(ddraw, "Unhandled texture format (bad Aplha channel for a 16 bit texture)\n");
363         }
364       } else if (src_d->ddpfPixelFormat.x.dwRGBBitCount == 24) {
365         glTexImage2D(GL_TEXTURE_2D,
366                      0,
367                      GL_RGB,
368                      src_d->dwWidth, src_d->dwHeight,
369                      0,
370                      GL_RGB,
371                      GL_UNSIGNED_BYTE,
372                      src_d->y.lpSurface);
373       } else if (src_d->ddpfPixelFormat.x.dwRGBBitCount == 32) {
374         glTexImage2D(GL_TEXTURE_2D,
375                      0,
376                      GL_RGBA,
377                      src_d->dwWidth, src_d->dwHeight,
378                      0,
379                      GL_RGBA,
380                      GL_UNSIGNED_BYTE,
381                      src_d->y.lpSurface);
382       } else {
383         ERR(ddraw, "Unhandled texture format (bad RGB count)\n");
384       }
385     } else {
386       ERR(ddraw, "Unhandled texture format (neither RGB nor INDEX)\n");
387     }
388
389     glBindTexture(GL_TEXTURE_2D, current_texture);
390   }
391   
392   return D3D_OK;
393 }
394
395
396 /*******************************************************************************
397  *                              IDirect3DTexture2 VTable
398  */
399 static IDirect3DTexture2_VTable texture2_vtable = {
400   /*** IUnknown methods ***/
401   IDirect3DTexture2_QueryInterface,
402   IDirect3DTexture2_AddRef,
403   IDirect3DTexture2_Release,
404   /*** IDirect3DTexture methods ***/
405   IDirect3DTexture2_GetHandle,
406   IDirect3DTexture2_PaletteChanged,
407   IDirect3DTexture2_Load
408 };
409
410 /*******************************************************************************
411  *                              IDirect3DTexture VTable
412  */
413 static IDirect3DTexture_VTable texture_vtable = {
414   /*** IUnknown methods ***/
415   IDirect3DTexture2_QueryInterface,
416   IDirect3DTexture2_AddRef,
417   IDirect3DTexture2_Release,
418   /*** IDirect3DTexture methods ***/
419   IDirect3DTexture_Initialize,
420   IDirect3DTexture_GetHandle,
421   IDirect3DTexture2_PaletteChanged,
422   IDirect3DTexture2_Load,
423   IDirect3DTexture_Unload
424 };
425
426 #else /* HAVE_MESAGL */
427
428 /* These function should never be called if MesaGL is not present */
429 LPDIRECT3DTEXTURE2 d3dtexture2_create(LPDIRECTDRAWSURFACE4 surf) {
430   ERR(ddraw, "Should not be called...\n");
431   return NULL;
432 }
433
434 LPDIRECT3DTEXTURE d3dtexture_create(LPDIRECTDRAWSURFACE4 surf) {
435   ERR(ddraw, "Should not be called...\n");
436   return NULL;
437 }
438
439 #endif /* HAVE_MESAGL */