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