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