msvcp90: Fixed strstreambuf_ctor_get implementation.
[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
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
26 #include "wine/debug.h"
27 #include "wine/unicode.h"
28 #include "windef.h"
29 #include "wingdi.h"
30 #include "objbase.h"
31 #include "d3dcommon.h"
32 #include "d3dcompiler.h"
33 #include "d3dx9_36_private.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
36
37 /* This function is not declared in the SDK headers yet */
38 HRESULT WINAPI D3DAssemble(LPCVOID data, SIZE_T datasize, LPCSTR filename,
39                            const D3D_SHADER_MACRO *defines, ID3DInclude *include,
40                            UINT flags,
41                            ID3DBlob **shader, ID3DBlob **error_messages);
42
43 LPCSTR WINAPI D3DXGetPixelShaderProfile(LPDIRECT3DDEVICE9 device)
44 {
45     D3DCAPS9 caps;
46
47     TRACE("device %p\n", device);
48
49     if (!device) return NULL;
50
51     IDirect3DDevice9_GetDeviceCaps(device,&caps);
52
53     switch (caps.PixelShaderVersion)
54     {
55     case D3DPS_VERSION(1, 1):
56         return "ps_1_1";
57
58     case D3DPS_VERSION(1, 2):
59         return "ps_1_2";
60
61     case D3DPS_VERSION(1, 3):
62         return "ps_1_3";
63
64     case D3DPS_VERSION(1, 4):
65         return "ps_1_4";
66
67     case D3DPS_VERSION(2, 0):
68         if ((caps.PS20Caps.NumTemps>=22)                          &&
69             (caps.PS20Caps.Caps&D3DPS20CAPS_ARBITRARYSWIZZLE)     &&
70             (caps.PS20Caps.Caps&D3DPS20CAPS_GRADIENTINSTRUCTIONS) &&
71             (caps.PS20Caps.Caps&D3DPS20CAPS_PREDICATION)          &&
72             (caps.PS20Caps.Caps&D3DPS20CAPS_NODEPENDENTREADLIMIT) &&
73             (caps.PS20Caps.Caps&D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT))
74         {
75             return "ps_2_a";
76         }
77         if ((caps.PS20Caps.NumTemps>=32)                          &&
78             (caps.PS20Caps.Caps&D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT))
79         {
80             return "ps_2_b";
81         }
82         return "ps_2_0";
83
84     case D3DPS_VERSION(3, 0):
85         return "ps_3_0";
86     }
87
88     return NULL;
89 }
90
91 UINT WINAPI D3DXGetShaderSize(const DWORD *byte_code)
92 {
93     const DWORD *ptr = byte_code;
94
95     TRACE("byte_code %p\n", byte_code);
96
97     if (!ptr) return 0;
98
99     /* Look for the END token, skipping the VERSION token */
100     while (*++ptr != D3DSIO_END)
101     {
102         /* Skip comments */
103         if ((*ptr & D3DSI_OPCODE_MASK) == D3DSIO_COMMENT)
104         {
105             ptr += ((*ptr & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT);
106         }
107     }
108     ++ptr;
109
110     /* Return the shader size in bytes */
111     return (ptr - byte_code) * sizeof(*ptr);
112 }
113
114 DWORD WINAPI D3DXGetShaderVersion(const DWORD *byte_code)
115 {
116     TRACE("byte_code %p\n", byte_code);
117
118     return byte_code ? *byte_code : 0;
119 }
120
121 LPCSTR WINAPI D3DXGetVertexShaderProfile(LPDIRECT3DDEVICE9 device)
122 {
123     D3DCAPS9 caps;
124
125     TRACE("device %p\n", device);
126
127     if (!device) return NULL;
128
129     IDirect3DDevice9_GetDeviceCaps(device,&caps);
130
131     switch (caps.VertexShaderVersion)
132     {
133     case D3DVS_VERSION(1, 1):
134         return "vs_1_1";
135     case D3DVS_VERSION(2, 0):
136         if ((caps.VS20Caps.NumTemps>=13) &&
137             (caps.VS20Caps.DynamicFlowControlDepth==24) &&
138             (caps.VS20Caps.Caps&D3DPS20CAPS_PREDICATION))
139         {
140             return "vs_2_a";
141         }
142         return "vs_2_0";
143     case D3DVS_VERSION(3, 0):
144         return "vs_3_0";
145     }
146
147     return NULL;
148 }
149
150 HRESULT WINAPI D3DXFindShaderComment(CONST DWORD* byte_code, DWORD fourcc, LPCVOID* data, UINT* size)
151 {
152     CONST DWORD *ptr = byte_code;
153
154     TRACE("(%p, %x, %p, %p)\n", byte_code, fourcc, data, size);
155
156     if (data) *data = NULL;
157     if (size) *size = 0;
158
159     if (!byte_code)
160         return D3DERR_INVALIDCALL;
161
162     while (*++ptr != D3DSIO_END)
163     {
164         /* Check if it is a comment */
165         if ((*ptr & D3DSI_OPCODE_MASK) == D3DSIO_COMMENT)
166         {
167             DWORD comment_size = (*ptr & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
168
169             /* Check if this is the comment we are looking for */
170             if (*(ptr + 1) == fourcc)
171             {
172                 UINT ctab_size = (comment_size - 1) * sizeof(DWORD);
173                 LPCVOID ctab_data = ptr + 2;
174                 if (size)
175                     *size = ctab_size;
176                 if (data)
177                     *data = ctab_data;
178                 TRACE("Returning comment data at %p with size %d\n", ctab_data, ctab_size);
179                 return D3D_OK;
180             }
181             ptr += comment_size;
182         }
183     }
184
185     return S_FALSE;
186 }
187
188 HRESULT WINAPI D3DXAssembleShader(LPCSTR data,
189                                   UINT data_len,
190                                   CONST D3DXMACRO* defines,
191                                   LPD3DXINCLUDE include,
192                                   DWORD flags,
193                                   LPD3DXBUFFER* shader,
194                                   LPD3DXBUFFER* error_messages)
195 {
196     /* Forward to d3dcompiler: the parameter types aren't really different,
197        the actual data types are equivalent */
198     HRESULT hr = D3DAssemble(data, data_len, NULL, (D3D_SHADER_MACRO *)defines,
199                              (ID3DInclude *)include, flags, (ID3DBlob **)shader,
200                              (ID3DBlob **)error_messages);
201
202     if(hr == E_FAIL) hr = D3DXERR_INVALIDDATA;
203     return hr;
204 }
205
206 /* D3DXInclude private implementation, used to implement
207    D3DXAssembleShaderFromFile from D3DXAssembleShader */
208 /* To be able to correctly resolve include search paths we have to store
209    the pathname of each include file. We store the pathname pointer right
210    before the file data. */
211 static HRESULT WINAPI d3dincludefromfile_open(ID3DXInclude *iface,
212                                               D3DXINCLUDE_TYPE include_type,
213                                               LPCSTR filename, LPCVOID parent_data,
214                                               LPCVOID *data, UINT *bytes) {
215     const char *p, *parent_name = "";
216     char *pathname = NULL;
217     char **buffer = NULL;
218     HANDLE file;
219     UINT size;
220
221     if(parent_data != NULL)
222         parent_name = *((const char **)parent_data - 1);
223
224     TRACE("Looking up for include file %s, parent %s\n", debugstr_a(filename), debugstr_a(parent_name));
225
226     if ((p = strrchr(parent_name, '\\')) || (p = strrchr(parent_name, '/'))) p++;
227     else p = parent_name;
228     pathname = HeapAlloc(GetProcessHeap(), 0, (p - parent_name) + strlen(filename) + 1);
229     if(!pathname)
230         return HRESULT_FROM_WIN32(GetLastError());
231
232     memcpy(pathname, parent_name, p - parent_name);
233     strcpy(pathname + (p - parent_name), filename);
234
235     file = CreateFileA(pathname, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
236     if(file == INVALID_HANDLE_VALUE)
237         goto error;
238
239     TRACE("Include file found at pathname = %s\n", debugstr_a(pathname));
240
241     size = GetFileSize(file, NULL);
242     if(size == INVALID_FILE_SIZE)
243         goto error;
244
245     buffer = HeapAlloc(GetProcessHeap(), 0, size + sizeof(char *));
246     if(!buffer)
247         goto error;
248     *buffer = pathname;
249     if(!ReadFile(file, buffer + 1, size, bytes, NULL))
250         goto error;
251
252     *data = buffer + 1;
253
254     CloseHandle(file);
255     return S_OK;
256
257 error:
258     CloseHandle(file);
259     HeapFree(GetProcessHeap(), 0, pathname);
260     HeapFree(GetProcessHeap(), 0, buffer);
261     return HRESULT_FROM_WIN32(GetLastError());
262 }
263
264 static HRESULT WINAPI d3dincludefromfile_close(ID3DXInclude *iface, LPCVOID data) {
265     HeapFree(GetProcessHeap(), 0, *((char **)data - 1));
266     HeapFree(GetProcessHeap(), 0, (char **)data - 1);
267     return S_OK;
268 }
269
270 static const struct ID3DXIncludeVtbl D3DXInclude_Vtbl = {
271     d3dincludefromfile_open,
272     d3dincludefromfile_close
273 };
274
275 struct D3DXIncludeImpl {
276     ID3DXInclude ID3DXInclude_iface;
277 };
278
279 HRESULT WINAPI D3DXAssembleShaderFromFileA(LPCSTR filename,
280                                            CONST D3DXMACRO* defines,
281                                            LPD3DXINCLUDE include,
282                                            DWORD flags,
283                                            LPD3DXBUFFER* shader,
284                                            LPD3DXBUFFER* error_messages)
285 {
286     LPWSTR filename_w = NULL;
287     DWORD len;
288     HRESULT ret;
289
290     if (!filename) return D3DXERR_INVALIDDATA;
291
292     len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
293     filename_w = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
294     if (!filename_w) return E_OUTOFMEMORY;
295     MultiByteToWideChar(CP_ACP, 0, filename, -1, filename_w, len);
296
297     ret = D3DXAssembleShaderFromFileW(filename_w, defines, include, flags, shader, error_messages);
298
299     HeapFree(GetProcessHeap(), 0, filename_w);
300     return ret;
301 }
302
303 HRESULT WINAPI D3DXAssembleShaderFromFileW(LPCWSTR filename,
304                                            CONST D3DXMACRO* defines,
305                                            LPD3DXINCLUDE include,
306                                            DWORD flags,
307                                            LPD3DXBUFFER* shader,
308                                            LPD3DXBUFFER* error_messages)
309 {
310     void *buffer;
311     DWORD len;
312     HRESULT hr;
313     struct D3DXIncludeImpl includefromfile;
314
315     if(FAILED(map_view_of_file(filename, &buffer, &len)))
316         return D3DXERR_INVALIDDATA;
317
318     if(!include)
319     {
320         includefromfile.ID3DXInclude_iface.lpVtbl = &D3DXInclude_Vtbl;
321         include = &includefromfile.ID3DXInclude_iface;
322     }
323
324     hr = D3DXAssembleShader(buffer, len, defines, include, flags,
325                             shader, error_messages);
326
327     UnmapViewOfFile(buffer);
328     return hr;
329 }
330
331 HRESULT WINAPI D3DXAssembleShaderFromResourceA(HMODULE module,
332                                                LPCSTR resource,
333                                                CONST D3DXMACRO* defines,
334                                                LPD3DXINCLUDE include,
335                                                DWORD flags,
336                                                LPD3DXBUFFER* shader,
337                                                LPD3DXBUFFER* error_messages)
338 {
339     HRSRC res;
340     LPCSTR buffer;
341     DWORD len;
342
343     if (!(res = FindResourceA(module, resource, (LPCSTR)RT_RCDATA)))
344         return D3DXERR_INVALIDDATA;
345     if (FAILED(load_resource_into_memory(module, res, (LPVOID *)&buffer, &len)))
346         return D3DXERR_INVALIDDATA;
347     return D3DXAssembleShader(buffer, len, defines, include, flags,
348                               shader, error_messages);
349 }
350
351 HRESULT WINAPI D3DXAssembleShaderFromResourceW(HMODULE module,
352                                                LPCWSTR resource,
353                                                CONST D3DXMACRO* defines,
354                                                LPD3DXINCLUDE include,
355                                                DWORD flags,
356                                                LPD3DXBUFFER* shader,
357                                                LPD3DXBUFFER* error_messages)
358 {
359     HRSRC res;
360     LPCSTR buffer;
361     DWORD len;
362
363     if (!(res = FindResourceW(module, resource, (LPCWSTR)RT_RCDATA)))
364         return D3DXERR_INVALIDDATA;
365     if (FAILED(load_resource_into_memory(module, res, (LPVOID *)&buffer, &len)))
366         return D3DXERR_INVALIDDATA;
367     return D3DXAssembleShader(buffer, len, defines, include, flags,
368                               shader, error_messages);
369 }
370
371 HRESULT WINAPI D3DXCompileShader(LPCSTR pSrcData,
372                                  UINT srcDataLen,
373                                  CONST D3DXMACRO* pDefines,
374                                  LPD3DXINCLUDE pInclude,
375                                  LPCSTR pFunctionName,
376                                  LPCSTR pProfile,
377                                  DWORD Flags,
378                                  LPD3DXBUFFER* ppShader,
379                                  LPD3DXBUFFER* ppErrorMsgs,
380                                  LPD3DXCONSTANTTABLE * ppConstantTable)
381 {
382     HRESULT hr = D3DCompile(pSrcData, srcDataLen, NULL,
383                             (D3D_SHADER_MACRO *)pDefines, (ID3DInclude *)pInclude,
384                             pFunctionName, pProfile, Flags, 0,
385                             (ID3DBlob **)ppShader, (ID3DBlob **)ppErrorMsgs);
386
387     if(SUCCEEDED(hr) && ppConstantTable)
388         return D3DXGetShaderConstantTable(ID3DXBuffer_GetBufferPointer(*ppShader),
389                                           ppConstantTable);
390     return hr;
391 }
392
393 HRESULT WINAPI D3DXCompileShaderFromFileA(LPCSTR filename,
394                                           CONST D3DXMACRO* defines,
395                                           LPD3DXINCLUDE include,
396                                           LPCSTR entrypoint,
397                                           LPCSTR profile,
398                                           DWORD flags,
399                                           LPD3DXBUFFER* shader,
400                                           LPD3DXBUFFER* error_messages,
401                                           LPD3DXCONSTANTTABLE* constant_table)
402 {
403     LPWSTR filename_w = NULL;
404     DWORD len;
405     HRESULT ret;
406
407     if (!filename) return D3DXERR_INVALIDDATA;
408
409     len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
410     filename_w = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
411     if (!filename_w) return E_OUTOFMEMORY;
412     MultiByteToWideChar(CP_ACP, 0, filename, -1, filename_w, len);
413
414     ret = D3DXCompileShaderFromFileW(filename_w, defines, include,
415                                      entrypoint, profile, flags,
416                                      shader, error_messages, constant_table);
417
418     HeapFree(GetProcessHeap(), 0, filename_w);
419     return ret;
420 }
421
422 HRESULT WINAPI D3DXCompileShaderFromFileW(LPCWSTR filename,
423                                           CONST D3DXMACRO* defines,
424                                           LPD3DXINCLUDE include,
425                                           LPCSTR entrypoint,
426                                           LPCSTR profile,
427                                           DWORD flags,
428                                           LPD3DXBUFFER* shader,
429                                           LPD3DXBUFFER* error_messages,
430                                           LPD3DXCONSTANTTABLE* constant_table)
431 {
432     void *buffer;
433     DWORD len, filename_len;
434     HRESULT hr;
435     struct D3DXIncludeImpl includefromfile;
436     char *filename_a;
437
438     if (FAILED(map_view_of_file(filename, &buffer, &len)))
439         return D3DXERR_INVALIDDATA;
440
441     if (!include)
442     {
443         includefromfile.ID3DXInclude_iface.lpVtbl = &D3DXInclude_Vtbl;
444         include = &includefromfile.ID3DXInclude_iface;
445     }
446
447     filename_len = WideCharToMultiByte(CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL);
448     filename_a = HeapAlloc(GetProcessHeap(), 0, filename_len * sizeof(char));
449     if (!filename_a)
450     {
451         UnmapViewOfFile(buffer);
452         return E_OUTOFMEMORY;
453     }
454     WideCharToMultiByte(CP_ACP, 0, filename, -1, filename_a, filename_len, NULL, NULL);
455
456     hr = D3DCompile(buffer, len, filename_a, (const D3D_SHADER_MACRO *)defines,
457                     (ID3DInclude *)include, entrypoint, profile, flags, 0,
458                     (ID3DBlob **)shader, (ID3DBlob **)error_messages);
459
460     if (SUCCEEDED(hr) && constant_table)
461         hr = D3DXGetShaderConstantTable(ID3DXBuffer_GetBufferPointer(*shader),
462                                         constant_table);
463
464     HeapFree(GetProcessHeap(), 0, filename_a);
465     UnmapViewOfFile(buffer);
466     return hr;
467 }
468
469 HRESULT WINAPI D3DXCompileShaderFromResourceA(HMODULE module,
470                                               LPCSTR resource,
471                                               CONST D3DXMACRO* defines,
472                                               LPD3DXINCLUDE include,
473                                               LPCSTR entrypoint,
474                                               LPCSTR profile,
475                                               DWORD flags,
476                                               LPD3DXBUFFER* shader,
477                                               LPD3DXBUFFER* error_messages,
478                                               LPD3DXCONSTANTTABLE* constant_table)
479 {
480     HRSRC res;
481     LPCSTR buffer;
482     DWORD len;
483
484     if (!(res = FindResourceA(module, resource, (LPCSTR)RT_RCDATA)))
485         return D3DXERR_INVALIDDATA;
486     if (FAILED(load_resource_into_memory(module, res, (LPVOID *)&buffer, &len)))
487         return D3DXERR_INVALIDDATA;
488     return D3DXCompileShader(buffer, len, defines, include, entrypoint, profile,
489                              flags, shader, error_messages, constant_table);
490 }
491
492 HRESULT WINAPI D3DXCompileShaderFromResourceW(HMODULE module,
493                                               LPCWSTR resource,
494                                               CONST D3DXMACRO* defines,
495                                               LPD3DXINCLUDE include,
496                                               LPCSTR entrypoint,
497                                               LPCSTR profile,
498                                               DWORD flags,
499                                               LPD3DXBUFFER* shader,
500                                               LPD3DXBUFFER* error_messages,
501                                               LPD3DXCONSTANTTABLE* constant_table)
502 {
503     HRSRC res;
504     LPCSTR buffer;
505     DWORD len;
506
507     if (!(res = FindResourceW(module, resource, (LPCWSTR)RT_RCDATA)))
508         return D3DXERR_INVALIDDATA;
509     if (FAILED(load_resource_into_memory(module, res, (LPVOID *)&buffer, &len)))
510         return D3DXERR_INVALIDDATA;
511     return D3DXCompileShader(buffer, len, defines, include, entrypoint, profile,
512                              flags, shader, error_messages, constant_table);
513 }
514
515 HRESULT WINAPI D3DXPreprocessShader(LPCSTR data,
516                                     UINT data_len,
517                                     CONST D3DXMACRO* defines,
518                                     LPD3DXINCLUDE include,
519                                     LPD3DXBUFFER* shader,
520                                     LPD3DXBUFFER* error_messages)
521 {
522     TRACE("Forward to D3DPreprocess\n");
523     return D3DPreprocess(data, data_len, NULL,
524                          (const D3D_SHADER_MACRO *)defines, (ID3DInclude *)include,
525                          (ID3DBlob **)shader, (ID3DBlob **)error_messages);
526 }
527
528 HRESULT WINAPI D3DXPreprocessShaderFromFileA(LPCSTR filename,
529                                              CONST D3DXMACRO* defines,
530                                              LPD3DXINCLUDE include,
531                                              LPD3DXBUFFER* shader,
532                                              LPD3DXBUFFER* error_messages)
533 {
534     WCHAR *filename_w = NULL;
535     DWORD len;
536     HRESULT ret;
537
538     if (!filename) return D3DXERR_INVALIDDATA;
539
540     len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
541     filename_w = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
542     if (!filename_w) return E_OUTOFMEMORY;
543     MultiByteToWideChar(CP_ACP, 0, filename, -1, filename_w, len);
544
545     ret = D3DXPreprocessShaderFromFileW(filename_w, defines, include, shader, error_messages);
546
547     HeapFree(GetProcessHeap(), 0, filename_w);
548     return ret;
549 }
550
551 HRESULT WINAPI D3DXPreprocessShaderFromFileW(LPCWSTR filename,
552                                              CONST D3DXMACRO* defines,
553                                              LPD3DXINCLUDE include,
554                                              LPD3DXBUFFER* shader,
555                                              LPD3DXBUFFER* error_messages)
556 {
557     void *buffer;
558     DWORD len;
559     HRESULT hr;
560     struct D3DXIncludeImpl includefromfile;
561
562     if (FAILED(map_view_of_file(filename, &buffer, &len)))
563         return D3DXERR_INVALIDDATA;
564
565     if (!include)
566     {
567         includefromfile.ID3DXInclude_iface.lpVtbl = &D3DXInclude_Vtbl;
568         include = &includefromfile.ID3DXInclude_iface;
569     }
570
571     hr = D3DPreprocess(buffer, len, NULL,
572                        (const D3D_SHADER_MACRO *)defines,
573                        (ID3DInclude *) include,
574                        (ID3DBlob **)shader, (ID3DBlob **)error_messages);
575
576     UnmapViewOfFile(buffer);
577     return hr;
578 }
579
580 HRESULT WINAPI D3DXPreprocessShaderFromResourceA(HMODULE module,
581                                                  LPCSTR resource,
582                                                  CONST D3DXMACRO* defines,
583                                                  LPD3DXINCLUDE include,
584                                                  LPD3DXBUFFER* shader,
585                                                  LPD3DXBUFFER* error_messages)
586 {
587     HRSRC res;
588     const char *buffer;
589     DWORD len;
590
591     if (!(res = FindResourceA(module, resource, (LPCSTR)RT_RCDATA)))
592         return D3DXERR_INVALIDDATA;
593     if (FAILED(load_resource_into_memory(module, res, (LPVOID *)&buffer, &len)))
594         return D3DXERR_INVALIDDATA;
595     return D3DXPreprocessShader(buffer, len, defines, include,
596                                 shader, error_messages);
597 }
598
599 HRESULT WINAPI D3DXPreprocessShaderFromResourceW(HMODULE module,
600                                                  LPCWSTR resource,
601                                                  CONST D3DXMACRO* defines,
602                                                  LPD3DXINCLUDE include,
603                                                  LPD3DXBUFFER* shader,
604                                                  LPD3DXBUFFER* error_messages)
605 {
606     HRSRC res;
607     const char *buffer;
608     DWORD len;
609
610     if (!(res = FindResourceW(module, resource, (const WCHAR *)RT_RCDATA)))
611         return D3DXERR_INVALIDDATA;
612     if (FAILED(load_resource_into_memory(module, res, (void **)&buffer, &len)))
613         return D3DXERR_INVALIDDATA;
614     return D3DXPreprocessShader(buffer, len, defines, include,
615                                 shader, error_messages);
616
617 }
618
619 struct ctab_constant {
620     D3DXCONSTANT_DESC desc;
621     struct ctab_constant *constants;
622 };
623
624 static const struct ID3DXConstantTableVtbl ID3DXConstantTable_Vtbl;
625
626 struct ID3DXConstantTableImpl {
627     ID3DXConstantTable ID3DXConstantTable_iface;
628     LONG ref;
629     char *ctab;
630     DWORD size;
631     D3DXCONSTANTTABLE_DESC desc;
632     struct ctab_constant *constants;
633 };
634
635 static void free_constant(struct ctab_constant *constant)
636 {
637     if (constant->constants)
638     {
639         UINT i, count = constant->desc.Elements > 1 ? constant->desc.Elements : constant->desc.StructMembers;
640
641         for (i = 0; i < count; ++i)
642         {
643             free_constant(&constant->constants[i]);
644         }
645         HeapFree(GetProcessHeap(), 0, constant->constants);
646     }
647 }
648
649 static void free_constant_table(struct ID3DXConstantTableImpl *table)
650 {
651     if (table->constants)
652     {
653         UINT i;
654
655         for (i = 0; i < table->desc.Constants; ++i)
656         {
657             free_constant(&table->constants[i]);
658         }
659         HeapFree(GetProcessHeap(), 0, table->constants);
660     }
661     HeapFree(GetProcessHeap(), 0, table->ctab);
662 }
663
664 static inline struct ID3DXConstantTableImpl *impl_from_ID3DXConstantTable(ID3DXConstantTable *iface)
665 {
666     return CONTAINING_RECORD(iface, struct ID3DXConstantTableImpl, ID3DXConstantTable_iface);
667 }
668
669 static inline int is_vertex_shader(DWORD version)
670 {
671     return (version & 0xFFFF0000) == 0xFFFE0000;
672 }
673
674 static inline struct ctab_constant *constant_from_handle(D3DXHANDLE handle)
675 {
676     return (struct ctab_constant *)handle;
677 }
678
679 static inline D3DXHANDLE handle_from_constant(struct ctab_constant *constant)
680 {
681     return (D3DXHANDLE)constant;
682 }
683
684 static struct ctab_constant *get_constant_by_name(struct ID3DXConstantTableImpl *, struct ctab_constant *, LPCSTR);
685
686 static struct ctab_constant *get_constant_element_by_name(struct ctab_constant *constant, LPCSTR name)
687 {
688     UINT element;
689     LPCSTR part;
690
691     TRACE("constant %p, name %s\n", constant, debugstr_a(name));
692
693     if (!name || !*name) return NULL;
694
695     element = atoi(name);
696     part = strchr(name, ']') + 1;
697
698     if (constant->desc.Elements > element)
699     {
700         struct ctab_constant *c = constant->constants ? &constant->constants[element] : constant;
701
702         switch (*part++)
703         {
704             case '.':
705                 return get_constant_by_name(NULL, c, part);
706
707             case '[':
708                 return get_constant_element_by_name(c, part);
709
710             case '\0':
711                 TRACE("Returning parameter %p\n", c);
712                 return c;
713
714             default:
715                 FIXME("Unhandled case \"%c\"\n", *--part);
716                 break;
717         }
718     }
719
720     TRACE("Constant not found\n");
721     return NULL;
722 }
723
724 static struct ctab_constant *get_constant_by_name(struct ID3DXConstantTableImpl *table,
725         struct ctab_constant *constant, LPCSTR name)
726 {
727     UINT i, count, length;
728     struct ctab_constant *handles;
729     LPCSTR part;
730
731     TRACE("table %p, constant %p, name %s\n", table, constant, debugstr_a(name));
732
733     if (!name || !*name) return NULL;
734
735     if (!constant)
736     {
737         count = table->desc.Constants;
738         handles = table->constants;
739     }
740     else
741     {
742         count = constant->desc.StructMembers;
743         handles = constant->constants;
744     }
745
746     length = strcspn(name, "[.");
747     part = name + length;
748
749     for (i = 0; i < count; i++)
750     {
751         if (strlen(handles[i].desc.Name) == length && !strncmp(handles[i].desc.Name, name, length))
752         {
753             switch (*part++)
754             {
755                 case '.':
756                     return get_constant_by_name(NULL, &handles[i], part);
757
758                 case '[':
759                     return get_constant_element_by_name(&handles[i], part);
760
761                 default:
762                     TRACE("Returning parameter %p\n", &handles[i]);
763                     return &handles[i];
764             }
765         }
766     }
767
768     TRACE("Constant not found\n");
769     return NULL;
770 }
771
772 static struct ctab_constant *is_valid_sub_constant(struct ctab_constant *parent, struct ctab_constant *constant)
773 {
774     UINT i, count;
775
776     /* all variable have at least elements = 1, but no elements */
777     if (!parent->constants) return NULL;
778
779     if (parent->desc.Elements > 1) count = parent->desc.Elements;
780     else count = parent->desc.StructMembers;
781
782     for (i = 0; i < count; ++i)
783     {
784         if (&parent->constants[i] == constant)
785             return constant;
786
787         if (is_valid_sub_constant(&parent->constants[i], constant))
788             return constant;
789     }
790
791     return NULL;
792 }
793
794 static inline struct ctab_constant *is_valid_constant(struct ID3DXConstantTableImpl *table, D3DXHANDLE handle)
795 {
796     struct ctab_constant *c = constant_from_handle(handle);
797     UINT i;
798
799     if (!c) return NULL;
800
801     for (i = 0; i < table->desc.Constants; ++i)
802     {
803         if (&table->constants[i] == c)
804             return c;
805
806         if (is_valid_sub_constant(&table->constants[i], c))
807             return c;
808     }
809
810     return NULL;
811 }
812
813 static inline struct ctab_constant *get_valid_constant(struct ID3DXConstantTableImpl *table, D3DXHANDLE handle)
814 {
815     struct ctab_constant *constant = is_valid_constant(table, handle);
816
817     if (!constant) constant = get_constant_by_name(table, NULL, handle);
818
819     return constant;
820 }
821
822 static inline void set_float_shader_constant(struct ID3DXConstantTableImpl *table, IDirect3DDevice9 *device,
823                                              UINT register_index, const FLOAT *data, UINT count)
824 {
825     if (is_vertex_shader(table->desc.Version))
826         IDirect3DDevice9_SetVertexShaderConstantF(device, register_index, data, count);
827     else
828         IDirect3DDevice9_SetPixelShaderConstantF(device, register_index, data, count);
829 }
830
831 /*** IUnknown methods ***/
832 static HRESULT WINAPI ID3DXConstantTableImpl_QueryInterface(ID3DXConstantTable *iface, REFIID riid, void **out)
833 {
834     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
835
836     if (IsEqualGUID(riid, &IID_IUnknown) ||
837         IsEqualGUID(riid, &IID_ID3DXBuffer) ||
838         IsEqualGUID(riid, &IID_ID3DXConstantTable))
839     {
840         ID3DXConstantTable_AddRef(iface);
841         *out = iface;
842         return S_OK;
843     }
844
845     WARN("Interface %s not found.\n", debugstr_guid(riid));
846
847     return E_NOINTERFACE;
848 }
849
850 static ULONG WINAPI ID3DXConstantTableImpl_AddRef(ID3DXConstantTable *iface)
851 {
852     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
853
854     TRACE("(%p)->(): AddRef from %d\n", This, This->ref);
855
856     return InterlockedIncrement(&This->ref);
857 }
858
859 static ULONG WINAPI ID3DXConstantTableImpl_Release(ID3DXConstantTable *iface)
860 {
861     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
862     ULONG ref = InterlockedDecrement(&This->ref);
863
864     TRACE("(%p)->(): Release from %d\n", This, ref + 1);
865
866     if (!ref)
867     {
868         free_constant_table(This);
869         HeapFree(GetProcessHeap(), 0, This);
870     }
871
872     return ref;
873 }
874
875 /*** ID3DXBuffer methods ***/
876 static LPVOID WINAPI ID3DXConstantTableImpl_GetBufferPointer(ID3DXConstantTable *iface)
877 {
878     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
879
880     TRACE("(%p)->()\n", This);
881
882     return This->ctab;
883 }
884
885 static DWORD WINAPI ID3DXConstantTableImpl_GetBufferSize(ID3DXConstantTable *iface)
886 {
887     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
888
889     TRACE("(%p)->()\n", This);
890
891     return This->size;
892 }
893
894 /*** ID3DXConstantTable methods ***/
895 static HRESULT WINAPI ID3DXConstantTableImpl_GetDesc(ID3DXConstantTable *iface, D3DXCONSTANTTABLE_DESC *desc)
896 {
897     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
898
899     TRACE("(%p)->(%p)\n", This, desc);
900
901     if (!desc)
902         return D3DERR_INVALIDCALL;
903
904     *desc = This->desc;
905
906     return D3D_OK;
907 }
908
909 static HRESULT WINAPI ID3DXConstantTableImpl_GetConstantDesc(ID3DXConstantTable *iface, D3DXHANDLE constant,
910                                                              D3DXCONSTANT_DESC *desc, UINT *count)
911 {
912     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
913     struct ctab_constant *c = get_valid_constant(This, constant);
914
915     TRACE("(%p)->(%p, %p, %p)\n", This, constant, desc, count);
916
917     if (!c)
918     {
919         WARN("Invalid argument specified\n");
920         return D3DERR_INVALIDCALL;
921     }
922
923     if (desc) *desc = c->desc;
924     if (count) *count = 1;
925
926     return D3D_OK;
927 }
928
929 static UINT WINAPI ID3DXConstantTableImpl_GetSamplerIndex(ID3DXConstantTable *iface, D3DXHANDLE constant)
930 {
931     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
932     struct ctab_constant *c = get_valid_constant(This, constant);
933
934     TRACE("(%p)->(%p)\n", This, constant);
935
936     if (!c || c->desc.RegisterSet != D3DXRS_SAMPLER)
937     {
938         WARN("Invalid argument specified\n");
939         return (UINT)-1;
940     }
941
942     TRACE("Returning RegisterIndex %u\n", c->desc.RegisterIndex);
943     return c->desc.RegisterIndex;
944 }
945
946 static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstant(ID3DXConstantTable *iface, D3DXHANDLE constant, UINT index)
947 {
948     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
949     struct ctab_constant *c;
950
951     TRACE("(%p)->(%p, %d)\n", This, constant, index);
952
953     if (constant)
954     {
955         c = get_valid_constant(This, constant);
956         if (c && index < c->desc.StructMembers)
957         {
958             c = &c->constants[index];
959             TRACE("Returning constant %p\n", c);
960             return handle_from_constant(c);
961         }
962     }
963     else
964     {
965         if (index < This->desc.Constants)
966         {
967             c = &This->constants[index];
968             TRACE("Returning constant %p\n", c);
969             return handle_from_constant(c);
970         }
971     }
972
973     WARN("Index out of range\n");
974     return NULL;
975 }
976
977 static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstantByName(ID3DXConstantTable *iface, D3DXHANDLE constant, LPCSTR name)
978 {
979     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
980     struct ctab_constant *c = get_valid_constant(This, constant);
981
982     TRACE("(%p)->(%p, %s)\n", This, constant, name);
983
984     c = get_constant_by_name(This, c, name);
985     TRACE("Returning constant %p\n", c);
986
987     return handle_from_constant(c);
988 }
989
990 static D3DXHANDLE WINAPI ID3DXConstantTableImpl_GetConstantElement(ID3DXConstantTable *iface, D3DXHANDLE constant, UINT index)
991 {
992     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
993     struct ctab_constant *c = get_valid_constant(This, constant);
994
995     TRACE("(%p)->(%p, %d)\n", This, constant, index);
996
997     if (c && index < c->desc.Elements)
998     {
999         if (c->desc.Elements > 1) c = &c->constants[index];
1000         TRACE("Returning constant %p\n", c);
1001         return handle_from_constant(c);
1002     }
1003
1004     WARN("Invalid argument specified\n");
1005     return NULL;
1006 }
1007
1008 static HRESULT set_scalar_array(ID3DXConstantTable *iface, IDirect3DDevice9 *device, D3DXHANDLE constant, const void *data,
1009                                UINT count, D3DXPARAMETER_TYPE type)
1010 {
1011     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1012     D3DXCONSTANT_DESC desc;
1013     HRESULT hr;
1014     UINT i, desc_count = 1;
1015     float row[4] = {0.0f, 0.0f, 0.0f, 0.0f};
1016
1017     hr = ID3DXConstantTable_GetConstantDesc(iface, constant, &desc, &desc_count);
1018     if (FAILED(hr))
1019     {
1020         TRACE("ID3DXConstantTable_GetConstantDesc failed: %08x\n", hr);
1021         return D3DERR_INVALIDCALL;
1022     }
1023
1024     if (desc.Class != D3DXPC_SCALAR)
1025         return D3D_OK;
1026
1027     switch (desc.RegisterSet)
1028     {
1029         case D3DXRS_FLOAT4:
1030             for (i = 0; i < min(count, desc.RegisterCount); i++)
1031             {
1032                 /* We need the for loop since each IDirect3DDevice9_Set*ShaderConstantF expects a float4 */
1033                 switch(type)
1034                 {
1035                     case D3DXPT_FLOAT:
1036                         row[0] = ((float *)data)[i];
1037                         break;
1038                     case D3DXPT_INT:
1039                         row[0] = (float)((int *)data)[i];
1040                         break;
1041                     case D3DXPT_BOOL:
1042                         row[0] = ((BOOL *)data)[i] ? 1.0f : 0.0f;
1043                         break;
1044                     default:
1045                         FIXME("Unhandled type %s\n", debug_d3dxparameter_type(type));
1046                         return D3DERR_INVALIDCALL;
1047                 }
1048                 set_float_shader_constant(This, device, desc.RegisterIndex + i, row, 1);
1049             }
1050             break;
1051         default:
1052             FIXME("Unhandled register set %s\n", debug_d3dxparameter_registerset(desc.RegisterSet));
1053             return E_NOTIMPL;
1054     }
1055
1056     return D3D_OK;
1057 }
1058
1059 static HRESULT set_vector_array(ID3DXConstantTable *iface, IDirect3DDevice9 *device, D3DXHANDLE constant, const void *data,
1060                                 UINT count, D3DXPARAMETER_TYPE type)
1061 {
1062     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1063     D3DXCONSTANT_DESC desc;
1064     HRESULT hr;
1065     UINT i, j, desc_count = 1;
1066     float vec[4] = {0.0f, 0.0f, 0.0f, 0.0f};
1067
1068     hr = ID3DXConstantTable_GetConstantDesc(iface, constant, &desc, &desc_count);
1069     if (FAILED(hr))
1070     {
1071         TRACE("ID3DXConstantTable_GetConstantDesc failed: %08x\n", hr);
1072         return D3DERR_INVALIDCALL;
1073     }
1074
1075     if (desc.Class == D3DXPC_MATRIX_ROWS || desc.Class == D3DXPC_MATRIX_COLUMNS)
1076         return D3D_OK;
1077
1078     switch (desc.RegisterSet)
1079     {
1080         case D3DXRS_FLOAT4:
1081             for (i = 0; i < min(count, desc.RegisterCount); i++)
1082             {
1083                 switch (type)
1084                 {
1085                     case D3DXPT_FLOAT:
1086                         memcpy(vec, ((float *)data) + i * desc.Columns, desc.Columns * sizeof(float));
1087                         break;
1088                     case D3DXPT_INT:
1089                         for (j = 0; j < desc.Columns; j++)
1090                             vec[j] = (float)((int *)data)[i * desc.Columns + j];
1091                         break;
1092                     case D3DXPT_BOOL:
1093                         for (j = 0; j < desc.Columns; j++)
1094                             vec[j] = ((BOOL *)data)[i * desc.Columns + j] ? 1.0f : 0.0f;
1095                         break;
1096                     default:
1097                         FIXME("Unhandled type %s\n", debug_d3dxparameter_type(type));
1098                         return D3DERR_INVALIDCALL;
1099                 }
1100
1101                 set_float_shader_constant(This, device, desc.RegisterIndex + i, vec, 1);
1102             }
1103             break;
1104         default:
1105             FIXME("Unhandled register set %s\n", debug_d3dxparameter_registerset(desc.RegisterSet));
1106             return E_NOTIMPL;
1107     }
1108
1109     return D3D_OK;
1110 }
1111
1112 static HRESULT set_float_matrix(FLOAT *matrix, const D3DXCONSTANT_DESC *desc,
1113                                 UINT row_offset, UINT column_offset, UINT rows, UINT columns,
1114                                 const void *data, D3DXPARAMETER_TYPE type, UINT src_columns)
1115 {
1116     UINT i, j;
1117
1118     switch (type)
1119     {
1120         case D3DXPT_FLOAT:
1121             for (i = 0; i < rows; i++)
1122             {
1123                 for (j = 0; j < columns; j++)
1124                     matrix[i * row_offset + j * column_offset] = ((FLOAT *)data)[i * src_columns + j];
1125             }
1126             break;
1127         case D3DXPT_INT:
1128             for (i = 0; i < rows; i++)
1129             {
1130                 for (j = 0; j < columns; j++)
1131                     matrix[i * row_offset + j * column_offset] = ((INT *)data)[i * src_columns + j];
1132             }
1133             break;
1134         default:
1135             FIXME("Unhandled type %s\n", debug_d3dxparameter_type(type));
1136             return D3DERR_INVALIDCALL;
1137     }
1138
1139     return D3D_OK;
1140 }
1141
1142 static HRESULT set_matrix_array(ID3DXConstantTable *iface, IDirect3DDevice9 *device, D3DXHANDLE constant, const void *data,
1143                                 UINT count, D3DXPARAMETER_CLASS class, D3DXPARAMETER_TYPE type, UINT rows, UINT columns)
1144 {
1145     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1146     struct ctab_constant *c = get_valid_constant(This, constant);
1147     D3DXCONSTANT_DESC *desc;
1148     UINT registers_per_matrix, num_rows, num_columns, i;
1149     UINT row_offset = 1, column_offset = 1;
1150     const DWORD *data_ptr;
1151     FLOAT matrix[16] = {0.0f, 0.0f, 0.0f, 0.0f,
1152                         0.0f, 0.0f, 0.0f, 0.0f,
1153                         0.0f, 0.0f, 0.0f, 0.0f,
1154                         0.0f, 0.0f, 0.0f, 0.0f};
1155
1156     if (!c)
1157     {
1158         WARN("Invalid argument specified\n");
1159         return D3DERR_INVALIDCALL;
1160     }
1161     desc = &c->desc;
1162
1163     if (desc->Class == D3DXPC_MATRIX_ROWS
1164         || desc->Class == D3DXPC_MATRIX_COLUMNS
1165         || desc->Class == D3DXPC_VECTOR
1166         || desc->Class == D3DXPC_SCALAR)
1167     {
1168         if (desc->Class == class) row_offset = 4;
1169         else column_offset = 4;
1170
1171         if (class == D3DXPC_MATRIX_ROWS)
1172         {
1173             if (desc->Class == D3DXPC_VECTOR) return D3D_OK;
1174
1175             num_rows = desc->Rows;
1176             num_columns = desc->Columns;
1177         }
1178         else
1179         {
1180             num_rows = desc->Columns;
1181             num_columns = desc->Rows;
1182         }
1183
1184         registers_per_matrix = (desc->Class == D3DXPC_MATRIX_COLUMNS) ? desc->Columns : desc->Rows;
1185     }
1186     else
1187     {
1188         FIXME("Unhandled variable class %s\n", debug_d3dxparameter_class(desc->Class));
1189         return E_NOTIMPL;
1190     }
1191
1192     switch (desc->RegisterSet)
1193     {
1194         case D3DXRS_FLOAT4:
1195             data_ptr = data;
1196             for (i = 0; i < count; i++)
1197             {
1198                 HRESULT hr;
1199
1200                 if (registers_per_matrix * (i + 1) > desc->RegisterCount)
1201                     break;
1202
1203                 hr = set_float_matrix(matrix, desc, row_offset, column_offset, num_rows, num_columns, data_ptr, type, columns);
1204                 if (FAILED(hr)) return hr;
1205
1206                 set_float_shader_constant(This, device, desc->RegisterIndex + i * registers_per_matrix, matrix, registers_per_matrix);
1207
1208                 data_ptr += rows * columns;
1209             }
1210             break;
1211         default:
1212             FIXME("Unhandled register set %s\n", debug_d3dxparameter_registerset(desc->RegisterSet));
1213             return E_NOTIMPL;
1214     }
1215
1216     return D3D_OK;
1217 }
1218
1219 static HRESULT set_matrix_pointer_array(ID3DXConstantTable *iface, IDirect3DDevice9 *device, D3DXHANDLE constant,
1220                                 const D3DXMATRIX **data, UINT count, D3DXPARAMETER_CLASS class)
1221 {
1222     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1223     D3DXCONSTANT_DESC desc;
1224     HRESULT hr;
1225     UINT registers_per_matrix;
1226     UINT i, desc_count = 1;
1227     UINT num_rows, num_columns;
1228     UINT row_offset, column_offset;
1229     FLOAT matrix[16] = {0.0f, 0.0f, 0.0f, 0.0f,
1230                         0.0f, 0.0f, 0.0f, 0.0f,
1231                         0.0f, 0.0f, 0.0f, 0.0f,
1232                         0.0f, 0.0f, 0.0f, 0.0f};
1233
1234     hr = ID3DXConstantTable_GetConstantDesc(iface, constant, &desc, &desc_count);
1235     if (FAILED(hr))
1236     {
1237         TRACE("ID3DXConstantTable_GetConstantDesc failed: %08x\n", hr);
1238         return D3DERR_INVALIDCALL;
1239     }
1240
1241     if (desc.Class == D3DXPC_MATRIX_ROWS || desc.Class == D3DXPC_MATRIX_COLUMNS)
1242     {
1243         if (desc.Class == class)
1244         {
1245             column_offset = 1;
1246             row_offset = 4;
1247         }
1248         else
1249         {
1250             column_offset = 4;
1251             row_offset = 1;
1252         }
1253
1254         if (class == D3DXPC_MATRIX_ROWS)
1255         {
1256             num_rows = desc.Rows;
1257             num_columns = desc.Columns;
1258         }
1259         else
1260         {
1261             num_rows = desc.Columns;
1262             num_columns = desc.Rows;
1263         }
1264
1265         registers_per_matrix = (desc.Class == D3DXPC_MATRIX_ROWS) ? desc.Rows : desc.Columns;
1266     }
1267     else if (desc.Class == D3DXPC_SCALAR)
1268     {
1269         registers_per_matrix = 1;
1270         column_offset = 1;
1271         row_offset = 1;
1272         num_rows = desc.Rows;
1273         num_columns = desc.Columns;
1274     }
1275     else if (desc.Class == D3DXPC_VECTOR)
1276     {
1277         registers_per_matrix = 1;
1278
1279         if (class == D3DXPC_MATRIX_ROWS)
1280         {
1281             column_offset = 1;
1282             row_offset = 4;
1283             num_rows = desc.Rows;
1284             num_columns = desc.Columns;
1285         }
1286         else
1287         {
1288             column_offset = 4;
1289             row_offset = 1;
1290             num_rows = desc.Columns;
1291             num_columns = desc.Rows;
1292         }
1293     }
1294     else
1295     {
1296         FIXME("Unhandled variable class %s\n", debug_d3dxparameter_class(desc.Class));
1297         return D3D_OK;
1298     }
1299
1300     switch (desc.RegisterSet)
1301     {
1302         case D3DXRS_FLOAT4:
1303             for (i = 0; i < count; i++)
1304             {
1305                 if (registers_per_matrix * (i + 1) > desc.RegisterCount)
1306                     break;
1307
1308                 hr = set_float_matrix(matrix, &desc, row_offset, column_offset, num_rows, num_columns, *data, D3DXPT_FLOAT, 4);
1309                 if (FAILED(hr)) return hr;
1310
1311                 set_float_shader_constant(This, device, desc.RegisterIndex + i * registers_per_matrix, matrix, registers_per_matrix);
1312
1313                 data++;
1314             }
1315             break;
1316         default:
1317             FIXME("Unhandled register set %s\n", debug_d3dxparameter_registerset(desc.RegisterSet));
1318             return E_NOTIMPL;
1319     }
1320
1321     return D3D_OK;
1322 }
1323
1324 static HRESULT WINAPI ID3DXConstantTableImpl_SetDefaults(ID3DXConstantTable *iface, LPDIRECT3DDEVICE9 device)
1325 {
1326     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1327     UINT i;
1328
1329     TRACE("(%p)->(%p)\n", This, device);
1330
1331     if (!device)
1332         return D3DERR_INVALIDCALL;
1333
1334     for (i = 0; i < This->desc.Constants; i++)
1335     {
1336         D3DXCONSTANT_DESC *desc = &This->constants[i].desc;
1337
1338         if (!desc->DefaultValue)
1339             continue;
1340
1341         set_float_shader_constant(This, device, desc->RegisterIndex, desc->DefaultValue, desc->RegisterCount);
1342     }
1343
1344     return D3D_OK;
1345 }
1346
1347 static HRESULT WINAPI ID3DXConstantTableImpl_SetValue(ID3DXConstantTable *iface, LPDIRECT3DDEVICE9 device,
1348                                                       D3DXHANDLE constant, LPCVOID data, UINT bytes)
1349 {
1350     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1351     HRESULT hr;
1352     UINT elements;
1353     UINT count = 1;
1354     D3DXCONSTANT_DESC desc;
1355
1356     TRACE("(%p)->(%p, %p, %p, %d)\n", This, device, constant, data, bytes);
1357
1358     if (!device || !constant || !data)
1359         return D3DERR_INVALIDCALL;
1360
1361     hr = ID3DXConstantTable_GetConstantDesc(iface, constant, &desc, &count);
1362     if (FAILED(hr))
1363         return hr;
1364
1365     elements = bytes / (desc.Bytes / desc.Elements);
1366
1367     switch (desc.Class)
1368     {
1369         case D3DXPC_SCALAR:
1370             return set_scalar_array(iface, device, constant, data, elements, desc.Type);
1371         case D3DXPC_VECTOR:
1372             return set_vector_array(iface, device, constant, data, elements, desc.Type);
1373         case D3DXPC_MATRIX_ROWS:
1374         case D3DXPC_MATRIX_COLUMNS:
1375             return set_matrix_array(iface, device, constant, data, elements,
1376                     D3DXPC_MATRIX_ROWS, desc.Type, desc.Rows, desc.Columns);
1377         default:
1378             FIXME("Unhandled parameter class %s\n", debug_d3dxparameter_class(desc.Class));
1379             return D3DERR_INVALIDCALL;
1380     }
1381 }
1382
1383 static HRESULT WINAPI ID3DXConstantTableImpl_SetBool(ID3DXConstantTable *iface, LPDIRECT3DDEVICE9 device,
1384                                                      D3DXHANDLE constant, BOOL b)
1385 {
1386     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1387
1388     TRACE("(%p)->(%p, %p, %d)\n", This, device, constant, b);
1389
1390     return set_scalar_array(iface, device, constant, &b, 1, D3DXPT_BOOL);
1391 }
1392
1393 static HRESULT WINAPI ID3DXConstantTableImpl_SetBoolArray(ID3DXConstantTable *iface, LPDIRECT3DDEVICE9 device,
1394                                                           D3DXHANDLE constant, CONST BOOL* b, UINT count)
1395 {
1396     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1397
1398     TRACE("(%p)->(%p, %p, %p, %d)\n", This, device, constant, b, count);
1399
1400     return set_scalar_array(iface, device, constant, b, count, D3DXPT_BOOL);
1401 }
1402
1403 static HRESULT WINAPI ID3DXConstantTableImpl_SetInt(ID3DXConstantTable *iface, LPDIRECT3DDEVICE9 device, D3DXHANDLE constant, INT n)
1404 {
1405     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1406
1407     TRACE("(%p)->(%p, %p, %d)\n", This, device, constant, n);
1408
1409     return set_scalar_array(iface, device, constant, &n, 1, D3DXPT_INT);
1410 }
1411
1412 static HRESULT WINAPI ID3DXConstantTableImpl_SetIntArray(ID3DXConstantTable *iface, LPDIRECT3DDEVICE9 device,
1413                                                          D3DXHANDLE constant, CONST INT* n, UINT count)
1414 {
1415     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1416
1417     TRACE("(%p)->(%p, %p, %p, %d)\n", This, device, constant, n, count);
1418
1419     return set_scalar_array(iface, device, constant, n, count, D3DXPT_INT);
1420 }
1421
1422 static HRESULT WINAPI ID3DXConstantTableImpl_SetFloat(ID3DXConstantTable *iface, LPDIRECT3DDEVICE9 device,
1423                                                       D3DXHANDLE constant, FLOAT f)
1424 {
1425     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1426
1427     TRACE("(%p)->(%p, %p, %f)\n", This, device, constant, f);
1428
1429     return set_scalar_array(iface, device, constant, &f, 1, D3DXPT_FLOAT);
1430 }
1431
1432 static HRESULT WINAPI ID3DXConstantTableImpl_SetFloatArray(ID3DXConstantTable *iface, LPDIRECT3DDEVICE9 device,
1433                                                            D3DXHANDLE constant, CONST FLOAT *f, UINT count)
1434 {
1435     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1436
1437     TRACE("(%p)->(%p, %p, %p, %d)\n", This, device, constant, f, count);
1438
1439     return set_scalar_array(iface, device, constant, f, count, D3DXPT_FLOAT);
1440 }
1441
1442 static HRESULT WINAPI ID3DXConstantTableImpl_SetVector(ID3DXConstantTable *iface, LPDIRECT3DDEVICE9 device,
1443                                                        D3DXHANDLE constant, CONST D3DXVECTOR4 *vector)
1444 {
1445     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1446
1447     TRACE("(%p)->(%p, %p, %p)\n", This, device, constant, vector);
1448
1449     return set_vector_array(iface, device, constant, vector, 1, D3DXPT_FLOAT);
1450 }
1451
1452 static HRESULT WINAPI ID3DXConstantTableImpl_SetVectorArray(ID3DXConstantTable *iface, LPDIRECT3DDEVICE9 device,
1453                                                             D3DXHANDLE constant, CONST D3DXVECTOR4 *vector, UINT count)
1454 {
1455     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1456
1457     TRACE("(%p)->(%p, %p, %p, %d)\n", This, device, constant, vector, count);
1458
1459     return set_vector_array(iface, device, constant, vector, count, D3DXPT_FLOAT);
1460 }
1461
1462 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrix(ID3DXConstantTable *iface, LPDIRECT3DDEVICE9 device,
1463                                                        D3DXHANDLE constant, CONST D3DXMATRIX *matrix)
1464 {
1465     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1466
1467     TRACE("(%p)->(%p, %p, %p)\n", This, device, constant, matrix);
1468
1469     return set_matrix_array(iface, device, constant, matrix, 1, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 4, 4);
1470 }
1471
1472 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixArray(ID3DXConstantTable *iface, LPDIRECT3DDEVICE9 device,
1473                                                             D3DXHANDLE constant, CONST D3DXMATRIX *matrix, UINT count)
1474 {
1475     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1476
1477     TRACE("(%p)->(%p, %p, %p, %d)\n", This, device, constant, matrix, count);
1478
1479     return set_matrix_array(iface, device, constant, matrix, count, D3DXPC_MATRIX_ROWS, D3DXPT_FLOAT, 4, 4);
1480 }
1481
1482 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixPointerArray(ID3DXConstantTable *iface, LPDIRECT3DDEVICE9 device,
1483                                                                    D3DXHANDLE constant, CONST D3DXMATRIX **matrix, UINT count)
1484 {
1485     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1486
1487     TRACE("(%p)->(%p, %p, %p, %d)\n", This, device, constant, matrix, count);
1488
1489     return set_matrix_pointer_array(iface, device, constant, matrix, count, D3DXPC_MATRIX_ROWS);
1490 }
1491
1492 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixTranspose(ID3DXConstantTable *iface, LPDIRECT3DDEVICE9 device,
1493                                                                 D3DXHANDLE constant, CONST D3DXMATRIX *matrix)
1494 {
1495     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1496
1497     TRACE("(%p)->(%p, %p, %p)\n", This, device, constant, matrix);
1498
1499     return set_matrix_array(iface, device, constant, matrix, 1, D3DXPC_MATRIX_COLUMNS, D3DXPT_FLOAT, 4, 4);
1500 }
1501
1502 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixTransposeArray(ID3DXConstantTable *iface, LPDIRECT3DDEVICE9 device,
1503                                                                      D3DXHANDLE constant, CONST D3DXMATRIX *matrix, UINT count)
1504 {
1505     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1506
1507     TRACE("(%p)->(%p, %p, %p, %d)\n", This, device, constant, matrix, count);
1508
1509     return set_matrix_array(iface, device, constant, matrix, count, D3DXPC_MATRIX_COLUMNS, D3DXPT_FLOAT, 4, 4);
1510 }
1511
1512 static HRESULT WINAPI ID3DXConstantTableImpl_SetMatrixTransposePointerArray(ID3DXConstantTable *iface, LPDIRECT3DDEVICE9 device,
1513                                                                             D3DXHANDLE constant, CONST D3DXMATRIX **matrix, UINT count)
1514 {
1515     struct ID3DXConstantTableImpl *This = impl_from_ID3DXConstantTable(iface);
1516
1517     TRACE("(%p)->(%p, %p, %p, %d)\n", This, device, constant, matrix, count);
1518
1519     return set_matrix_pointer_array(iface, device, constant, matrix, count, D3DXPC_MATRIX_COLUMNS);
1520 }
1521
1522 static const struct ID3DXConstantTableVtbl ID3DXConstantTable_Vtbl =
1523 {
1524     /*** IUnknown methods ***/
1525     ID3DXConstantTableImpl_QueryInterface,
1526     ID3DXConstantTableImpl_AddRef,
1527     ID3DXConstantTableImpl_Release,
1528     /*** ID3DXBuffer methods ***/
1529     ID3DXConstantTableImpl_GetBufferPointer,
1530     ID3DXConstantTableImpl_GetBufferSize,
1531     /*** ID3DXConstantTable methods ***/
1532     ID3DXConstantTableImpl_GetDesc,
1533     ID3DXConstantTableImpl_GetConstantDesc,
1534     ID3DXConstantTableImpl_GetSamplerIndex,
1535     ID3DXConstantTableImpl_GetConstant,
1536     ID3DXConstantTableImpl_GetConstantByName,
1537     ID3DXConstantTableImpl_GetConstantElement,
1538     ID3DXConstantTableImpl_SetDefaults,
1539     ID3DXConstantTableImpl_SetValue,
1540     ID3DXConstantTableImpl_SetBool,
1541     ID3DXConstantTableImpl_SetBoolArray,
1542     ID3DXConstantTableImpl_SetInt,
1543     ID3DXConstantTableImpl_SetIntArray,
1544     ID3DXConstantTableImpl_SetFloat,
1545     ID3DXConstantTableImpl_SetFloatArray,
1546     ID3DXConstantTableImpl_SetVector,
1547     ID3DXConstantTableImpl_SetVectorArray,
1548     ID3DXConstantTableImpl_SetMatrix,
1549     ID3DXConstantTableImpl_SetMatrixArray,
1550     ID3DXConstantTableImpl_SetMatrixPointerArray,
1551     ID3DXConstantTableImpl_SetMatrixTranspose,
1552     ID3DXConstantTableImpl_SetMatrixTransposeArray,
1553     ID3DXConstantTableImpl_SetMatrixTransposePointerArray
1554 };
1555
1556 static HRESULT parse_ctab_constant_type(const char *ctab, DWORD typeoffset, struct ctab_constant *constant,
1557         BOOL is_element, WORD index, WORD max, DWORD *offset, DWORD nameoffset, UINT regset)
1558 {
1559     const D3DXSHADER_TYPEINFO *type = (LPD3DXSHADER_TYPEINFO)(ctab + typeoffset);
1560     const D3DXSHADER_STRUCTMEMBERINFO *memberinfo = NULL;
1561     HRESULT hr = D3D_OK;
1562     UINT i, count = 0;
1563     WORD size = 0;
1564
1565     constant->desc.DefaultValue = offset ? ctab + *offset : NULL;
1566     constant->desc.Class = type->Class;
1567     constant->desc.Type = type->Type;
1568     constant->desc.Rows = type->Rows;
1569     constant->desc.Columns = type->Columns;
1570     constant->desc.Elements = is_element ? 1 : type->Elements;
1571     constant->desc.StructMembers = type->StructMembers;
1572     constant->desc.Name = ctab + nameoffset;
1573     constant->desc.RegisterSet = regset;
1574     constant->desc.RegisterIndex = index;
1575
1576     TRACE("name %s, elements %u, index %u, defaultvalue %p, regset %s\n", constant->desc.Name,
1577             constant->desc.Elements, index, constant->desc.DefaultValue,
1578             debug_d3dxparameter_registerset(regset));
1579     TRACE("class %s, type %s, rows %d, columns %d, elements %d, struct_members %d\n",
1580             debug_d3dxparameter_class(type->Class), debug_d3dxparameter_type(type->Type),
1581             type->Rows, type->Columns, type->Elements, type->StructMembers);
1582
1583     if (type->Elements > 1 && !is_element)
1584     {
1585         count = type->Elements;
1586     }
1587     else if ((type->Class == D3DXPC_STRUCT) && type->StructMembers)
1588     {
1589         memberinfo = (D3DXSHADER_STRUCTMEMBERINFO*)(ctab + type->StructMemberInfo);
1590         count = type->StructMembers;
1591     }
1592
1593     if (count)
1594     {
1595         constant->constants = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*constant->constants) * count);
1596         if (!constant->constants)
1597         {
1598              ERR("Out of memory\n");
1599              hr = E_OUTOFMEMORY;
1600              goto error;
1601         }
1602
1603         for (i = 0; i < count; ++i)
1604         {
1605             hr = parse_ctab_constant_type(ctab, memberinfo ? memberinfo[i].TypeInfo : typeoffset,
1606                     &constant->constants[i], memberinfo == NULL, index + size, max, offset,
1607                     memberinfo ? memberinfo[i].Name : nameoffset, regset);
1608             if (hr != D3D_OK)
1609                 goto error;
1610
1611             size += constant->constants[i].desc.RegisterCount;
1612         }
1613     }
1614     else
1615     {
1616         WORD offsetdiff = 0;
1617
1618         switch (type->Class)
1619         {
1620             case D3DXPC_SCALAR:
1621             case D3DXPC_VECTOR:
1622                 offsetdiff = 1;
1623                 size = 1;
1624                 break;
1625
1626             case D3DXPC_MATRIX_ROWS:
1627                 size = is_element ? type->Rows : max(type->Rows, type->Columns);
1628                 offsetdiff = type->Rows;
1629                 break;
1630
1631             case D3DXPC_MATRIX_COLUMNS:
1632                 size = type->Columns;
1633                 offsetdiff = type->Columns;
1634                 break;
1635
1636             case D3DXPC_OBJECT:
1637                 size = 1;
1638                 break;
1639
1640             default:
1641                 FIXME("Unhandled type class %s\n", debug_d3dxparameter_class(type->Class));
1642                 break;
1643         }
1644
1645         /* offset in bytes => offsetdiff * components(4) * sizeof(DWORD) */
1646         if (offset) *offset += offsetdiff * 4 * 4;
1647
1648         /* int and bool registerset have different sizes */
1649         if (regset == D3DXRS_INT4 || regset == D3DXRS_BOOL)
1650         {
1651             switch (type->Class)
1652             {
1653                 case D3DXPC_SCALAR:
1654                 case D3DXPC_VECTOR:
1655                     size = type->Columns;
1656                     break;
1657
1658                 case D3DXPC_MATRIX_ROWS:
1659                 case D3DXPC_MATRIX_COLUMNS:
1660                     size = 4 * type->Columns;
1661                     break;
1662
1663                 default:
1664                     FIXME("Unhandled type class %s\n", debug_d3dxparameter_class(type->Class));
1665                     break;
1666             }
1667         }
1668     }
1669
1670     constant->desc.RegisterCount = max(0, min(max - index, size));
1671     constant->desc.Bytes = 4 * constant->desc.Elements * type->Rows * type->Columns;
1672
1673     return D3D_OK;
1674
1675 error:
1676     if (constant->constants)
1677     {
1678         for (i = 0; i < count; ++i)
1679         {
1680             free_constant(&constant->constants[i]);
1681         }
1682         HeapFree(GetProcessHeap(), 0, constant->constants);
1683         constant->constants = NULL;
1684     }
1685
1686     return hr;
1687 }
1688
1689 HRESULT WINAPI D3DXGetShaderConstantTableEx(CONST DWORD *byte_code,
1690                                             DWORD flags,
1691                                             LPD3DXCONSTANTTABLE *constant_table)
1692 {
1693     struct ID3DXConstantTableImpl *object = NULL;
1694     HRESULT hr;
1695     LPCVOID data;
1696     UINT size;
1697     const D3DXSHADER_CONSTANTTABLE* ctab_header;
1698     D3DXSHADER_CONSTANTINFO* constant_info;
1699     DWORD i;
1700
1701     TRACE("(%p, %x, %p)\n", byte_code, flags, constant_table);
1702
1703     if (!byte_code || !constant_table)
1704     {
1705         WARN("Invalid argument specified.\n");
1706         return D3DERR_INVALIDCALL;
1707     }
1708
1709     if (flags) FIXME("Flags (%#x) are not handled, yet!\n", flags);
1710
1711     hr = D3DXFindShaderComment(byte_code, MAKEFOURCC('C','T','A','B'), &data, &size);
1712     if (hr != D3D_OK)
1713     {
1714         WARN("CTAB not found.\n");
1715         return D3DXERR_INVALIDDATA;
1716     }
1717
1718     if (size < sizeof(D3DXSHADER_CONSTANTTABLE))
1719     {
1720         WARN("Invalid CTAB size.\n");
1721         return D3DXERR_INVALIDDATA;
1722     }
1723
1724     ctab_header = (const D3DXSHADER_CONSTANTTABLE *)data;
1725     if (ctab_header->Size != sizeof(D3DXSHADER_CONSTANTTABLE))
1726     {
1727         WARN("Invalid D3DXSHADER_CONSTANTTABLE size.\n");
1728         return D3DXERR_INVALIDDATA;
1729     }
1730
1731     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1732     if (!object)
1733     {
1734         ERR("Out of memory\n");
1735         return E_OUTOFMEMORY;
1736     }
1737
1738     object->ID3DXConstantTable_iface.lpVtbl = &ID3DXConstantTable_Vtbl;
1739     object->ref = 1;
1740
1741     object->ctab = HeapAlloc(GetProcessHeap(), 0, size);
1742     if (!object->ctab)
1743     {
1744         ERR("Out of memory\n");
1745         HeapFree(GetProcessHeap(), 0, object);
1746         return E_OUTOFMEMORY;
1747     }
1748     object->size = size;
1749     memcpy(object->ctab, data, object->size);
1750
1751     object->desc.Creator = ctab_header->Creator ? object->ctab + ctab_header->Creator : NULL;
1752     object->desc.Version = ctab_header->Version;
1753     object->desc.Constants = ctab_header->Constants;
1754     TRACE("Creator %s, Version %x, Constants %u, Target %s\n",
1755             debugstr_a(object->desc.Creator), object->desc.Version, object->desc.Constants,
1756             debugstr_a(ctab_header->Target ? object->ctab + ctab_header->Target : NULL));
1757
1758     object->constants = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1759                                   sizeof(*object->constants) * object->desc.Constants);
1760     if (!object->constants)
1761     {
1762          ERR("Out of memory\n");
1763          hr = E_OUTOFMEMORY;
1764          goto error;
1765     }
1766
1767     constant_info = (LPD3DXSHADER_CONSTANTINFO)(object->ctab + ctab_header->ConstantInfo);
1768     for (i = 0; i < ctab_header->Constants; i++)
1769     {
1770         DWORD offset = constant_info[i].DefaultValue;
1771
1772         hr = parse_ctab_constant_type(object->ctab, constant_info[i].TypeInfo,
1773                 &object->constants[i], FALSE, constant_info[i].RegisterIndex,
1774                 constant_info[i].RegisterIndex + constant_info[i].RegisterCount,
1775                 offset ? &offset : NULL, constant_info[i].Name, constant_info[i].RegisterSet);
1776         if (hr != D3D_OK)
1777             goto error;
1778     }
1779
1780     *constant_table = &object->ID3DXConstantTable_iface;
1781
1782     return D3D_OK;
1783
1784 error:
1785     free_constant_table(object);
1786     HeapFree(GetProcessHeap(), 0, object);
1787
1788     return hr;
1789 }
1790
1791 HRESULT WINAPI D3DXGetShaderConstantTable(CONST DWORD* byte_code,
1792                                           LPD3DXCONSTANTTABLE* constant_table)
1793 {
1794     TRACE("(%p, %p): Forwarded to D3DXGetShaderConstantTableEx\n", byte_code, constant_table);
1795
1796     return D3DXGetShaderConstantTableEx(byte_code, 0, constant_table);
1797 }
1798
1799 HRESULT WINAPI D3DXGetShaderSamplers(CONST DWORD *byte_code, LPCSTR *samplers, UINT *count)
1800 {
1801     HRESULT hr;
1802     UINT i, sampler_count = 0;
1803     UINT size;
1804     LPCSTR data;
1805     const D3DXSHADER_CONSTANTTABLE *ctab_header;
1806     const D3DXSHADER_CONSTANTINFO *constant_info;
1807
1808     TRACE("byte_code %p, samplers %p, count %p\n", byte_code, samplers, count);
1809
1810     if (count) *count = 0;
1811
1812     hr = D3DXFindShaderComment(byte_code, MAKEFOURCC('C','T','A','B'), (LPCVOID *)&data, &size);
1813     if (hr != D3D_OK) return D3D_OK;
1814
1815     if (size < sizeof(D3DXSHADER_CONSTANTTABLE)) return D3D_OK;
1816
1817     ctab_header = (const D3DXSHADER_CONSTANTTABLE *)data;
1818     if (ctab_header->Size != sizeof(*ctab_header)) return D3D_OK;
1819
1820     constant_info = (D3DXSHADER_CONSTANTINFO *)(data + ctab_header->ConstantInfo);
1821     for (i = 0; i < ctab_header->Constants; i++)
1822     {
1823         const D3DXSHADER_TYPEINFO *type;
1824
1825         TRACE("name = %s\n", data + constant_info[i].Name);
1826
1827         type = (D3DXSHADER_TYPEINFO *)(data + constant_info[i].TypeInfo);
1828
1829         if (type->Type == D3DXPT_SAMPLER
1830                 || type->Type == D3DXPT_SAMPLER1D
1831                 || type->Type == D3DXPT_SAMPLER2D
1832                 || type->Type == D3DXPT_SAMPLER3D
1833                 || type->Type == D3DXPT_SAMPLERCUBE)
1834         {
1835             if (samplers) samplers[sampler_count] = data + constant_info[i].Name;
1836
1837             ++sampler_count;
1838         }
1839     }
1840
1841     TRACE("Found %u samplers\n", sampler_count);
1842
1843     if (count) *count = sampler_count;
1844
1845     return D3D_OK;
1846 }