d3dx9_36: Added stub D3DXCreateCubeTextureFromFileInMemory.
[wine] / dlls / d3dx9_36 / shader.c
1 /*
2  * Copyright 2008 Luis Busquets
3  * Copyright 2009 Matteo Bruni
4  * Copyright 2011 Travis Athougies
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23 #include "wine/debug.h"
24 #include "wine/unicode.h"
25 #include "windef.h"
26 #include "wingdi.h"
27 #include "objbase.h"
28 #include "d3dcommon.h"
29 #include "d3dcompiler.h"
30 #include "d3dx9_36_private.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
33
34 /* This function is not declared in the SDK headers yet */
35 HRESULT WINAPI D3DAssemble(LPCVOID data, SIZE_T datasize, LPCSTR filename,
36                            const D3D_SHADER_MACRO *defines, ID3DInclude *include,
37                            UINT flags,
38                            ID3DBlob **shader, ID3DBlob **error_messages);
39
40 LPCSTR WINAPI D3DXGetPixelShaderProfile(LPDIRECT3DDEVICE9 device)
41 {
42     D3DCAPS9 caps;
43
44     TRACE("device %p\n", device);
45
46     if (!device) return NULL;
47
48     IDirect3DDevice9_GetDeviceCaps(device,&caps);
49
50     switch (caps.PixelShaderVersion)
51     {
52     case D3DPS_VERSION(1, 1):
53         return "ps_1_1";
54
55     case D3DPS_VERSION(1, 2):
56         return "ps_1_2";
57
58     case D3DPS_VERSION(1, 3):
59         return "ps_1_3";
60
61     case D3DPS_VERSION(1, 4):
62         return "ps_1_4";
63
64     case D3DPS_VERSION(2, 0):
65         if ((caps.PS20Caps.NumTemps>=22)                          &&
66             (caps.PS20Caps.Caps&D3DPS20CAPS_ARBITRARYSWIZZLE)     &&
67             (caps.PS20Caps.Caps&D3DPS20CAPS_GRADIENTINSTRUCTIONS) &&
68             (caps.PS20Caps.Caps&D3DPS20CAPS_PREDICATION)          &&
69             (caps.PS20Caps.Caps&D3DPS20CAPS_NODEPENDENTREADLIMIT) &&
70             (caps.PS20Caps.Caps&D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT))
71         {
72             return "ps_2_a";
73         }
74         if ((caps.PS20Caps.NumTemps>=32)                          &&
75             (caps.PS20Caps.Caps&D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT))
76         {
77             return "ps_2_b";
78         }
79         return "ps_2_0";
80
81     case D3DPS_VERSION(3, 0):
82         return "ps_3_0";
83     }
84
85     return NULL;
86 }
87
88 UINT WINAPI D3DXGetShaderSize(const DWORD *byte_code)
89 {
90     const DWORD *ptr = byte_code;
91
92     TRACE("byte_code %p\n", byte_code);
93
94     if (!ptr) return 0;
95
96     /* Look for the END token, skipping the VERSION token */
97     while (*++ptr != D3DSIO_END)
98     {
99         /* Skip comments */
100         if ((*ptr & D3DSI_OPCODE_MASK) == D3DSIO_COMMENT)
101         {
102             ptr += ((*ptr & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT);
103         }
104     }
105     ++ptr;
106
107     /* Return the shader size in bytes */
108     return (ptr - byte_code) * sizeof(*ptr);
109 }
110
111 DWORD WINAPI D3DXGetShaderVersion(const DWORD *byte_code)
112 {
113     TRACE("byte_code %p\n", byte_code);
114
115     return byte_code ? *byte_code : 0;
116 }
117
118 LPCSTR WINAPI D3DXGetVertexShaderProfile(LPDIRECT3DDEVICE9 device)
119 {
120     D3DCAPS9 caps;
121
122     TRACE("device %p\n", device);
123
124     if (!device) return NULL;
125
126     IDirect3DDevice9_GetDeviceCaps(device,&caps);
127
128     switch (caps.VertexShaderVersion)
129     {
130     case D3DVS_VERSION(1, 1):
131         return "vs_1_1";
132     case D3DVS_VERSION(2, 0):
133         if ((caps.VS20Caps.NumTemps>=13) &&
134             (caps.VS20Caps.DynamicFlowControlDepth==24) &&
135             (caps.VS20Caps.Caps&D3DPS20CAPS_PREDICATION))
136         {
137             return "vs_2_a";
138         }
139         return "vs_2_0";
140     case D3DVS_VERSION(3, 0):
141         return "vs_3_0";
142     }
143
144     return NULL;
145 }
146
147 HRESULT WINAPI D3DXFindShaderComment(CONST DWORD* byte_code, DWORD fourcc, LPCVOID* data, UINT* size)
148 {
149     CONST DWORD *ptr = byte_code;
150
151     TRACE("(%p, %x, %p, %p)\n", byte_code, fourcc, data, size);
152
153     if (!byte_code)
154         return D3DERR_INVALIDCALL;
155
156     while (*++ptr != D3DSIO_END)
157     {
158         /* Check if it is a comment */
159         if ((*ptr & D3DSI_OPCODE_MASK) == D3DSIO_COMMENT)
160         {
161             DWORD comment_size = (*ptr & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
162
163             /* Check if this is the comment we are looking for */
164             if (*(ptr + 1) == fourcc)
165             {
166                 UINT ctab_size = (comment_size - 1) * sizeof(DWORD);
167                 LPCVOID ctab_data = ptr + 2;
168                 if (size)
169                     *size = ctab_size;
170                 if (data)
171                     *data = ctab_data;
172                 TRACE("Returning comment data at %p with size %d\n", ctab_data, ctab_size);
173                 return D3D_OK;
174             }
175             ptr += comment_size;
176         }
177     }
178
179     return S_FALSE;
180 }
181
182 HRESULT WINAPI D3DXAssembleShader(LPCSTR data,
183                                   UINT data_len,
184                                   CONST D3DXMACRO* defines,
185                                   LPD3DXINCLUDE include,
186                                   DWORD flags,
187                                   LPD3DXBUFFER* shader,
188                                   LPD3DXBUFFER* error_messages)
189 {
190     /* Forward to d3dcompiler: the parameter types aren't really different,
191        the actual data types are equivalent */
192     HRESULT hr = D3DAssemble(data, data_len, NULL, (D3D_SHADER_MACRO *)defines,
193                              (ID3DInclude *)include, flags, (ID3DBlob **)shader,
194                              (ID3DBlob **)error_messages);
195
196     if(hr == E_FAIL) hr = D3DXERR_INVALIDDATA;
197     return hr;
198 }
199
200 /* D3DXInclude private implementation, used to implement
201    D3DXAssembleShaderFromFile from D3DXAssembleShader */
202 /* To be able to correctly resolve include search paths we have to store
203    the pathname of each include file. We store the pathname pointer right
204    before the file data. */
205 static HRESULT WINAPI d3dincludefromfile_open(ID3DXInclude *iface,
206                                               D3DXINCLUDE_TYPE include_type,
207                                               LPCSTR filename, LPCVOID parent_data,
208                                               LPCVOID *data, UINT *bytes) {
209     const char *p, *parent_name = "";
210     char *pathname = NULL;
211     char **buffer = NULL;
212     HANDLE file;
213     UINT size;
214
215     if(parent_data != NULL)
216         parent_name = *((const char **)parent_data - 1);
217
218     TRACE("Looking up for include file %s, parent %s\n", debugstr_a(filename), debugstr_a(parent_name));
219
220     if ((p = strrchr(parent_name, '\\')) || (p = strrchr(parent_name, '/'))) p++;
221     else p = parent_name;
222     pathname = HeapAlloc(GetProcessHeap(), 0, (p - parent_name) + strlen(filename) + 1);
223     if(!pathname)
224         return HRESULT_FROM_WIN32(GetLastError());
225
226     memcpy(pathname, parent_name, p - parent_name);
227     strcpy(pathname + (p - parent_name), filename);
228
229     file = CreateFileA(pathname, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
230     if(file == INVALID_HANDLE_VALUE)
231         goto error;
232
233     TRACE("Include file found at pathname = %s\n", debugstr_a(pathname));
234
235     size = GetFileSize(file, NULL);
236     if(size == INVALID_FILE_SIZE)
237         goto error;
238
239     buffer = HeapAlloc(GetProcessHeap(), 0, size + sizeof(char *));
240     if(!buffer)
241         goto error;
242     *buffer = pathname;
243     if(!ReadFile(file, buffer + 1, size, bytes, NULL))
244         goto error;
245
246     *data = buffer + 1;
247
248     CloseHandle(file);
249     return S_OK;
250
251 error:
252     CloseHandle(file);
253     HeapFree(GetProcessHeap(), 0, pathname);
254     HeapFree(GetProcessHeap(), 0, buffer);
255     return HRESULT_FROM_WIN32(GetLastError());
256 }
257
258 static HRESULT WINAPI d3dincludefromfile_close(ID3DXInclude *iface, LPCVOID data) {
259     HeapFree(GetProcessHeap(), 0, *((char **)data - 1));
260     HeapFree(GetProcessHeap(), 0, (char **)data - 1);
261     return S_OK;
262 }
263
264 static const struct ID3DXIncludeVtbl D3DXInclude_Vtbl = {
265     d3dincludefromfile_open,
266     d3dincludefromfile_close
267 };
268
269 struct D3DXIncludeImpl {
270     ID3DXInclude ID3DXInclude_iface;
271 };
272
273 HRESULT WINAPI D3DXAssembleShaderFromFileA(LPCSTR filename,
274                                            CONST D3DXMACRO* defines,
275                                            LPD3DXINCLUDE include,
276                                            DWORD flags,
277                                            LPD3DXBUFFER* shader,
278                                            LPD3DXBUFFER* error_messages)
279 {
280     LPWSTR filename_w = NULL;
281     DWORD len;
282     HRESULT ret;
283
284     if (!filename) return D3DXERR_INVALIDDATA;
285
286     len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
287     filename_w = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
288     if (!filename_w) return E_OUTOFMEMORY;
289     MultiByteToWideChar(CP_ACP, 0, filename, -1, filename_w, len);
290
291     ret = D3DXAssembleShaderFromFileW(filename_w, defines, include, flags, shader, error_messages);
292
293     HeapFree(GetProcessHeap(), 0, filename_w);
294     return ret;
295 }
296
297 HRESULT WINAPI D3DXAssembleShaderFromFileW(LPCWSTR filename,
298                                            CONST D3DXMACRO* defines,
299                                            LPD3DXINCLUDE include,
300                                            DWORD flags,
301                                            LPD3DXBUFFER* shader,
302                                            LPD3DXBUFFER* error_messages)
303 {
304     void *buffer;
305     DWORD len;
306     HRESULT hr;
307     struct D3DXIncludeImpl includefromfile;
308
309     if(FAILED(map_view_of_file(filename, &buffer, &len)))
310         return D3DXERR_INVALIDDATA;
311
312     if(!include)
313     {
314         includefromfile.ID3DXInclude_iface.lpVtbl = &D3DXInclude_Vtbl;
315         include = &includefromfile.ID3DXInclude_iface;
316     }
317
318     hr = D3DXAssembleShader(buffer, len, defines, include, flags,
319                             shader, error_messages);
320
321     UnmapViewOfFile(buffer);
322     return hr;
323 }
324
325 HRESULT WINAPI D3DXAssembleShaderFromResourceA(HMODULE module,
326                                                LPCSTR resource,
327                                                CONST D3DXMACRO* defines,
328                                                LPD3DXINCLUDE include,
329                                                DWORD flags,
330                                                LPD3DXBUFFER* shader,
331                                                LPD3DXBUFFER* error_messages)
332 {
333     HRSRC res;
334     LPCSTR buffer;
335     DWORD len;
336
337     if (!(res = FindResourceA(module, resource, (LPCSTR)RT_RCDATA)))
338         return D3DXERR_INVALIDDATA;
339     if (FAILED(load_resource_into_memory(module, res, (LPVOID *)&buffer, &len)))
340         return D3DXERR_INVALIDDATA;
341     return D3DXAssembleShader(buffer, len, defines, include, flags,
342                               shader, error_messages);
343 }
344
345 HRESULT WINAPI D3DXAssembleShaderFromResourceW(HMODULE module,
346                                                LPCWSTR resource,
347                                                CONST D3DXMACRO* defines,
348                                                LPD3DXINCLUDE include,
349                                                DWORD flags,
350                                                LPD3DXBUFFER* shader,
351                                                LPD3DXBUFFER* error_messages)
352 {
353     HRSRC res;
354     LPCSTR buffer;
355     DWORD len;
356
357     if (!(res = FindResourceW(module, resource, (LPCWSTR)RT_RCDATA)))
358         return D3DXERR_INVALIDDATA;
359     if (FAILED(load_resource_into_memory(module, res, (LPVOID *)&buffer, &len)))
360         return D3DXERR_INVALIDDATA;
361     return D3DXAssembleShader(buffer, len, defines, include, flags,
362                               shader, error_messages);
363 }
364
365 HRESULT WINAPI D3DXCompileShader(LPCSTR pSrcData,
366                                  UINT srcDataLen,
367                                  CONST D3DXMACRO* pDefines,
368                                  LPD3DXINCLUDE pInclude,
369                                  LPCSTR pFunctionName,
370                                  LPCSTR pProfile,
371                                  DWORD Flags,
372                                  LPD3DXBUFFER* ppShader,
373                                  LPD3DXBUFFER* ppErrorMsgs,
374                                  LPD3DXCONSTANTTABLE * ppConstantTable)
375 {
376     HRESULT hr = D3DCompile(pSrcData, srcDataLen, NULL,
377                             (D3D_SHADER_MACRO *)pDefines, (ID3DInclude *)pInclude,
378                             pFunctionName, pProfile, Flags, 0,
379                             (ID3DBlob **)ppShader, (ID3DBlob **)ppErrorMsgs);
380
381     if(SUCCEEDED(hr) && ppConstantTable)
382         return D3DXGetShaderConstantTable(ID3DXBuffer_GetBufferPointer(*ppShader),
383                                           ppConstantTable);
384     return hr;
385 }
386
387 HRESULT WINAPI D3DXCompileShaderFromFileA(LPCSTR filename,
388                                           CONST D3DXMACRO* defines,
389                                           LPD3DXINCLUDE include,
390                                           LPCSTR entrypoint,
391                                           LPCSTR profile,
392                                           DWORD flags,
393                                           LPD3DXBUFFER* shader,
394                                           LPD3DXBUFFER* error_messages,
395                                           LPD3DXCONSTANTTABLE* constant_table)
396 {
397     LPWSTR filename_w = NULL;
398     DWORD len;
399     HRESULT ret;
400
401     if (!filename) return D3DXERR_INVALIDDATA;
402
403     len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
404     filename_w = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
405     if (!filename_w) return E_OUTOFMEMORY;
406     MultiByteToWideChar(CP_ACP, 0, filename, -1, filename_w, len);
407
408     ret = D3DXCompileShaderFromFileW(filename_w, defines, include,
409                                      entrypoint, profile, flags,
410                                      shader, error_messages, constant_table);
411
412     HeapFree(GetProcessHeap(), 0, filename_w);
413     return ret;
414 }
415
416 HRESULT WINAPI D3DXCompileShaderFromFileW(LPCWSTR filename,
417                                           CONST D3DXMACRO* defines,
418                                           LPD3DXINCLUDE include,
419                                           LPCSTR entrypoint,
420                                           LPCSTR profile,
421                                           DWORD flags,
422                                           LPD3DXBUFFER* shader,
423                                           LPD3DXBUFFER* error_messages,
424                                           LPD3DXCONSTANTTABLE* constant_table)
425 {
426     void *buffer;
427     DWORD len, filename_len;
428     HRESULT hr;
429     struct D3DXIncludeImpl includefromfile;
430     char *filename_a;
431
432     if (FAILED(map_view_of_file(filename, &buffer, &len)))
433         return D3DXERR_INVALIDDATA;
434
435     if (!include)
436     {
437         includefromfile.ID3DXInclude_iface.lpVtbl = &D3DXInclude_Vtbl;
438         include = &includefromfile.ID3DXInclude_iface;
439     }
440
441     filename_len = WideCharToMultiByte(CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL);
442     filename_a = HeapAlloc(GetProcessHeap(), 0, filename_len * sizeof(char));
443     if (!filename_a)
444     {
445         UnmapViewOfFile(buffer);
446         return E_OUTOFMEMORY;
447     }
448     WideCharToMultiByte(CP_ACP, 0, filename, -1, filename_a, filename_len, NULL, NULL);
449
450     hr = D3DCompile(buffer, len, filename_a, (const D3D_SHADER_MACRO *)defines,
451                     (ID3DInclude *)include, entrypoint, profile, flags, 0,
452                     (ID3DBlob **)shader, (ID3DBlob **)error_messages);
453
454     if (SUCCEEDED(hr) && constant_table)
455         hr = D3DXGetShaderConstantTable(ID3DXBuffer_GetBufferPointer(*shader),
456                                         constant_table);
457
458     HeapFree(GetProcessHeap(), 0, filename_a);
459     UnmapViewOfFile(buffer);
460     return hr;
461 }
462
463 HRESULT WINAPI D3DXCompileShaderFromResourceA(HMODULE module,
464                                               LPCSTR resource,
465                                               CONST D3DXMACRO* defines,
466                                               LPD3DXINCLUDE include,
467                                               LPCSTR entrypoint,
468                                               LPCSTR profile,
469                                               DWORD flags,
470                                               LPD3DXBUFFER* shader,
471                                               LPD3DXBUFFER* error_messages,
472                                               LPD3DXCONSTANTTABLE* constant_table)
473 {
474     HRSRC res;
475     LPCSTR buffer;
476     DWORD len;
477
478     if (!(res = FindResourceA(module, resource, (LPCSTR)RT_RCDATA)))
479         return D3DXERR_INVALIDDATA;
480     if (FAILED(load_resource_into_memory(module, res, (LPVOID *)&buffer, &len)))
481         return D3DXERR_INVALIDDATA;
482     return D3DXCompileShader(buffer, len, defines, include, entrypoint, profile,
483                              flags, shader, error_messages, constant_table);
484 }
485
486 HRESULT WINAPI D3DXCompileShaderFromResourceW(HMODULE module,
487                                               LPCWSTR resource,
488                                               CONST D3DXMACRO* defines,
489                                               LPD3DXINCLUDE include,
490                                               LPCSTR entrypoint,
491                                               LPCSTR profile,
492                                               DWORD flags,
493                                               LPD3DXBUFFER* shader,
494                                               LPD3DXBUFFER* error_messages,
495                                               LPD3DXCONSTANTTABLE* constant_table)
496 {
497     HRSRC res;
498     LPCSTR buffer;
499     DWORD len;
500
501     if (!(res = FindResourceW(module, resource, (LPCWSTR)RT_RCDATA)))
502         return D3DXERR_INVALIDDATA;
503     if (FAILED(load_resource_into_memory(module, res, (LPVOID *)&buffer, &len)))
504         return D3DXERR_INVALIDDATA;
505     return D3DXCompileShader(buffer, len, defines, include, entrypoint, profile,
506                              flags, shader, error_messages, constant_table);
507 }
508
509 HRESULT WINAPI D3DXPreprocessShader(LPCSTR data,
510                                     UINT data_len,
511                                     CONST D3DXMACRO* defines,
512                                     LPD3DXINCLUDE include,
513                                     LPD3DXBUFFER* shader,
514                                     LPD3DXBUFFER* error_messages)
515 {
516     TRACE("Forward to D3DPreprocess\n");
517     return D3DPreprocess(data, data_len, NULL,
518                          (const D3D_SHADER_MACRO *)defines, (ID3DInclude *)include,
519                          (ID3DBlob **)shader, (ID3DBlob **)error_messages);
520 }
521
522 HRESULT WINAPI D3DXPreprocessShaderFromFileA(LPCSTR filename,
523                                              CONST D3DXMACRO* defines,
524                                              LPD3DXINCLUDE include,
525                                              LPD3DXBUFFER* shader,
526                                              LPD3DXBUFFER* error_messages)
527 {
528     WCHAR *filename_w = NULL;
529     DWORD len;
530     HRESULT ret;
531
532     if (!filename) return D3DXERR_INVALIDDATA;
533
534     len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
535     filename_w = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
536     if (!filename_w) return E_OUTOFMEMORY;
537     MultiByteToWideChar(CP_ACP, 0, filename, -1, filename_w, len);
538
539     ret = D3DXPreprocessShaderFromFileW(filename_w, defines, include, shader, error_messages);
540
541     HeapFree(GetProcessHeap(), 0, filename_w);
542     return ret;
543 }
544
545 HRESULT WINAPI D3DXPreprocessShaderFromFileW(LPCWSTR filename,
546                                              CONST D3DXMACRO* defines,
547                                              LPD3DXINCLUDE include,
548                                              LPD3DXBUFFER* shader,
549                                              LPD3DXBUFFER* error_messages)
550 {
551     void *buffer;
552     DWORD len;
553     HRESULT hr;
554     struct D3DXIncludeImpl includefromfile;
555
556     if (FAILED(map_view_of_file(filename, &buffer, &len)))
557         return D3DXERR_INVALIDDATA;
558
559     if (!include)
560     {
561         includefromfile.ID3DXInclude_iface.lpVtbl = &D3DXInclude_Vtbl;
562         include = &includefromfile.ID3DXInclude_iface;
563     }
564
565     hr = D3DPreprocess(buffer, len, NULL,
566                        (const D3D_SHADER_MACRO *)defines,
567                        (ID3DInclude *) include,
568                        (ID3DBlob **)shader, (ID3DBlob **)error_messages);
569
570     UnmapViewOfFile(buffer);
571     return hr;
572 }
573
574 HRESULT WINAPI D3DXPreprocessShaderFromResourceA(HMODULE module,
575                                                  LPCSTR resource,
576                                                  CONST D3DXMACRO* defines,
577                                                  LPD3DXINCLUDE include,
578                                                  LPD3DXBUFFER* shader,
579                                                  LPD3DXBUFFER* error_messages)
580 {
581     HRSRC res;
582     const char *buffer;
583     DWORD len;
584
585     if (!(res = FindResourceA(module, resource, (LPCSTR)RT_RCDATA)))
586         return D3DXERR_INVALIDDATA;
587     if (FAILED(load_resource_into_memory(module, res, (LPVOID *)&buffer, &len)))
588         return D3DXERR_INVALIDDATA;
589     return D3DXPreprocessShader(buffer, len, defines, include,
590                                 shader, error_messages);
591 }
592
593 HRESULT WINAPI D3DXPreprocessShaderFromResourceW(HMODULE module,
594                                                  LPCWSTR resource,
595                                                  CONST D3DXMACRO* defines,
596                                                  LPD3DXINCLUDE include,
597                                                  LPD3DXBUFFER* shader,
598                                                  LPD3DXBUFFER* error_messages)
599 {
600     HRSRC res;
601     const char *buffer;
602     DWORD len;
603
604     if (!(res = FindResourceW(module, resource, (const WCHAR *)RT_RCDATA)))
605         return D3DXERR_INVALIDDATA;
606     if (FAILED(load_resource_into_memory(module, res, (void **)&buffer, &len)))
607         return D3DXERR_INVALIDDATA;
608     return D3DXPreprocessShader(buffer, len, defines, include,
609                                 shader, error_messages);
610
611 }
612
613 typedef struct ctab_constant {
614     D3DXCONSTANT_DESC desc;
615     struct ctab_constant *members;
616 } ctab_constant;
617
618 static const struct ID3DXConstantTableVtbl ID3DXConstantTable_Vtbl;
619
620 typedef struct ID3DXConstantTableImpl {
621     ID3DXConstantTable ID3DXConstantTable_iface;
622     LONG ref;
623     char *ctab;
624     DWORD size;
625     D3DXCONSTANTTABLE_DESC desc;
626     ctab_constant *constants;
627 } ID3DXConstantTableImpl;
628
629 static inline ID3DXConstantTableImpl *impl_from_ID3DXConstantTable(ID3DXConstantTable *iface)
630 {
631     return CONTAINING_RECORD(iface, ID3DXConstantTableImpl, ID3DXConstantTable_iface);
632 }
633
634 static inline int is_vertex_shader(DWORD version)
635 {
636     return (version & 0xFFFF0000) == 0xFFFE0000;
637 }
638
639 /*** IUnknown methods ***/
640 static HRESULT WINAPI ID3DXConstantTableImpl_QueryInterface(ID3DXConstantTable* iface, REFIID riid, void** ppvObject)
641 {
642     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
643
644     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
645
646     if (IsEqualGUID(riid, &IID_IUnknown) ||
647         IsEqualGUID(riid, &IID_ID3DXBuffer) ||
648         IsEqualGUID(riid, &IID_ID3DXConstantTable))
649     {
650         ID3DXConstantTable_AddRef(iface);
651         *ppvObject = This;
652         return S_OK;
653     }
654
655     WARN("Interface %s not found.\n", debugstr_guid(riid));
656
657     return E_NOINTERFACE;
658 }
659
660 static ULONG WINAPI ID3DXConstantTableImpl_AddRef(ID3DXConstantTable* iface)
661 {
662     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
663
664     TRACE("(%p)->(): AddRef from %d\n", This, This->ref);
665
666     return InterlockedIncrement(&This->ref);
667 }
668
669 static ULONG WINAPI ID3DXConstantTableImpl_Release(ID3DXConstantTable* iface)
670 {
671     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
672     ULONG ref = InterlockedDecrement(&This->ref);
673
674     TRACE("(%p)->(): Release from %d\n", This, ref + 1);
675
676     if (!ref)
677     {
678         HeapFree(GetProcessHeap(), 0, This->constants);
679         HeapFree(GetProcessHeap(), 0, This->ctab);
680         HeapFree(GetProcessHeap(), 0, This);
681     }
682
683     return ref;
684 }
685
686 /*** ID3DXBuffer methods ***/
687 static LPVOID WINAPI ID3DXConstantTableImpl_GetBufferPointer(ID3DXConstantTable* iface)
688 {
689     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
690
691     TRACE("(%p)->()\n", This);
692
693     return This->ctab;
694 }
695
696 static DWORD WINAPI ID3DXConstantTableImpl_GetBufferSize(ID3DXConstantTable* iface)
697 {
698     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
699
700     TRACE("(%p)->()\n", This);
701
702     return This->size;
703 }
704
705 /*** ID3DXConstantTable methods ***/
706 static HRESULT WINAPI ID3DXConstantTableImpl_GetDesc(ID3DXConstantTable* iface, D3DXCONSTANTTABLE_DESC *desc)
707 {
708     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
709
710     TRACE("(%p)->(%p)\n", This, desc);
711
712     if (!desc)
713         return D3DERR_INVALIDCALL;
714
715     memcpy(desc, &This->desc, sizeof(This->desc));
716
717     return D3D_OK;
718 }
719
720 static HRESULT WINAPI ID3DXConstantTableImpl_GetConstantDesc(ID3DXConstantTable* iface, D3DXHANDLE constant,
721                                                              D3DXCONSTANT_DESC *desc, UINT *count)
722 {
723     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
724     ctab_constant *constant_info;
725
726     TRACE("(%p)->(%p, %p, %p)\n", This, constant, desc, count);
727
728     if (!constant)
729         return D3DERR_INVALIDCALL;
730
731     /* Applications can pass the name of the constant in place of the handle */
732     if (!((UINT_PTR)constant >> 16))
733         constant_info = &This->constants[(UINT_PTR)constant - 1];
734     else
735     {
736         D3DXHANDLE c = ID3DXConstantTable_GetConstantByName(iface, NULL, constant);
737         if (!c)
738             return D3DERR_INVALIDCALL;
739
740         constant_info = &This->constants[(UINT_PTR)c - 1];
741     }
742
743     if (desc)
744         *desc = constant_info->desc;
745     if (count)
746         *count = 1;
747
748     return D3D_OK;
749 }
750
751 static UINT WINAPI ID3DXConstantTableImpl_GetSamplerIndex(ID3DXConstantTable *iface, D3DXHANDLE constant)
752 {
753     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
754     D3DXCONSTANT_DESC desc;
755     UINT count = 1;
756     HRESULT res;
757
758     TRACE("(%p)->(%p)\n", This, constant);
759
760     res = ID3DXConstantTable_GetConstantDesc(iface, constant, &desc, &count);
761     if (FAILED(res))
762         return (UINT)-1;
763
764     if (desc.RegisterSet != D3DXRS_SAMPLER)
765         return (UINT)-1;
766
767     return desc.RegisterIndex;
768 }
769
770 static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstant(ID3DXConstantTable* iface, D3DXHANDLE constant, UINT index)
771 {
772     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
773
774     TRACE("(%p)->(%p, %d)\n", This, constant, index);
775
776     if (constant)
777     {
778         FIXME("Only top level constants supported\n");
779         return NULL;
780     }
781
782     if (index >= This->desc.Constants)
783         return NULL;
784
785     return (D3DXHANDLE)(DWORD_PTR)(index + 1);
786 }
787
788 static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstantByName(ID3DXConstantTable* iface, D3DXHANDLE constant, LPCSTR name)
789 {
790     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
791     UINT i;
792
793     TRACE("(%p)->(%p, %s)\n", This, constant, name);
794
795     if (!name)
796         return NULL;
797
798     if (constant)
799     {
800         FIXME("Only top level constants supported\n");
801         return NULL;
802     }
803
804     for (i = 0; i < This->desc.Constants; i++)
805         if (!strcmp(This->constants[i].desc.Name, name))
806             return (D3DXHANDLE)(DWORD_PTR)(i + 1);
807
808     return NULL;
809 }
810
811 static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstantElement(ID3DXConstantTable* iface, D3DXHANDLE constant, UINT index)
812 {
813     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
814
815     FIXME("(%p)->(%p, %d): stub\n", This, constant, index);
816
817     return NULL;
818 }
819
820 static HRESULT set_float_array(ID3DXConstantTable *iface, LPDIRECT3DDEVICE9 device, D3DXHANDLE constant, const void *data,
821                                UINT count, D3DXPARAMETER_TYPE type)
822 {
823     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
824
825     D3DXCONSTANT_DESC desc;
826     HRESULT hr;
827     UINT i, desc_count = 1;
828     float row[4] = {0.0f, 0.0f, 0.0f, 0.0f};
829
830     hr = ID3DXConstantTable_GetConstantDesc(iface, constant, &desc, &desc_count);
831     if (FAILED(hr))
832     {
833         TRACE("ID3DXConstantTable_GetConstantDesc failed: %08x", hr);
834         return D3DERR_INVALIDCALL;
835     }
836
837     switch (desc.RegisterSet)
838     {
839         case D3DXRS_FLOAT4:
840             for (i = 0; i < count && i < desc.RegisterCount; i++)
841             {
842                 /* We need the for loop since each IDirect3DDevice9_Set*ShaderConstantF expects a float4 */
843                 switch(type)
844                 {
845                     case D3DXPT_FLOAT:
846                         row[0] = ((float *)data)[i];
847                         break;
848                     case D3DXPT_INT:
849                         row[0] = (float)((int *)data)[i];
850                         break;
851                     default:
852                         FIXME("Unhandled type passed to set_float_array\n");
853                         return D3DERR_INVALIDCALL;
854                 }
855                 if (is_vertex_shader(This->desc.Version))
856                     IDirect3DDevice9_SetVertexShaderConstantF(device, desc.RegisterIndex + i, row, 1);
857                 else
858                     IDirect3DDevice9_SetPixelShaderConstantF(device, desc.RegisterIndex + i, row, 1);
859             }
860             break;
861         default:
862             FIXME("Handle other register sets\n");
863             return E_NOTIMPL;
864     }
865
866     return D3D_OK;
867 }
868
869 static HRESULT WINAPI ID3DXConstantTableImpl_SetDefaults(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device)
870 {
871     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
872
873     FIXME("(%p)->(%p): stub\n", This, device);
874
875     return E_NOTIMPL;
876 }
877
878 static HRESULT WINAPI ID3DXConstantTableImpl_SetValue(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
879                                                       D3DXHANDLE constant, LPCVOID data, UINT bytes)
880 {
881     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
882
883     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, data, bytes);
884
885     return E_NOTIMPL;
886 }
887
888 static HRESULT WINAPI ID3DXConstantTableImpl_SetBool(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
889                                                      D3DXHANDLE constant, BOOL b)
890 {
891     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
892
893     FIXME("(%p)->(%p, %p, %d): stub\n", This, device, constant, b);
894
895     return E_NOTIMPL;
896 }
897
898 static HRESULT WINAPI ID3DXConstantTableImpl_SetBoolArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
899                                                           D3DXHANDLE constant, CONST BOOL* b, UINT count)
900 {
901     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
902
903     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, b, count);
904
905     return E_NOTIMPL;
906 }
907
908 static HRESULT WINAPI ID3DXConstantTableImpl_SetInt(ID3DXConstantTable *iface, LPDIRECT3DDEVICE9 device, D3DXHANDLE constant, INT n)
909 {
910     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
911
912     TRACE("(%p)->(%p, %p, %d)\n", This, device, constant, n);
913
914     return ID3DXConstantTable_SetIntArray(iface, device, constant, &n, 1);
915 }
916
917 static HRESULT WINAPI ID3DXConstantTableImpl_SetIntArray(ID3DXConstantTable *iface, LPDIRECT3DDEVICE9 device,
918                                                          D3DXHANDLE constant, CONST INT* n, UINT count)
919 {
920     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
921
922     TRACE("(%p)->(%p, %p, %p, %d)\n", This, device, constant, n, count);
923
924     return set_float_array(iface, device, constant, n, count, D3DXPT_INT);
925 }
926
927 static HRESULT WINAPI ID3DXConstantTableImpl_SetFloat(ID3DXConstantTable *iface, LPDIRECT3DDEVICE9 device,
928                                                       D3DXHANDLE constant, FLOAT f)
929 {
930     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
931
932     TRACE("(%p)->(%p, %p, %f)\n", This, device, constant, f);
933
934     return ID3DXConstantTable_SetFloatArray(iface, device, constant, &f, 1);
935 }
936
937 static HRESULT WINAPI ID3DXConstantTableImpl_SetFloatArray(ID3DXConstantTable *iface, LPDIRECT3DDEVICE9 device,
938                                                            D3DXHANDLE constant, CONST FLOAT *f, UINT count)
939 {
940     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
941
942     TRACE("(%p)->(%p, %p, %p, %d)\n", This, device, constant, f, count);
943
944     return set_float_array(iface, device, constant, f, count, D3DXPT_FLOAT);
945 }
946
947 static HRESULT WINAPI ID3DXConstantTableImpl_SetVector(ID3DXConstantTable *iface, LPDIRECT3DDEVICE9 device,
948                                                        D3DXHANDLE constant, CONST D3DXVECTOR4 *vector)
949 {
950     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
951
952     TRACE("(%p)->(%p, %p, %p)\n", This, device, constant, vector);
953
954     return ID3DXConstantTable_SetVectorArray(iface, device, constant, vector, 1);
955 }
956
957 static HRESULT WINAPI ID3DXConstantTableImpl_SetVectorArray(ID3DXConstantTable *iface, LPDIRECT3DDEVICE9 device,
958                                                             D3DXHANDLE constant, CONST D3DXVECTOR4 *vector, UINT count)
959 {
960     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
961
962     D3DXCONSTANT_DESC desc;
963     HRESULT hr;
964     UINT desc_count = 1;
965
966     TRACE("(%p)->(%p, %p, %p, %d)\n", This, device, constant, vector, count);
967
968     hr = ID3DXConstantTable_GetConstantDesc(iface, constant, &desc, &desc_count);
969     if (FAILED(hr))
970     {
971         TRACE("ID3DXConstantTable_GetConstantDesc failed: %08x", hr);
972         return D3DERR_INVALIDCALL;
973     }
974
975     switch (desc.RegisterSet)
976     {
977         case D3DXRS_FLOAT4:
978             if (is_vertex_shader(This->desc.Version))
979                 IDirect3DDevice9_SetVertexShaderConstantF(device, desc.RegisterIndex, (float *)vector,
980                         min(desc.RegisterCount, count));
981             else
982                 IDirect3DDevice9_SetPixelShaderConstantF(device, desc.RegisterIndex, (float *)vector,
983                         min(desc.RegisterCount, count));
984             break;
985         default:
986             FIXME("Handle other register sets\n");
987             return E_NOTIMPL;
988     }
989
990     return D3D_OK;
991 }
992
993 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrix(ID3DXConstantTable *iface, LPDIRECT3DDEVICE9 device,
994                                                        D3DXHANDLE constant, CONST D3DXMATRIX *matrix)
995 {
996     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
997
998     TRACE("(%p)->(%p, %p, %p)\n", This, device, constant, matrix);
999
1000     return ID3DXConstantTable_SetMatrixArray(iface, device, constant, matrix, 1);
1001 }
1002
1003 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixArray(ID3DXConstantTable *iface, LPDIRECT3DDEVICE9 device,
1004                                                             D3DXHANDLE constant, CONST D3DXMATRIX *matrix, UINT count)
1005 {
1006     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1007
1008     D3DXCONSTANT_DESC desc;
1009     HRESULT hr;
1010     UINT i, desc_count = 1;
1011     D3DXMATRIX temp;
1012
1013     TRACE("(%p)->(%p, %p, %p, %d)\n", This, device, constant, matrix, count);
1014
1015     hr = ID3DXConstantTable_GetConstantDesc(iface, constant, &desc, &desc_count);
1016     if (FAILED(hr))
1017     {
1018         TRACE("ID3DXConstantTable_GetConstantDesc failed: %08x", hr);
1019         return D3DERR_INVALIDCALL;
1020     }
1021
1022     switch (desc.RegisterSet)
1023     {
1024         case D3DXRS_FLOAT4:
1025             /* i * 4 + 3 is the last register we set. The conditional makes sure that we don't access
1026                registers we're not supposed to */
1027             for (i = 0; i < count && i * 4 + 3 < desc.RegisterCount; i++)
1028             {
1029                 if (desc.Class == D3DXPC_MATRIX_ROWS)
1030                     temp = matrix[i];
1031                 else
1032                     D3DXMatrixTranspose(&temp, &matrix[i]);
1033
1034                 if (is_vertex_shader(This->desc.Version))
1035                     IDirect3DDevice9_SetVertexShaderConstantF(device, desc.RegisterIndex + i * 4, &temp._11, 4);
1036                 else
1037                     IDirect3DDevice9_SetPixelShaderConstantF(device, desc.RegisterIndex + i * 4, &temp._11, 4);
1038             }
1039             break;
1040         default:
1041             FIXME("Handle other register sets\n");
1042             return E_NOTIMPL;
1043     }
1044
1045     return D3D_OK;
1046 }
1047
1048 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixPointerArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
1049                                                                    D3DXHANDLE constant, CONST D3DXMATRIX** matrix, UINT count)
1050 {
1051     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1052
1053     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, matrix, count);
1054
1055     return E_NOTIMPL;
1056 }
1057
1058 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixTranspose(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
1059                                                                 D3DXHANDLE constant, CONST D3DXMATRIX* matrix)
1060 {
1061     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1062
1063     FIXME("(%p)->(%p, %p, %p): stub\n", This, device, constant, matrix);
1064
1065     return E_NOTIMPL;
1066 }
1067
1068 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixTransposeArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
1069                                                                      D3DXHANDLE constant, CONST D3DXMATRIX* matrix, UINT count)
1070 {
1071     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1072
1073     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, matrix, count);
1074
1075     return E_NOTIMPL;
1076 }
1077
1078 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixTransposePointerArray(ID3DXConstantTable* iface, LPDIRECT3DDEVICE9 device,
1079                                                                             D3DXHANDLE constant, CONST D3DXMATRIX** matrix, UINT count)
1080 {
1081     ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1082
1083     FIXME("(%p)->(%p, %p, %p, %d): stub\n", This, device, constant, matrix, count);
1084
1085     return E_NOTIMPL;
1086 }
1087
1088 static const struct ID3DXConstantTableVtbl ID3DXConstantTable_Vtbl =
1089 {
1090     /*** IUnknown methods ***/
1091     ID3DXConstantTableImpl_QueryInterface,
1092     ID3DXConstantTableImpl_AddRef,
1093     ID3DXConstantTableImpl_Release,
1094     /*** ID3DXBuffer methods ***/
1095     ID3DXConstantTableImpl_GetBufferPointer,
1096     ID3DXConstantTableImpl_GetBufferSize,
1097     /*** ID3DXConstantTable methods ***/
1098     ID3DXConstantTableImpl_GetDesc,
1099     ID3DXConstantTableImpl_GetConstantDesc,
1100     ID3DXConstantTableImpl_GetSamplerIndex,
1101     ID3DXConstantTableImpl_GetConstant,
1102     ID3DXConstantTableImpl_GetConstantByName,
1103     ID3DXConstantTableImpl_GetConstantElement,
1104     ID3DXConstantTableImpl_SetDefaults,
1105     ID3DXConstantTableImpl_SetValue,
1106     ID3DXConstantTableImpl_SetBool,
1107     ID3DXConstantTableImpl_SetBoolArray,
1108     ID3DXConstantTableImpl_SetInt,
1109     ID3DXConstantTableImpl_SetIntArray,
1110     ID3DXConstantTableImpl_SetFloat,
1111     ID3DXConstantTableImpl_SetFloatArray,
1112     ID3DXConstantTableImpl_SetVector,
1113     ID3DXConstantTableImpl_SetVectorArray,
1114     ID3DXConstantTableImpl_SetMatrix,
1115     ID3DXConstantTableImpl_SetMatrixArray,
1116     ID3DXConstantTableImpl_SetMatrixPointerArray,
1117     ID3DXConstantTableImpl_SetMatrixTranspose,
1118     ID3DXConstantTableImpl_SetMatrixTransposeArray,
1119     ID3DXConstantTableImpl_SetMatrixTransposePointerArray
1120 };
1121
1122 static HRESULT parse_ctab_constant_type(const D3DXSHADER_TYPEINFO *type, ctab_constant *constant)
1123 {
1124     constant->desc.Class = type->Class;
1125     constant->desc.Type = type->Type;
1126     constant->desc.Rows = type->Rows;
1127     constant->desc.Columns = type->Columns;
1128     constant->desc.Elements = type->Elements;
1129     constant->desc.StructMembers = type->StructMembers;
1130
1131     TRACE("class = %d, type = %d, rows = %d, columns = %d, elements = %d, struct_members = %d\n",
1132           constant->desc.Class, constant->desc.Type, constant->desc.Elements,
1133           constant->desc.Rows, constant->desc.Columns, constant->desc.StructMembers);
1134
1135     if ((constant->desc.Class == D3DXPC_STRUCT) && constant->desc.StructMembers)
1136     {
1137         FIXME("Struct not supported yet\n");
1138         return E_NOTIMPL;
1139     }
1140
1141     return D3D_OK;
1142 }
1143
1144 HRESULT WINAPI D3DXGetShaderConstantTableEx(CONST DWORD* byte_code,
1145                                             DWORD flags,
1146                                             LPD3DXCONSTANTTABLE* constant_table)
1147 {
1148     ID3DXConstantTableImpl* object = NULL;
1149     HRESULT hr;
1150     LPCVOID data;
1151     UINT size;
1152     const D3DXSHADER_CONSTANTTABLE* ctab_header;
1153     D3DXSHADER_CONSTANTINFO* constant_info;
1154     DWORD i;
1155
1156     TRACE("(%p, %x, %p)\n", byte_code, flags, constant_table);
1157
1158     if (!byte_code || !constant_table)
1159         return D3DERR_INVALIDCALL;
1160
1161     hr = D3DXFindShaderComment(byte_code, MAKEFOURCC('C','T','A','B'), &data, &size);
1162     if (hr != D3D_OK)
1163         return D3DXERR_INVALIDDATA;
1164
1165     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ID3DXConstantTableImpl));
1166     if (!object)
1167     {
1168         ERR("Out of memory\n");
1169         return E_OUTOFMEMORY;
1170     }
1171
1172     object->ID3DXConstantTable_iface.lpVtbl = &ID3DXConstantTable_Vtbl;
1173     object->ref = 1;
1174
1175     if (size < sizeof(D3DXSHADER_CONSTANTTABLE))
1176     {
1177         hr = D3DXERR_INVALIDDATA;
1178         goto error;
1179     }
1180
1181     object->ctab = HeapAlloc(GetProcessHeap(), 0, size);
1182     if (!object->ctab)
1183     {
1184         ERR("Out of memory\n");
1185         hr = E_OUTOFMEMORY;
1186         goto error;
1187     }
1188     object->size = size;
1189     memcpy(object->ctab, data, object->size);
1190
1191     ctab_header = (const D3DXSHADER_CONSTANTTABLE*)data;
1192     if (ctab_header->Size != sizeof(D3DXSHADER_CONSTANTTABLE))
1193     {
1194         hr = D3DXERR_INVALIDDATA;
1195         goto error;
1196     }
1197     object->desc.Creator = ctab_header->Creator ? object->ctab + ctab_header->Creator : NULL;
1198     object->desc.Version = ctab_header->Version;
1199     object->desc.Constants = ctab_header->Constants;
1200     if (object->desc.Creator)
1201         TRACE("Creator = %s\n", object->desc.Creator);
1202     TRACE("Version = %x\n", object->desc.Version);
1203     TRACE("Constants = %d\n", ctab_header->Constants);
1204     if (ctab_header->Target)
1205         TRACE("Target = %s\n", object->ctab + ctab_header->Target);
1206
1207     if (object->desc.Constants > 65535)
1208     {
1209         FIXME("Too many constants (%u)\n", object->desc.Constants);
1210         hr = E_NOTIMPL;
1211         goto error;
1212     }
1213
1214     object->constants = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1215                                   sizeof(*object->constants) * object->desc.Constants);
1216     if (!object->constants)
1217     {
1218          ERR("Out of memory\n");
1219          hr = E_OUTOFMEMORY;
1220          goto error;
1221     }
1222
1223     constant_info = (LPD3DXSHADER_CONSTANTINFO)(object->ctab + ctab_header->ConstantInfo);
1224     for (i = 0; i < ctab_header->Constants; i++)
1225     {
1226         TRACE("name = %s\n", object->ctab + constant_info[i].Name);
1227         object->constants[i].desc.Name = object->ctab + constant_info[i].Name;
1228         object->constants[i].desc.RegisterSet = constant_info[i].RegisterSet;
1229         object->constants[i].desc.RegisterIndex = constant_info[i].RegisterIndex;
1230         object->constants[i].desc.RegisterCount = constant_info[i].RegisterCount;
1231         object->constants[i].desc.DefaultValue = object->ctab + constant_info[i].DefaultValue;
1232
1233         hr = parse_ctab_constant_type((LPD3DXSHADER_TYPEINFO)(object->ctab + constant_info[i].TypeInfo),
1234              &object->constants[i]);
1235         if (hr != D3D_OK)
1236             goto error;
1237
1238         if (constant_info[i].RegisterSet != D3DXRS_FLOAT4 &&
1239                 constant_info[i].RegisterSet != D3DXRS_SAMPLER)
1240             FIXME("Don't know how to calculate Bytes for constants of type %d\n",
1241                     constant_info[i].RegisterSet);
1242
1243         /*
1244          * D3DXRS_FLOAT4 and D3DXRS_SAMPLER have a base size of 4
1245          * (not taking into account dimensions and element count)
1246          */
1247         object->constants[i].desc.Bytes = 4;
1248
1249         /* Take into account dimensions and elements */
1250         object->constants[i].desc.Bytes *= object->constants[i].desc.Elements;
1251         object->constants[i].desc.Bytes *= object->constants[i].desc.Rows *
1252                 object->constants[i].desc.Columns;
1253     }
1254
1255     *constant_table = &object->ID3DXConstantTable_iface;
1256
1257     return D3D_OK;
1258
1259 error:
1260
1261     HeapFree(GetProcessHeap(), 0, object->constants);
1262     HeapFree(GetProcessHeap(), 0, object->ctab);
1263     HeapFree(GetProcessHeap(), 0, object);
1264
1265     return hr;
1266 }
1267
1268 HRESULT WINAPI D3DXGetShaderConstantTable(CONST DWORD* byte_code,
1269                                           LPD3DXCONSTANTTABLE* constant_table)
1270 {
1271     TRACE("(%p, %p): Forwarded to D3DXGetShaderConstantTableEx\n", byte_code, constant_table);
1272
1273     return D3DXGetShaderConstantTableEx(byte_code, 0, constant_table);
1274 }