Implemented NtQueryObject and NtSetInformationObject for the
[wine] / dlls / d3d8 / shader.c
1 /*
2  * shaders implementation
3  *
4  * Copyright 2002 Raphael Junqueira
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "wingdi.h"
27 #include "wine/debug.h"
28
29 #include <math.h>
30
31 #include "d3d8_private.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
34
35 /* Shader debugging - Change the following line to enable debugging of software
36       vertex shaders                                                             */
37 #if 1
38 # define VSTRACE(A) TRACE A
39 # define TRACE_VECTOR(name) TRACE( #name "=(%f, %f, %f, %f)\n", name.x, name.y, name.z, name.w)
40 #else 
41 # define VSTRACE(A) 
42 # define TRACE_VECTOR(name)
43 #endif
44
45
46 /**
47  * DirectX9 SDK download
48  *  http://msdn.microsoft.com/library/default.asp?url=/downloads/list/directx.asp
49  *
50  * Exploring D3DX
51  *  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndrive/html/directx07162002.asp
52  *
53  * Using Vertex Shaders
54  *  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndrive/html/directx02192001.asp
55  *
56  * Dx9 New
57  *  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/whatsnew.asp
58  *
59  * Dx9 Shaders
60  *  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/Shaders/VertexShader2_0/VertexShader2_0.asp
61  *  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/Shaders/VertexShader2_0/Instructions/Instructions.asp
62  *  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/GettingStarted/VertexDeclaration/VertexDeclaration.asp
63  *  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/Shaders/VertexShader3_0/VertexShader3_0.asp
64  *
65  * Dx9 D3DX
66  *  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/VertexPipe/matrixstack/matrixstack.asp
67  *
68  * FVF
69  *  http://msdn.microsoft.com/library/en-us/directx9_c/directx/graphics/programmingguide/GettingStarted/VertexFormats/vformats.asp
70  *
71  * NVIDIA: DX8 Vertex Shader to NV Vertex Program
72  *  http://developer.nvidia.com/view.asp?IO=vstovp
73  *
74  * NVIDIA: Memory Management with VAR
75  *  http://developer.nvidia.com/view.asp?IO=var_memory_management 
76  */
77
78 typedef void (*shader_fct_t)();
79
80 typedef struct SHADER_OPCODE {
81   CONST BYTE    opcode;
82   const char*   name;
83   CONST UINT    num_params;
84   shader_fct_t  soft_fct;
85 } SHADER_OPCODE;
86
87 /*******************************
88  * vshader functions software VM
89  */
90
91 void vshader_add(D3DSHADERVECTOR* d, D3DSHADERVECTOR* s0, D3DSHADERVECTOR* s1) {
92   d->x = s0->x + s1->x;
93   d->y = s0->y + s1->y;
94   d->z = s0->z + s1->z;
95   d->w = s0->w + s1->w;
96   VSTRACE(("executing add: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
97                  s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
98 }
99
100 void vshader_dp3(D3DSHADERVECTOR* d, D3DSHADERVECTOR* s0, D3DSHADERVECTOR* s1) {
101   d->x = d->y = d->z = d->w = s0->x * s1->x + s0->y * s1->y + s0->z * s1->z;
102   VSTRACE(("executing dp3: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
103                  s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
104 }
105
106 void vshader_dp4(D3DSHADERVECTOR* d, D3DSHADERVECTOR* s0, D3DSHADERVECTOR* s1) {
107   d->x = d->y = d->z = d->w = s0->x * s1->x + s0->y * s1->y + s0->z * s1->z + s0->w * s1->w;
108   VSTRACE(("executing dp4: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
109           s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
110 }
111
112 void vshader_dst(D3DSHADERVECTOR* d, D3DSHADERVECTOR* s0, D3DSHADERVECTOR* s1) {
113   d->x = 1.0f;
114   d->y = s0->y * s1->y;
115   d->z = s0->z;
116   d->w = s1->w;
117   VSTRACE(("executing dst: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
118           s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
119 }
120
121 void vshader_expp(D3DSHADERVECTOR* d, D3DSHADERVECTOR* s0) {
122   float tmp_f = floorf(s0->w);
123   DWORD tmp_d = 0;
124   tmp_f = powf(2.0f, s0->w);
125   tmp_d = *((DWORD*) &tmp_f) & 0xFFFFFF00;
126
127   d->x  = powf(2.0f, tmp_f);
128   d->y  = s0->w - tmp_f;
129   d->z  = *((float*) &tmp_d);
130   d->w  = 1.0f;
131   VSTRACE(("executing exp: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
132                 s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
133 }
134
135 void vshader_lit(D3DSHADERVECTOR* d, D3DSHADERVECTOR* s0) {
136   d->x = 1.0f;
137   d->y = (0.0f < s0->x) ? s0->x : 0.0f;
138   d->z = (0.0f < s0->x && 0.0f < s0->y) ? powf(s0->y, s0->w) : 0.0f;
139   d->w = 1.0f;
140   VSTRACE(("executing lit: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
141                  s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
142 }
143
144 void vshader_logp(D3DSHADERVECTOR* d, D3DSHADERVECTOR* s0) {
145   float tmp_f = fabsf(s0->w); 
146   d->x = d->y = d->z = d->w = (0.0f != tmp_f) ? logf(tmp_f) / logf(2.0f) : -HUGE;
147   VSTRACE(("executing logp: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
148                  s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
149 }
150
151 void vshader_mad(D3DSHADERVECTOR* d, D3DSHADERVECTOR* s0, D3DSHADERVECTOR* s1, D3DSHADERVECTOR* s2) {
152   d->x = s0->x * s1->x + s2->x;
153   d->y = s0->y * s1->y + s2->y;
154   d->z = s0->z * s1->z + s2->z;
155   d->w = s0->w * s1->w + s2->w;
156   VSTRACE(("executing mad: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) s2=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
157           s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, s2->x, s2->y, s2->z, s2->w, d->x, d->y, d->z, d->w));
158 }
159
160 void vshader_max(D3DSHADERVECTOR* d, D3DSHADERVECTOR* s0, D3DSHADERVECTOR* s1) {
161   d->x = (s0->x >= s1->x) ? s0->x : s1->x;
162   d->y = (s0->y >= s1->y) ? s0->y : s1->y;
163   d->z = (s0->z >= s1->z) ? s0->z : s1->z;
164   d->w = (s0->w >= s1->w) ? s0->w : s1->w;
165   VSTRACE(("executing max: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
166           s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
167 }
168
169 void vshader_min(D3DSHADERVECTOR* d, D3DSHADERVECTOR* s0, D3DSHADERVECTOR* s1) {
170   d->x = (s0->x < s1->x) ? s0->x : s1->x;
171   d->y = (s0->y < s1->y) ? s0->y : s1->y;
172   d->z = (s0->z < s1->z) ? s0->z : s1->z;
173   d->w = (s0->w < s1->w) ? s0->w : s1->w;
174   VSTRACE(("executing min: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
175           s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
176 }
177
178 void vshader_mov(D3DSHADERVECTOR* d, D3DSHADERVECTOR* s0) {
179   d->x = s0->x;
180   d->y = s0->y;
181   d->z = s0->z;
182   d->w = s0->w;
183   VSTRACE(("executing mov: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
184           s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
185 }
186
187 void vshader_mul(D3DSHADERVECTOR* d, D3DSHADERVECTOR* s0, D3DSHADERVECTOR* s1) {
188   d->x = s0->x * s1->x;
189   d->y = s0->y * s1->y;
190   d->z = s0->z * s1->z;
191   d->w = s0->w * s1->w;
192   VSTRACE(("executing mul: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
193           s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
194 }
195
196 void vshader_nop(void) {
197   /* NOPPPP ahhh too easy ;) */
198 }
199
200 void vshader_rcp(D3DSHADERVECTOR* d, D3DSHADERVECTOR* s0) {
201   d->x = d->y = d->z = d->w = (0.0f == s0->w) ? HUGE : 1.0f / s0->w;
202   VSTRACE(("executing rcp: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
203           s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
204 }
205
206 void vshader_rsq(D3DSHADERVECTOR* d, D3DSHADERVECTOR* s0) {
207   float tmp_f = fabsf(s0->w);
208   d->x = d->y = d->z = d->w = (0.0f == tmp_f) ? HUGE : ((1.0f != tmp_f) ? 1.0f / sqrtf(tmp_f) : 1.0f);
209   VSTRACE(("executing rsq: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
210           s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
211 }
212
213 void vshader_sge(D3DSHADERVECTOR* d, D3DSHADERVECTOR* s0, D3DSHADERVECTOR* s1) {
214   d->x = (s0->x >= s1->x) ? 1.0f : 0.0f;
215   d->y = (s0->y >= s1->y) ? 1.0f : 0.0f;
216   d->z = (s0->z >= s1->z) ? 1.0f : 0.0f;
217   d->w = (s0->w >= s1->w) ? 1.0f : 0.0f;
218   VSTRACE(("executing sge: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
219           s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
220 }
221
222 void vshader_slt(D3DSHADERVECTOR* d, D3DSHADERVECTOR* s0, D3DSHADERVECTOR* s1) {
223   d->x = (s0->x < s1->x) ? 1.0f : 0.0f;
224   d->y = (s0->y < s1->y) ? 1.0f : 0.0f;
225   d->z = (s0->z < s1->z) ? 1.0f : 0.0f;
226   d->w = (s0->w < s1->w) ? 1.0f : 0.0f;
227   VSTRACE(("executing slt: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
228           s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
229 }
230
231 void vshader_sub(D3DSHADERVECTOR* d, D3DSHADERVECTOR* s0, D3DSHADERVECTOR* s1) {
232   d->x = s0->x - s1->x;
233   d->y = s0->y - s1->y;
234   d->z = s0->z - s1->z;
235   d->w = s0->w - s1->w;
236   VSTRACE(("executing sub: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
237           s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
238 }
239
240 /**
241  * Version 1.1 specific
242  */
243
244 void vshader_exp(D3DSHADERVECTOR* d, D3DSHADERVECTOR* s0) {
245   d->x = d->y = d->z = d->w = powf(2.0f, s0->w);
246   VSTRACE(("executing exp: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
247           s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
248 }
249
250 void vshader_log(D3DSHADERVECTOR* d, D3DSHADERVECTOR* s0) {
251   float tmp_f = fabsf(s0->w); 
252   d->x = d->y = d->z = d->w = (0.0f != tmp_f) ? logf(tmp_f) / logf(2.0f) : -HUGE;
253   VSTRACE(("executing log: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
254           s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
255 }
256
257 void vshader_frc(D3DSHADERVECTOR* d, D3DSHADERVECTOR* s0) {
258   d->x = s0->x - floorf(s0->x);
259   d->y = s0->y - floorf(s0->y);
260   d->z = 0.0f;
261   d->w = 1.0f;
262   VSTRACE(("executing frc: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
263           s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
264 }
265
266 typedef FLOAT D3DMATRIX44[4][4];
267 typedef FLOAT D3DMATRIX43[4][3];
268 typedef FLOAT D3DMATRIX34[4][4];
269 typedef FLOAT D3DMATRIX33[4][3];
270 typedef FLOAT D3DMATRIX32[4][2];
271
272 void vshader_m4x4(D3DSHADERVECTOR* d, D3DSHADERVECTOR* s0, /*D3DSHADERVECTOR* mat1*/ D3DMATRIX44 mat) {
273   /*
274    * BuGGY CODE: here only if cast not work for copy/paste
275   D3DSHADERVECTOR* mat2 = mat1 + 1;
276   D3DSHADERVECTOR* mat3 = mat1 + 2;
277   D3DSHADERVECTOR* mat4 = mat1 + 3; 
278   d->x = mat1->x * s0->x + mat2->x * s0->y + mat3->x * s0->z + mat4->x * s0->w;
279   d->y = mat1->y * s0->x + mat2->y * s0->y + mat3->y * s0->z + mat4->y * s0->w;
280   d->z = mat1->z * s0->x + mat2->z * s0->y + mat3->z * s0->z + mat4->z * s0->w;
281   d->w = mat1->w * s0->x + mat2->w * s0->y + mat3->w * s0->z + mat4->w * s0->w;
282   */
283   d->x = mat[0][0] * s0->x + mat[0][1] * s0->y + mat[0][2] * s0->z + mat[0][3] * s0->w;
284   d->y = mat[1][0] * s0->x + mat[1][1] * s0->y + mat[1][2] * s0->z + mat[1][3] * s0->w;
285   d->z = mat[2][0] * s0->x + mat[2][1] * s0->y + mat[2][2] * s0->z + mat[2][3] * s0->w;
286   d->w = mat[3][0] * s0->x + mat[3][1] * s0->y + mat[3][2] * s0->z + mat[3][3] * s0->w;
287   VSTRACE(("executing m4x4(1): mat=(%f, %f, %f, %f)    s0=(%f)     d=(%f) \n", mat[0][0], mat[0][1], mat[0][2], mat[0][3], s0->x, d->x));
288   VSTRACE(("executing m4x4(2): mat=(%f, %f, %f, %f)       (%f)       (%f) \n", mat[1][0], mat[1][1], mat[1][2], mat[1][3], s0->y, d->y));
289   VSTRACE(("executing m4x4(3): mat=(%f, %f, %f, %f) X     (%f)  =    (%f) \n", mat[2][0], mat[2][1], mat[2][2], mat[2][3], s0->z, d->z));
290   VSTRACE(("executing m4x4(4): mat=(%f, %f, %f, %f)       (%f)       (%f) \n", mat[3][0], mat[3][1], mat[3][2], mat[3][3], s0->w, d->w));
291 }
292
293 void vshader_m4x3(D3DSHADERVECTOR* d, D3DSHADERVECTOR* s0, D3DMATRIX43 mat) {
294   d->x = mat[0][0] * s0->x + mat[0][1] * s0->y + mat[0][2] * s0->z + mat[0][3] * s0->w;
295   d->y = mat[1][0] * s0->x + mat[1][1] * s0->y + mat[1][2] * s0->z + mat[1][3] * s0->w;
296   d->z = mat[2][0] * s0->x + mat[2][1] * s0->y + mat[2][2] * s0->z + mat[2][3] * s0->w;
297   d->w = 1.0f;
298   VSTRACE(("executing m4x3(1): mat=(%f, %f, %f, %f)    s0=(%f)     d=(%f) \n", mat[0][0], mat[0][1], mat[0][2], mat[0][3], s0->x, d->x));
299   VSTRACE(("executing m4x3(2): mat=(%f, %f, %f, %f)       (%f)       (%f) \n", mat[1][0], mat[1][1], mat[1][2], mat[1][3], s0->y, d->y));
300   VSTRACE(("executing m4x3(3): mat=(%f, %f, %f, %f) X     (%f)  =    (%f) \n", mat[2][0], mat[2][1], mat[2][2], mat[2][3], s0->z, d->z));
301   VSTRACE(("executing m4x3(4):                            (%f)       (%f) \n", s0->w, d->w));
302 }
303
304 void vshader_m3x4(D3DSHADERVECTOR* d, D3DSHADERVECTOR* s0, D3DMATRIX34 mat) {
305   d->x = mat[0][0] * s0->x + mat[0][1] * s0->y + mat[0][2] * s0->z;
306   d->y = mat[2][0] * s0->x + mat[1][1] * s0->y + mat[1][2] * s0->z;
307   d->z = mat[2][0] * s0->x + mat[2][1] * s0->y + mat[2][2] * s0->z;
308   d->w = mat[3][0] * s0->x + mat[3][1] * s0->y + mat[3][2] * s0->z;
309   VSTRACE(("executing m3x4(1): mat=(%f, %f, %f)    s0=(%f)     d=(%f) \n", mat[0][0], mat[0][1], mat[0][2], s0->x, d->x));
310   VSTRACE(("executing m3x4(2): mat=(%f, %f, %f)       (%f)       (%f) \n", mat[1][0], mat[1][1], mat[1][2], s0->y, d->y));
311   VSTRACE(("executing m3x4(3): mat=(%f, %f, %f) X     (%f)  =    (%f) \n", mat[2][0], mat[2][1], mat[2][2], s0->z, d->z));
312   VSTRACE(("executing m3x4(4): mat=(%f, %f, %f)       (%f)       (%f) \n", mat[3][0], mat[3][1], mat[3][2], s0->w, d->w));
313 }
314
315 void vshader_m3x3(D3DSHADERVECTOR* d, D3DSHADERVECTOR* s0, D3DMATRIX33 mat) {
316   d->x = mat[0][0] * s0->x + mat[0][1] * s0->y + mat[2][2] * s0->z;
317   d->y = mat[1][0] * s0->x + mat[1][1] * s0->y + mat[2][2] * s0->z;
318   d->z = mat[2][0] * s0->x + mat[2][1] * s0->y + mat[2][2] * s0->z;
319   d->w = 1.0f;
320   VSTRACE(("executing m3x3(1): mat=(%f, %f, %f)    s0=(%f)     d=(%f) \n", mat[0][0], mat[0][1], mat[0][2], s0->x, d->x));
321   VSTRACE(("executing m3x3(2): mat=(%f, %f, %f)       (%f)       (%f) \n", mat[1][0], mat[1][1], mat[1][2], s0->y, d->y));
322   VSTRACE(("executing m3x3(3): mat=(%f, %f, %f) X     (%f)  =    (%f) \n", mat[2][0], mat[2][1], mat[2][2], s0->z, d->z));
323   VSTRACE(("executing m3x3(4):                                       (%f) \n", d->w));
324 }
325
326 void vshader_m3x2(D3DSHADERVECTOR* d, D3DSHADERVECTOR* s0, D3DMATRIX32 mat) {
327   FIXME("check\n");
328   d->x = mat[0][0] * s0->x + mat[0][1] * s0->y + mat[0][2] * s0->z;
329   d->y = mat[1][0] * s0->x + mat[1][1] * s0->y + mat[1][2] * s0->z;
330   d->z = 0.0f;
331   d->w = 1.0f;
332 }
333
334 /**
335  * Version 2.0 specific
336  */
337 void vshader_lrp(D3DSHADERVECTOR* d, D3DSHADERVECTOR* s0, D3DSHADERVECTOR* s1, D3DSHADERVECTOR* s2, D3DSHADERVECTOR* s3) {
338   d->x = s0->x * (s1->x - s2->x) + s2->x; 
339   d->y = s0->y * (s1->y - s2->y) + s2->y; 
340   d->z = s0->z * (s1->z - s2->z) + s2->z; 
341   d->w = s0->w * (s1->w - s2->w) + s2->x; 
342 }
343
344 /**
345  * log, exp, frc, m*x* seems to be macros ins ... to see
346  */
347 static CONST SHADER_OPCODE vshader_ins [] = {
348   {D3DSIO_NOP,  "nop",  0, vshader_nop},
349   {D3DSIO_MOV,  "mov",  2, vshader_mov},
350   {D3DSIO_ADD,  "add",  3, vshader_add},
351   {D3DSIO_SUB,  "sub",  3, vshader_sub},
352   {D3DSIO_MAD,  "mad",  4, vshader_mad},
353   {D3DSIO_MUL,  "mul",  3, vshader_mul},
354   {D3DSIO_RCP,  "rcp",  2, vshader_rcp},
355   {D3DSIO_RSQ,  "rsq",  2, vshader_rsq},
356   {D3DSIO_DP3,  "dp3",  3, vshader_dp3},
357   {D3DSIO_DP4,  "dp4",  3, vshader_dp4},
358   {D3DSIO_MIN,  "min",  3, vshader_min},
359   {D3DSIO_MAX,  "max",  3, vshader_max},
360   {D3DSIO_SLT,  "slt",  3, vshader_slt},
361   {D3DSIO_SGE,  "sge",  3, vshader_sge},
362   {D3DSIO_EXP,  "exp",  2, vshader_exp},
363   {D3DSIO_LOG,  "log",  2, vshader_log},
364   {D3DSIO_LIT,  "lit",  2, vshader_lit},
365   {D3DSIO_DST,  "dst",  3, vshader_dst},
366   {D3DSIO_LRP,  "lrp",  5, vshader_lrp},
367   {D3DSIO_FRC,  "frc",  2, vshader_frc},
368   {D3DSIO_M4x4, "m4x4", 3, vshader_m4x4},
369   {D3DSIO_M4x3, "m4x3", 3, vshader_m4x3},
370   {D3DSIO_M3x4, "m3x4", 3, vshader_m3x4},
371   {D3DSIO_M3x3, "m3x3", 3, vshader_m3x3},
372   {D3DSIO_M3x2, "m3x2", 3, vshader_m3x2},
373   /** FIXME: use direct access so add the others opcodes as stubs */
374   {D3DSIO_EXPP, "expp", 2, vshader_expp},
375   {D3DSIO_LOGP, "logp", 2, vshader_logp},
376
377   {0, NULL, 0, NULL}
378 };
379
380
381 inline static const SHADER_OPCODE* vshader_program_get_opcode(const DWORD code) {
382   DWORD i = 0;
383   /** TODO: use dichotomic search */
384   while (NULL != vshader_ins[i].name) {
385     if ((code & D3DSI_OPCODE_MASK) == vshader_ins[i].opcode) {
386       return &vshader_ins[i];
387     }
388     ++i;
389   }
390   return NULL;
391 }
392
393 inline static void vshader_program_dump_param(const DWORD param, int input) {
394   static const char* rastout_reg_names[] = { "oPos", "oFog", "oPts" };
395   static const char swizzle_reg_chars[] = "xyzw";
396
397   DWORD reg = param & 0x00001FFF;
398   DWORD regtype = ((param & D3DSP_REGTYPE_MASK) >> D3DSP_REGTYPE_SHIFT);
399
400   if ((param & D3DSP_SRCMOD_MASK) == D3DSPSM_NEG) TRACE("-");
401   
402   switch (regtype << D3DSP_REGTYPE_SHIFT) {
403   case D3DSPR_TEMP:
404     TRACE("R[%lu]", reg);
405     break;
406   case D3DSPR_INPUT:
407     TRACE("V[%lu]", reg);
408     break;
409   case D3DSPR_CONST:
410     TRACE("C[%s%lu]", (reg & D3DVS_ADDRMODE_RELATIVE) ? "a0.x + " : "", reg);
411     break;
412   case D3DSPR_ADDR: /*case D3DSPR_TEXTURE:*/
413     TRACE("a[%lu]", reg);
414     break;
415   case D3DSPR_RASTOUT:
416     TRACE("%s", rastout_reg_names[reg]);
417     break;
418   case D3DSPR_ATTROUT:
419     TRACE("oD[%lu]", reg);
420     break;
421   case D3DSPR_TEXCRDOUT:
422     TRACE("oT[%lu]", reg);
423     break;
424   default:
425     break;
426   }
427
428   if (!input) {
429     /** operand output */
430     if ((param & D3DSP_WRITEMASK_ALL) != D3DSP_WRITEMASK_ALL) {
431       if (param & D3DSP_WRITEMASK_0) TRACE(".x");
432       if (param & D3DSP_WRITEMASK_1) TRACE(".y");
433       if (param & D3DSP_WRITEMASK_2) TRACE(".z");
434       if (param & D3DSP_WRITEMASK_3) TRACE(".w");
435     }
436   } else {
437     /** operand input */
438     DWORD swizzle = (param & D3DVS_SWIZZLE_MASK) >> D3DVS_SWIZZLE_SHIFT;
439     DWORD swizzle_x = swizzle & 0x03;
440     DWORD swizzle_y = (swizzle >> 2) & 0x03;
441     DWORD swizzle_z = (swizzle >> 4) & 0x03;
442     DWORD swizzle_w = (swizzle >> 6) & 0x03;
443     /**
444      * swizzle bits fields:
445      *  WWZZYYXX
446      */
447     if ((D3DVS_NOSWIZZLE >> D3DVS_SWIZZLE_SHIFT) != swizzle) { /* ! D3DVS_NOSWIZZLE == 0xE4 << D3DVS_SWIZZLE_SHIFT */
448       if (swizzle_x == swizzle_y && 
449           swizzle_x == swizzle_z && 
450           swizzle_x == swizzle_w) {
451         TRACE(".%c", swizzle_reg_chars[swizzle_x]);
452       } else {
453         TRACE(".%c%c%c%c", 
454                 swizzle_reg_chars[swizzle_x], 
455                 swizzle_reg_chars[swizzle_y], 
456                 swizzle_reg_chars[swizzle_z], 
457                 swizzle_reg_chars[swizzle_w]);
458       }
459     }
460   }
461 }
462
463 inline static BOOL vshader_is_version_token(DWORD token) {
464   return 0xFFFE0000 == (token & 0xFFFE0000);
465 }
466
467 inline static BOOL vshader_is_comment_token(DWORD token) {
468   return D3DSIO_COMMENT == (token & D3DSI_OPCODE_MASK);
469 }
470
471 /**
472  * Function parser ...
473  */
474 inline static VOID IDirect3DVertexShaderImpl_ParseProgram(IDirect3DVertexShaderImpl* vshader, CONST DWORD* pFunction) {
475   const DWORD* pToken = pFunction;
476   const SHADER_OPCODE* curOpcode = NULL;
477   DWORD len = 0;  
478   DWORD i;
479
480   if (NULL != pToken) {
481     while (D3DVS_END() != *pToken) {
482       if (vshader_is_version_token(*pToken)) { /** version */
483         TRACE("vs.%lu.%lu\n", (*pToken >> 8) & 0x0F, (*pToken & 0x0F));
484         ++pToken;
485         ++len;
486         continue;
487       } 
488       if (vshader_is_comment_token(*pToken)) { /** comment */
489         DWORD comment_len = (*pToken & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
490         ++pToken;
491         /*TRACE("comment[%ld] ;%s\n", comment_len, (char*)pToken);*/
492         pToken += comment_len;
493         len += comment_len + 1;
494         continue;
495       }
496       curOpcode = vshader_program_get_opcode(*pToken);
497       ++pToken;
498       ++len;
499       if (NULL == curOpcode) {
500         /* unkown current opcode ... */
501         while (*pToken & 0x80000000) {
502           TRACE("unrecognized opcode: %08lx\n", *pToken);
503           ++pToken;
504           ++len;
505         }
506       } else {
507         TRACE("%s ", curOpcode->name);
508         if (curOpcode->num_params > 0) {
509           vshader_program_dump_param(*pToken, 0);
510           ++pToken;
511           ++len;
512           for (i = 1; i < curOpcode->num_params; ++i) {
513             TRACE(", ");
514             vshader_program_dump_param(*pToken, 1);
515             ++pToken;
516             ++len;
517           }
518         }
519         TRACE("\n");
520       }
521     }
522     vshader->functionLength = (len + 1) * sizeof(DWORD);
523   } else {
524     vshader->functionLength = 1; /* no Function defined use fixed function vertex processing */
525   }
526   /* copy the function ... because it will certainly be released by application */
527
528   if (NULL != pFunction) {
529     vshader->function = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, vshader->functionLength);
530     memcpy(vshader->function, pFunction, vshader->functionLength);
531   } else {
532     vshader->function = NULL;
533   }
534 }
535
536 HRESULT WINAPI IDirect3DDeviceImpl_CreateVertexShader(IDirect3DDevice8Impl* This, CONST DWORD* pFunction, DWORD Usage, IDirect3DVertexShaderImpl** ppVertexShader) {
537   IDirect3DVertexShaderImpl* object;
538
539   object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DVertexShaderImpl));
540   if (NULL == object) {
541     *ppVertexShader = NULL;
542     return D3DERR_OUTOFVIDEOMEMORY;
543   }
544   /*object->lpVtbl = &Direct3DVextexShader9_Vtbl;*/
545   object->device = This; /* FIXME: AddRef(This) */
546   object->ref = 1;
547   
548   object->usage = Usage;
549   object->data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SHADERDATA8));
550     
551   IDirect3DVertexShaderImpl_ParseProgram(object, pFunction);
552
553   *ppVertexShader = object;
554   return D3D_OK;
555 }
556
557 BOOL IDirect3DVertexShaderImpl_ExecuteHAL(IDirect3DVertexShaderImpl* vshader, VSHADERINPUTDATA8* input, VSHADEROUTPUTDATA8* output) {
558   /** 
559    * TODO: use the NV_vertex_program (or 1_1) extension 
560    *  and specifics vendors (ARB_vertex_program??) variants for it 
561    */
562   return TRUE;
563 }
564
565 HRESULT WINAPI IDirect3DVertexShaderImpl_ExecuteSW(IDirect3DVertexShaderImpl* vshader, VSHADERINPUTDATA8* input, VSHADEROUTPUTDATA8* output) {
566   /** Vertex Shader Temporary Registers */
567   D3DSHADERVECTOR R[12];
568   /*D3DSHADERSCALAR A0;*/
569   D3DSHADERVECTOR A[1];
570   /** temporary Vector for modifier management */
571   D3DSHADERVECTOR d;
572   D3DSHADERVECTOR s[3];
573   /** parser datas */
574   const DWORD* pToken = vshader->function;
575   const SHADER_OPCODE* curOpcode = NULL;
576   /** functions parameters */
577   D3DSHADERVECTOR* p[4];
578   D3DSHADERVECTOR* p_send[4];
579   DWORD i;
580
581   /** init temporary register */
582   memset(R, 0, 12 * sizeof(D3DSHADERVECTOR));
583
584   /* vshader_program_parse(vshader); */
585 #if 0
586   TRACE("Input:\n");
587   TRACE_VECTOR(vshader->data->C[0]);
588   TRACE_VECTOR(vshader->data->C[1]);
589   TRACE_VECTOR(vshader->data->C[2]);
590   TRACE_VECTOR(vshader->data->C[3]);
591   TRACE_VECTOR(vshader->data->C[4]);
592   TRACE_VECTOR(vshader->data->C[5]);
593   TRACE_VECTOR(vshader->data->C[6]);
594   TRACE_VECTOR(vshader->data->C[7]);
595   TRACE_VECTOR(vshader->data->C[8]);
596   TRACE_VECTOR(input->V[D3DVSDE_POSITION]);
597   TRACE_VECTOR(input->V[D3DVSDE_BLENDWEIGHT]);
598   TRACE_VECTOR(input->V[D3DVSDE_BLENDINDICES]);
599   TRACE_VECTOR(input->V[D3DVSDE_NORMAL]);
600   TRACE_VECTOR(input->V[D3DVSDE_PSIZE]);
601   TRACE_VECTOR(input->V[D3DVSDE_DIFFUSE]);
602   TRACE_VECTOR(input->V[D3DVSDE_SPECULAR]);
603   TRACE_VECTOR(input->V[D3DVSDE_TEXCOORD0]);
604   TRACE_VECTOR(input->V[D3DVSDE_TEXCOORD1]);
605 #endif
606
607   TRACE_VECTOR(vshader->data->C[64]);
608
609   /* the first dword is the version tag */
610   /* TODO: parse it */
611   
612   if (vshader_is_version_token(*pToken)) { /** version */
613     ++pToken;
614   }
615   while (D3DVS_END() != *pToken) {
616     if (vshader_is_comment_token(*pToken)) { /** comment */
617       DWORD comment_len = (*pToken & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
618       ++pToken;
619       pToken += comment_len;
620       continue ;
621     }
622     curOpcode = vshader_program_get_opcode(*pToken);
623     ++pToken;
624     if (NULL == curOpcode) {
625       i = 0;
626       /* unkown current opcode ... */
627       while (*pToken & 0x80000000) {
628         if (i == 0) {
629           TRACE("unrecognized opcode: pos=%d token=%08lX\n", (pToken - 1) - vshader->function, *(pToken - 1));
630         }
631         TRACE("unrecognized opcode param: pos=%d token=%08lX what=", pToken - vshader->function, *pToken);
632         vshader_program_dump_param(*pToken, i);
633         TRACE("\n");
634         ++i;
635         ++pToken;
636       }
637       /*return FALSE;*/
638     } else {     
639       if (curOpcode->num_params > 0) {  
640         /*TRACE(">> execting opcode: pos=%d opcode_name=%s token=%08lX\n", pToken - vshader->function, curOpcode->name, *pToken);*/
641         for (i = 0; i < curOpcode->num_params; ++i) {
642           DWORD reg = pToken[i] & 0x00001FFF;
643           DWORD regtype = ((pToken[i] & D3DSP_REGTYPE_MASK) >> D3DSP_REGTYPE_SHIFT);
644
645           switch (regtype << D3DSP_REGTYPE_SHIFT) {
646           case D3DSPR_TEMP:
647             /*TRACE("p[%d]=R[%d]\n", i, reg);*/
648             p[i] = &R[reg];
649             break;
650           case D3DSPR_INPUT:
651             /*TRACE("p[%d]=V[%s]\n", i, VertexShaderDeclRegister[reg]);*/
652             p[i] = &input->V[reg];
653             break;
654           case D3DSPR_CONST:
655             if (reg & D3DVS_ADDRMODE_RELATIVE) {
656               p[i] = &vshader->data->C[(DWORD) A[0].x + reg];
657             } else {
658               p[i] = &vshader->data->C[reg];
659             }
660             break;
661           case D3DSPR_ADDR: /*case D3DSPR_TEXTURE:*/
662             if (0 != reg) {
663               ERR("cannot handle address registers != a0, forcing use of a0\n");
664               reg = 0;
665             }
666             /*TRACE("p[%d]=A[%d]\n", i, reg);*/
667             p[i] = &A[reg];
668             break;
669           case D3DSPR_RASTOUT:
670             switch (reg) {
671             case D3DSRO_POSITION:
672               p[i] = &output->oPos;
673               break;
674             case D3DSRO_FOG:
675               p[i] = &output->oFog;
676               break;
677             case D3DSRO_POINT_SIZE:
678               p[i] = &output->oPts;
679               break;
680             }
681             break;
682           case D3DSPR_ATTROUT:
683             /*TRACE("p[%d]=oD[%d]\n", i, reg);*/
684             p[i] = &output->oD[reg];
685             break;
686           case D3DSPR_TEXCRDOUT:
687             /*TRACE("p[%d]=oT[%d]\n", i, reg);*/
688             p[i] = &output->oT[reg];
689             break;
690           default:
691             break;
692           }
693           
694           if (i > 0) { /* input reg */
695             DWORD swizzle = (pToken[i] & D3DVS_SWIZZLE_MASK) >> D3DVS_SWIZZLE_SHIFT;
696             UINT isNegative = ((pToken[i] & D3DSP_SRCMOD_MASK) == D3DSPSM_NEG);
697
698             if (!isNegative && (D3DVS_NOSWIZZLE >> D3DVS_SWIZZLE_SHIFT) == swizzle) {
699               /*TRACE("p[%d] not swizzled\n", i);*/
700               p_send[i] = p[i];
701             } else {
702               DWORD swizzle_x = swizzle & 0x03;
703               DWORD swizzle_y = (swizzle >> 2) & 0x03;
704               DWORD swizzle_z = (swizzle >> 4) & 0x03;
705               DWORD swizzle_w = (swizzle >> 6) & 0x03;
706               /*TRACE("p[%d] swizzled\n", i);*/
707               float* tt = (float*) p[i];
708               s[i].x = (isNegative) ? -tt[swizzle_x] : tt[swizzle_x];
709               s[i].y = (isNegative) ? -tt[swizzle_y] : tt[swizzle_y];
710               s[i].z = (isNegative) ? -tt[swizzle_z] : tt[swizzle_z];
711               s[i].w = (isNegative) ? -tt[swizzle_w] : tt[swizzle_w];
712               p_send[i] = &s[i];
713             }
714           } else { /* output reg */
715             if ((pToken[i] & D3DSP_WRITEMASK_ALL) == D3DSP_WRITEMASK_ALL) {
716               p_send[i] = p[i];
717             } else {
718               p_send[i] = &d; /* to be post-processed for modifiers management */
719             }
720           }
721         }      
722       }
723
724       switch (curOpcode->num_params) {  
725       case 0:
726         curOpcode->soft_fct();
727         break;
728       case 1:
729         curOpcode->soft_fct(p_send[0]);
730         break;
731       case 2:
732         curOpcode->soft_fct(p_send[0], p_send[1]);
733         break;
734       case 3:
735         curOpcode->soft_fct(p_send[0], p_send[1], p_send[2]);
736         break;
737       case 4:
738         curOpcode->soft_fct(p_send[0], p_send[1], p_send[2], p_send[3]);
739         break;
740       case 5:
741         curOpcode->soft_fct(p_send[0], p_send[1], p_send[2], p_send[3], p_send[4]);
742         break;
743       default:
744         ERR("%s too many params: %u\n", curOpcode->name, curOpcode->num_params);
745       }
746
747       /* check if output reg modifier post-process */
748       if (curOpcode->num_params > 0 && (pToken[0] & D3DSP_WRITEMASK_ALL) != D3DSP_WRITEMASK_ALL) {
749         if (pToken[0] & D3DSP_WRITEMASK_0) p[0]->x = d.x; 
750         if (pToken[0] & D3DSP_WRITEMASK_1) p[0]->y = d.y; 
751         if (pToken[0] & D3DSP_WRITEMASK_2) p[0]->z = d.z; 
752         if (pToken[0] & D3DSP_WRITEMASK_3) p[0]->w = d.w; 
753       }
754       
755 #if 0
756       TRACE_VECTOR(output->oPos);
757       TRACE_VECTOR(output->oD[0]);
758       TRACE_VECTOR(output->oD[1]);
759       TRACE_VECTOR(output->oT[0]);
760       TRACE_VECTOR(output->oT[1]);
761       TRACE_VECTOR(R[0]);
762       TRACE_VECTOR(R[1]);
763       TRACE_VECTOR(R[2]);
764       TRACE_VECTOR(R[3]);
765       TRACE_VECTOR(R[4]);
766       TRACE_VECTOR(R[5]);
767 #endif
768
769       /* to next opcode token */
770       pToken += curOpcode->num_params;
771     }
772 #if 0
773     TRACE("End of current instruction:\n");
774     TRACE_VECTOR(output->oPos);
775     TRACE_VECTOR(output->oD[0]);
776     TRACE_VECTOR(output->oD[1]);
777     TRACE_VECTOR(output->oT[0]);
778     TRACE_VECTOR(output->oT[1]);
779     TRACE_VECTOR(R[0]);
780     TRACE_VECTOR(R[1]);
781     TRACE_VECTOR(R[2]);
782     TRACE_VECTOR(R[3]);
783     TRACE_VECTOR(R[4]);
784     TRACE_VECTOR(R[5]);
785 #endif
786   }
787 #if 0
788     TRACE("Output:\n");
789     TRACE_VECTOR(output->oPos);
790     TRACE_VECTOR(output->oD[0]);
791     TRACE_VECTOR(output->oD[1]);
792     TRACE_VECTOR(output->oT[0]);
793     TRACE_VECTOR(output->oT[1]);
794 #endif
795   return D3D_OK;
796 }
797
798 HRESULT WINAPI IDirect3DVertexShaderImpl_GetFunction(IDirect3DVertexShaderImpl* This, VOID* pData, UINT* pSizeOfData) {
799   if (NULL == pData) {
800     *pSizeOfData = This->functionLength;
801     return D3D_OK;
802   }
803   if (*pSizeOfData < This->functionLength) {
804     *pSizeOfData = This->functionLength;
805     return D3DERR_MOREDATA;
806   }
807   if (NULL == This->function) { /* no function defined */
808     TRACE("(%p) : GetFunction no User Function defined using NULL to %p\n", This, pData);
809     (*(DWORD **) pData) = NULL;
810   } else {
811     TRACE("(%p) : GetFunction copying to %p\n", This, pData);
812     memcpy(pData, This->function, This->functionLength);
813   }
814   return D3D_OK;
815 }
816
817 HRESULT WINAPI IDirect3DVertexShaderImpl_SetConstantF(IDirect3DVertexShaderImpl* This, UINT StartRegister, CONST FLOAT* pConstantData, UINT Vector4fCount) {
818   if (StartRegister + Vector4fCount > D3D8_VSHADER_MAX_CONSTANTS) {
819     return D3DERR_INVALIDCALL;
820   }
821   if (NULL == This->data) { /* temporary while datas not supported */
822     FIXME("(%p) : VertexShader_SetConstant not fully supported yet\n", This);
823     return D3DERR_INVALIDCALL;
824   }
825   memcpy(&This->data->C[StartRegister], pConstantData, Vector4fCount * 4 * sizeof(FLOAT));
826   return D3D_OK;
827 }
828
829 HRESULT WINAPI IDirect3DVertexShaderImpl_GetConstantF(IDirect3DVertexShaderImpl* This, UINT StartRegister, FLOAT* pConstantData, UINT Vector4fCount) {
830   if (StartRegister + Vector4fCount > D3D8_VSHADER_MAX_CONSTANTS) {
831     return D3DERR_INVALIDCALL;
832   }
833   if (NULL == This->data) { /* temporary while datas not supported */
834     return D3DERR_INVALIDCALL;
835   }
836   memcpy(pConstantData, &This->data->C[StartRegister], Vector4fCount * 4 * sizeof(FLOAT));
837   return D3D_OK;
838 }
839
840
841 /***********************************************************************
842  *              ValidateVertexShader (D3D8.@)
843  */
844 BOOL WINAPI ValidateVertexShader(LPVOID what, LPVOID toto) {
845   FIXME("(void): stub: %p %p\n", what, toto);
846   return TRUE;
847 }
848
849 /***********************************************************************
850  *              ValidatePixelShader (D3D8.@)
851  */
852 BOOL WINAPI ValidatePixelShader(LPVOID what) {
853   FIXME("(void): stub: %p\n", what);
854   return TRUE;
855 }