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