Fixed a race condition on RPC worker thread creation, and a typo.
[wine] / dlls / ddraw / d3dexecutebuffer.c
1 /* Direct3D ExecuteBuffer
2  * Copyright (c) 1998 Lionel ULMER
3  *
4  * This file contains the implementation of Direct3DExecuteBuffer.
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 <string.h>
24
25 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
27 #include "windef.h"
28 #include "winerror.h"
29 #include "objbase.h"
30 #include "ddraw.h"
31 #include "d3d.h"
32 #include "wine/debug.h"
33
34 #include "d3d_private.h"
35 #include "mesa_private.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
38
39 /* Structure to store the 'semi transformed' vertices */
40 typedef struct {
41     D3DVALUE x;
42     D3DVALUE y;
43     D3DVALUE z;
44     D3DVALUE w;
45
46     D3DVALUE nx;
47     D3DVALUE ny;
48     D3DVALUE nz;
49
50     D3DVALUE u;
51     D3DVALUE v;
52 } OGL_Vertex;
53
54 typedef struct {
55     D3DVALUE x;
56     D3DVALUE y;
57     D3DVALUE z;
58     D3DVALUE w;
59
60     D3DCOLOR c;
61     D3DCOLOR sc;
62
63     D3DVALUE u;
64     D3DVALUE v;
65 } OGL_LVertex;
66
67 static void _dump_d3dstatus(LPD3DSTATUS lpStatus) {
68
69 }
70
71 static void _dump_executedata(LPD3DEXECUTEDATA lpData) {
72     DPRINTF("dwSize : %ld\n", lpData->dwSize);
73     DPRINTF("Vertex      Offset : %ld  Count  : %ld\n", lpData->dwVertexOffset, lpData->dwVertexCount);
74     DPRINTF("Instruction Offset : %ld  Length : %ld\n", lpData->dwInstructionOffset, lpData->dwInstructionLength);
75     DPRINTF("HVertex     Offset : %ld\n", lpData->dwHVertexOffset);
76     _dump_d3dstatus(&(lpData->dsStatus));
77 }
78
79 static void _dump_D3DEXECUTEBUFFERDESC(LPD3DEXECUTEBUFFERDESC lpDesc) {
80
81 }
82
83 #define DO_VERTEX(index)                                                        \
84 {                                                                               \
85     glTexCoord2f(vx[index].u,                                                   \
86                  vx[index].v);                                                  \
87     glNormal3f(vx[index].nx,                                                    \
88                vx[index].ny,                                                    \
89                vx[index].nz);                                                   \
90     glVertex4f(vx[index].x,                                                     \
91                vx[index].y,                                                     \
92                vx[index].z,                                                     \
93                vx[index].w);                                                    \
94                                                                                 \
95     TRACE("   V: %f %f %f %f (%f %f %f) (%f %f)\n",                             \
96           vx[index].x, vx[index].y, vx[index].z, vx[index].w,                   \
97           vx[index].nx, vx[index].ny, vx[index].nz,                             \
98           vx[index].u, vx[index].v);                                            \
99 }
100
101 #define DO_LVERTEX(index)                                                       \
102 {                                                                               \
103     DWORD col = l_vx[index].c;                                                  \
104                                                                                 \
105     glColor3f(((col >> 16) & 0xFF) / 255.0,                                     \
106               ((col >>  8) & 0xFF) / 255.0,                                     \
107               ((col >>  0) & 0xFF) / 255.0);                                    \
108     glTexCoord2f(l_vx[index].u,                                                 \
109                  l_vx[index].v);                                                \
110     glVertex4f(l_vx[index].x,                                                   \
111                l_vx[index].y,                                                   \
112                l_vx[index].z,                                                   \
113                l_vx[index].w);                                                  \
114                                                                                 \
115     TRACE("  LV: %f %f %f %f (%02lx %02lx %02lx) (%f %f)\n",                    \
116           l_vx[index].x, l_vx[index].y, l_vx[index].z, l_vx[index].w,           \
117           ((col >> 16) & 0xFF), ((col >>  8) & 0xFF), ((col >>  0) & 0xFF),     \
118           l_vx[index].u, l_vx[index].v);                                        \
119 }
120
121 #define DO_TLVERTEX(index)                                                      \
122 {                                                                               \
123     D3DTLVERTEX *vx = &(tl_vx[index]);                                          \
124     DWORD col = vx->u5.color;                                                   \
125                                                                                 \
126     glColor3f(((col >> 16) & 0xFF) / 255.0,                                     \
127               ((col >>  8) & 0xFF) / 255.0,                                     \
128               ((col >>  0) & 0xFF) / 255.0);                                    \
129     glTexCoord2f(vx->u7.tu, vx->u8.tv);                                         \
130     if (vx->u4.rhw < 1e-8)                                                      \
131         glVertex3f(vx->u1.sx,                                                   \
132                    vx->u2.sy,                                                   \
133                    vx->u3.sz);                                                  \
134     else                                                                        \
135         glVertex4f(vx->u1.sx / vx->u4.rhw,                                      \
136                    vx->u2.sy / vx->u4.rhw,                                      \
137                    vx->u3.sz / vx->u4.rhw,                                      \
138                    1.0 / vx->u4.rhw);                                           \
139     TRACE(" TLV: %f %f %f (%02lx %02lx %02lx) (%f %f) (%f)\n",                  \
140           vx->u1.sx, vx->u2.sy, vx->u3.sz,                                      \
141           ((col >> 16) & 0xFF), ((col >>  8) & 0xFF), ((col >>  0) & 0xFF),     \
142           vx->u7.tu, vx->u8.tv, vx->u4.rhw);                                    \
143 }
144
145 #define TRIANGLE_LOOP(macro)                            \
146 {                                                       \
147     glBegin(GL_TRIANGLES);                              \
148     for (i = 0; i < count; i++) {                       \
149         LPD3DTRIANGLE ci = (LPD3DTRIANGLE) instr;       \
150                                                         \
151         TRACE("  v1: %d  v2: %d  v3: %d\n",             \
152               ci->u1.v1, ci->u2.v2, ci->u3.v3);         \
153         TRACE("  Flags : ");                            \
154         if (TRACE_ON(ddraw)) {                          \
155             /* Wireframe */                             \
156             if (ci->wFlags & D3DTRIFLAG_EDGEENABLE1)    \
157                 TRACE("EDGEENABLE1 ");          \
158             if (ci->wFlags & D3DTRIFLAG_EDGEENABLE2)    \
159                 TRACE("EDGEENABLE2 ");          \
160             if (ci->wFlags & D3DTRIFLAG_EDGEENABLE1)    \
161                 TRACE("EDGEENABLE3 ");          \
162                                                         \
163             /* Strips / Fans */                         \
164             if (ci->wFlags == D3DTRIFLAG_EVEN)          \
165                 TRACE("EVEN ");                 \
166             if (ci->wFlags == D3DTRIFLAG_ODD)           \
167                 TRACE("ODD ");                  \
168             if (ci->wFlags == D3DTRIFLAG_START)         \
169                 TRACE("START ");                        \
170             if ((ci->wFlags > 0) && (ci->wFlags < 30))  \
171                 TRACE("STARTFLAT(%d) ", ci->wFlags);    \
172             TRACE("\n");                                \
173         }                                               \
174                                                         \
175         /* Draw the triangle */                         \
176         macro(ci->u1.v1);                               \
177         macro(ci->u2.v2);                               \
178         macro(ci->u3.v3);                               \
179                                                         \
180         instr += size;                                  \
181     }                                                   \
182     glEnd();                                            \
183 }
184
185
186 static void execute(IDirect3DExecuteBufferImpl *This,
187                     IDirect3DDeviceImpl *lpDevice,
188                     IDirect3DViewportImpl *lpViewport)
189 {
190     /* DWORD bs = This->desc.dwBufferSize; */
191     DWORD vs = This->data.dwVertexOffset;
192     /* DWORD vc = This->data.dwVertexCount; */
193     DWORD is = This->data.dwInstructionOffset;
194     /* DWORD il = This->data.dwInstructionLength; */
195
196     char *instr = (char *)This->desc.lpData + is;
197
198     /* Should check if the viewport was added or not to the device */
199
200     /* Activate the viewport */
201     lpViewport->active_device = lpDevice;
202     lpViewport->activate(lpViewport);
203
204     TRACE("ExecuteData : \n");
205     if (TRACE_ON(ddraw))
206       _dump_executedata(&(This->data));
207
208     ENTER_GL();
209
210     while (1) {
211         LPD3DINSTRUCTION current = (LPD3DINSTRUCTION) instr;
212         BYTE size;
213         WORD count;
214         
215         count = current->wCount;
216         size = current->bSize;
217         instr += sizeof(D3DINSTRUCTION);
218         
219         switch (current->bOpcode) {
220             case D3DOP_POINT: {
221                 WARN("POINT-s          (%d)\n", count);
222                 instr += count * size;
223             } break;
224
225             case D3DOP_LINE: {
226                 WARN("LINE-s           (%d)\n", count);
227                 instr += count * size;
228             } break;
229
230             case D3DOP_TRIANGLE: {
231                 int i;
232                 OGL_Vertex  *vx    = (OGL_Vertex  *) This->vertex_data;
233                 OGL_LVertex *l_vx  = (OGL_LVertex *) This->vertex_data;
234                 D3DTLVERTEX *tl_vx = (D3DTLVERTEX *) This->vertex_data;
235                 TRACE("TRIANGLE         (%d)\n", count);
236                 
237                 switch (This->vertex_type) {
238                     case D3DVT_VERTEX:
239                         /* This time, there is lighting */
240                         glEnable(GL_LIGHTING);
241                         
242                         if (TRACE_ON(ddraw)) {
243                             TRACE("  Projection Matrix : (%p)\n", lpDevice->proj_mat);
244                             dump_D3DMATRIX(lpDevice->proj_mat);
245                             TRACE("  View       Matrix : (%p)\n", lpDevice->view_mat);
246                             dump_D3DMATRIX(lpDevice->view_mat);
247                         }
248
249                         /* Using the identity matrix as the world matrix as the world transformation was
250                            already done. */
251                         lpDevice->set_matrices(lpDevice, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
252                                                (D3DMATRIX *) id_mat, lpDevice->view_mat, lpDevice->proj_mat);
253                         break;
254
255                     case D3DVT_LVERTEX:
256                         /* No lighting */
257                         glDisable(GL_LIGHTING);
258
259                         if (TRACE_ON(ddraw)) {
260                             TRACE("  Projection Matrix : (%p)\n", lpDevice->proj_mat);
261                             dump_D3DMATRIX(lpDevice->proj_mat);
262                             TRACE("  View       Matrix : (%p)\n", lpDevice->view_mat);
263                             dump_D3DMATRIX(lpDevice->view_mat);
264                         }
265
266                         /* Using the identity matrix as the world matrix as the world transformation was
267                            already done. */
268                         lpDevice->set_matrices(lpDevice, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
269                                                (D3DMATRIX *) id_mat, lpDevice->view_mat, lpDevice->proj_mat);
270                         break;
271
272                     case D3DVT_TLVERTEX: {
273                         /* First, disable lighting and fogging */
274                         glDisable(GL_LIGHTING);
275                         glDisable(GL_FOG);
276                         
277                         d3ddevice_set_ortho(lpDevice);
278                     } break;
279
280                     default:
281                         ERR("Unhandled vertex type !\n");
282                         break;
283                 }
284
285                 switch (This->vertex_type) {
286                     case D3DVT_VERTEX:
287                         TRIANGLE_LOOP(DO_VERTEX);
288                         break;
289
290                     case D3DVT_LVERTEX:
291                         TRIANGLE_LOOP(DO_LVERTEX);
292                         break;
293
294                     case D3DVT_TLVERTEX:
295                         TRIANGLE_LOOP(DO_TLVERTEX);
296                         break;
297
298                     default:
299                         ERR("Unhandled vertex type !\n");
300                 }
301             } break;
302
303             case D3DOP_MATRIXLOAD:
304                 WARN("MATRIXLOAD-s     (%d)\n", count);
305                 instr += count * size;
306                 break;
307
308             case D3DOP_MATRIXMULTIPLY: {
309                 int i;
310                 TRACE("MATRIXMULTIPLY   (%d)\n", count);
311                 
312                 for (i = 0; i < count; i++) {
313                     LPD3DMATRIXMULTIPLY ci = (LPD3DMATRIXMULTIPLY) instr;
314                     LPD3DMATRIX a = (LPD3DMATRIX) ci->hDestMatrix;
315                     LPD3DMATRIX b = (LPD3DMATRIX) ci->hSrcMatrix1;
316                     LPD3DMATRIX c = (LPD3DMATRIX) ci->hSrcMatrix2;
317                     
318                     TRACE("  Dest : %08lx  Src1 : %08lx  Src2 : %08lx\n",
319                           ci->hDestMatrix, ci->hSrcMatrix1, ci->hSrcMatrix2);
320                     
321                     /* Do the multiplication..
322                        As I am VERY lazy, I let OpenGL do the multiplication for me */
323                     glMatrixMode(GL_PROJECTION);
324                     /* Save the current matrix */
325                     glPushMatrix();
326                     /* Load Matrix one and do the multiplication */
327                     glLoadMatrixf((float *) c);
328                     glMultMatrixf((float *) b);
329                     glGetFloatv(GL_PROJECTION_MATRIX, (float *) a);
330                     /* Restore the current matrix */
331                     glPopMatrix();
332                     
333                     instr += size;
334                 }
335             } break;
336
337             case D3DOP_STATETRANSFORM: {
338                 int i;
339                 TRACE("STATETRANSFORM   (%d)\n", count);
340                 
341                 for (i = 0; i < count; i++) {
342                     LPD3DSTATE ci = (LPD3DSTATE) instr;
343                     
344                     /* Handle the state transform */
345                     switch (ci->u1.dtstTransformStateType) {
346                         case D3DTRANSFORMSTATE_WORLD: {
347                             TRACE("  WORLD (%p)\n", (D3DMATRIX*) ci->u2.dwArg[0]);
348                             lpDevice->world_mat = (D3DMATRIX*) ci->u2.dwArg[0];
349                         } break;
350
351                         case D3DTRANSFORMSTATE_VIEW: {
352                             TRACE("  VIEW (%p)\n", (D3DMATRIX*) ci->u2.dwArg[0]);
353                             lpDevice->view_mat = (D3DMATRIX*) ci->u2.dwArg[0];
354                         } break;
355
356                         case D3DTRANSFORMSTATE_PROJECTION: {
357                             TRACE("  PROJECTION (%p)\n", (D3DMATRIX*) ci->u2.dwArg[0]);
358                             lpDevice->proj_mat = (D3DMATRIX*) ci->u2.dwArg[0];
359                         } break;
360                           
361                         default:
362                             ERR("  Unhandled state transformation !! (%d)\n", (int) ci->u1.dtstTransformStateType);
363                             break;
364                     }
365
366                     instr += size;
367                 }
368             } break;
369
370             case D3DOP_STATELIGHT: {
371                 int i;
372                 TRACE("STATELIGHT       (%d)\n", count);
373                 
374                 for (i = 0; i < count; i++) {
375                     LPD3DSTATE ci = (LPD3DSTATE) instr;
376                     
377                     /* Handle the state transform */
378                     switch (ci->u1.dlstLightStateType) {
379                         case D3DLIGHTSTATE_MATERIAL: {
380                             IDirect3DMaterialImpl* mat = (IDirect3DMaterialImpl*) ci->u2.dwArg[0];
381                             TRACE("  MATERIAL\n");
382                             
383                             if (mat != NULL) {
384                                 mat->activate(mat);
385                             } else {
386                                 TRACE("    bad Material Handle\n");
387                             }
388                         } break ;
389
390                         case D3DLIGHTSTATE_AMBIENT: {
391                             float light[4];
392                             DWORD dwLightState = ci->u2.dwArg[0];
393                             TRACE("  AMBIENT\n");
394                             
395                             light[0] = ((dwLightState >> 16) & 0xFF) / 255.0;
396                             light[1] = ((dwLightState >>  8) & 0xFF) / 255.0;
397                             light[2] = ((dwLightState >>  0) & 0xFF) / 255.0;
398                             light[3] = 1.0;
399                             glLightModelfv(GL_LIGHT_MODEL_AMBIENT, (float *) light);
400                             
401                             TRACE("    R:%02lx G:%02lx B:%02lx A:%02lx\n",
402                                   ((dwLightState >> 16) & 0xFF),
403                                   ((dwLightState >>  8) & 0xFF),
404                                   ((dwLightState >>  0) & 0xFF),
405                                   ((dwLightState >> 24) & 0xFF));
406                         } break ;
407                           
408                         case D3DLIGHTSTATE_COLORMODEL: {
409                             WARN("  COLORMODEL\n");
410                         } break ;
411
412                         case D3DLIGHTSTATE_FOGMODE: {
413                             WARN("  FOGMODE\n");
414                         } break ;
415
416                         case D3DLIGHTSTATE_FOGSTART: {
417                             WARN("  FOGSTART\n");
418                         } break ;
419
420                         case D3DLIGHTSTATE_FOGEND: {
421                             WARN("  FOGEND\n");
422                         } break ;
423
424                         case D3DLIGHTSTATE_FOGDENSITY: {
425                             WARN("  FOGDENSITY\n");
426                         } break ;
427
428                         default:
429                             ERR("  Unhandled light state !! (%d)\n", (int) ci->u1.dlstLightStateType);
430                             break;
431                     }
432                     instr += size;
433                 }
434             } break;
435
436             case D3DOP_STATERENDER: {
437                 int i;
438                 TRACE("STATERENDER      (%d)\n", count);
439
440                 for (i = 0; i < count; i++) {
441                     LPD3DSTATE ci = (LPD3DSTATE) instr;
442                     
443                     LEAVE_GL();
444                     IDirect3DDevice7_SetRenderState(ICOM_INTERFACE(lpDevice, IDirect3DDevice7),
445                                                     ci->u1.drstRenderStateType, ci->u2.dwArg[0]);
446                     ENTER_GL();
447
448                     instr += size;
449                 }
450             } break;
451
452             case D3DOP_PROCESSVERTICES: {
453                 int i;
454                 TRACE("PROCESSVERTICES  (%d)\n", count);
455
456                 for (i = 0; i < count; i++) {
457                     LPD3DPROCESSVERTICES ci = (LPD3DPROCESSVERTICES) instr;
458
459                     TRACE("  Start : %d Dest : %d Count : %ld\n",
460                           ci->wStart, ci->wDest, ci->dwCount);
461                     TRACE("  Flags : ");
462                     if (TRACE_ON(ddraw)) {
463                         if (ci->dwFlags & D3DPROCESSVERTICES_COPY)
464                             TRACE("COPY ");
465                         if (ci->dwFlags & D3DPROCESSVERTICES_NOCOLOR)
466                             TRACE("NOCOLOR ");
467                         if (ci->dwFlags == D3DPROCESSVERTICES_OPMASK)
468                             TRACE("OPMASK ");
469                         if (ci->dwFlags & D3DPROCESSVERTICES_TRANSFORM)
470                             TRACE("TRANSFORM ");
471                         if (ci->dwFlags == D3DPROCESSVERTICES_TRANSFORMLIGHT)
472                             TRACE("TRANSFORMLIGHT ");
473                         if (ci->dwFlags & D3DPROCESSVERTICES_UPDATEEXTENTS)
474                             TRACE("UPDATEEXTENTS ");
475                         TRACE("\n");
476                     }
477                     
478                     /* This is where doing Direct3D on top on OpenGL is quite difficult.
479                        This method transforms a set of vertices using the CURRENT state
480                        (lighting, projection, ...) but does not rasterize them.
481                        They will only be put on screen later (with the POINT / LINE and
482                        TRIANGLE op-codes). The problem is that you can have a triangle
483                        with each point having been transformed using another state...
484                        
485                        In this implementation, I will emulate only ONE thing : each
486                        vertex can have its own "WORLD" transformation (this is used in the
487                        TWIST.EXE demo of the 5.2 SDK). I suppose that all vertices of the
488                        execute buffer use the same state.
489                        
490                        If I find applications that change other states, I will try to do a
491                        more 'fine-tuned' state emulation (but I may become quite tricky if
492                        it changes a light position in the middle of a triangle).
493                        
494                        In this case, a 'direct' approach (i.e. without using OpenGL, but
495                        writing our own 3D rasterizer) would be easier. */
496                     
497                     /* The current method (with the hypothesis that only the WORLD matrix
498                        will change between two points) is like this :
499                        - I transform 'manually' all the vertices with the current WORLD
500                          matrix and store them in the vertex buffer
501                        - during the rasterization phase, the WORLD matrix will be set to
502                          the Identity matrix */
503                     
504                     /* Enough for the moment */
505                     if (ci->dwFlags == D3DPROCESSVERTICES_TRANSFORMLIGHT) {
506                         int nb;
507                         D3DVERTEX  *src = ((LPD3DVERTEX)  ((char *)This->desc.lpData + vs)) + ci->wStart;
508                         OGL_Vertex *dst = ((OGL_Vertex *) (This->vertex_data)) + ci->wDest;
509                         D3DMATRIX *mat = lpDevice->world_mat;
510                         
511                         TRACE("  World Matrix : (%p)\n", mat);
512                         dump_D3DMATRIX(mat);
513
514                         This->vertex_type = D3DVT_VERTEX;
515                         
516                         for (nb = 0; nb < ci->dwCount; nb++) {
517                             /* For the moment, no normal transformation... */
518                             dst->nx = (src->u4.nx * mat->_11) + (src->u5.ny * mat->_21) + (src->u6.nz * mat->_31);
519                             dst->ny = (src->u4.nx * mat->_12) + (src->u5.ny * mat->_22) + (src->u6.nz * mat->_32);
520                             dst->nz = (src->u4.nx * mat->_13) + (src->u5.ny * mat->_23) + (src->u6.nz * mat->_33);
521                             
522                             dst->u  = src->u7.tu;
523                             dst->v  = src->u8.tv;
524                             
525                             /* Now, the matrix multiplication */
526                             dst->x = (src->u1.x * mat->_11) + (src->u2.y * mat->_21) + (src->u3.z * mat->_31) + (1.0 * mat->_41);
527                             dst->y = (src->u1.x * mat->_12) + (src->u2.y * mat->_22) + (src->u3.z * mat->_32) + (1.0 * mat->_42);
528                             dst->z = (src->u1.x * mat->_13) + (src->u2.y * mat->_23) + (src->u3.z * mat->_33) + (1.0 * mat->_43);
529                             dst->w = (src->u1.x * mat->_14) + (src->u2.y * mat->_24) + (src->u3.z * mat->_34) + (1.0 * mat->_44);
530                             
531                             src++;
532                             dst++;
533                         }
534                     } else if (ci->dwFlags == D3DPROCESSVERTICES_TRANSFORM) {
535                         int nb;
536                         D3DLVERTEX *src  = ((LPD3DLVERTEX) ((char *)This->desc.lpData + vs)) + ci->wStart;
537                         OGL_LVertex *dst = ((OGL_LVertex *) (This->vertex_data)) + ci->wDest;
538                         D3DMATRIX *mat = lpDevice->world_mat;
539                         
540                         TRACE("  World Matrix : (%p)\n", mat);
541                         dump_D3DMATRIX(mat);
542                         
543                         This->vertex_type = D3DVT_LVERTEX;
544                         
545                         for (nb = 0; nb < ci->dwCount; nb++) {
546                             dst->c  = src->u4.color;
547                             dst->sc = src->u5.specular;
548                             dst->u  = src->u6.tu;
549                             dst->v  = src->u7.tv;
550                             
551                             /* Now, the matrix multiplication */
552                             dst->x = (src->u1.x * mat->_11) + (src->u2.y * mat->_21) + (src->u3.z * mat->_31) + (1.0 * mat->_41);
553                             dst->y = (src->u1.x * mat->_12) + (src->u2.y * mat->_22) + (src->u3.z * mat->_32) + (1.0 * mat->_42);
554                             dst->z = (src->u1.x * mat->_13) + (src->u2.y * mat->_23) + (src->u3.z * mat->_33) + (1.0 * mat->_43);
555                             dst->w = (src->u1.x * mat->_14) + (src->u2.y * mat->_24) + (src->u3.z * mat->_34) + (1.0 * mat->_44);
556                             
557                             src++;
558                             dst++;
559                         }
560                     } else if (ci->dwFlags == D3DPROCESSVERTICES_COPY) {
561                         D3DTLVERTEX *src = ((LPD3DTLVERTEX) ((char *)This->desc.lpData + vs)) + ci->wStart;
562                         D3DTLVERTEX *dst = ((LPD3DTLVERTEX) (This->vertex_data)) + ci->wDest;
563                         
564                         This->vertex_type = D3DVT_TLVERTEX;
565                         
566                         memcpy(dst, src, ci->dwCount * sizeof(D3DTLVERTEX));
567                     } else {
568                         ERR("Unhandled vertex processing !\n");
569                     }
570
571                     instr += size;
572                 }
573             } break;
574
575             case D3DOP_TEXTURELOAD: {
576                 WARN("TEXTURELOAD-s    (%d)\n", count);
577
578                 instr += count * size;
579             } break;
580
581             case D3DOP_EXIT: {
582                 TRACE("EXIT             (%d)\n", count);
583                 /* We did this instruction */
584                 instr += size;
585                 /* Exit this loop */
586                 goto end_of_buffer;
587             } break;
588
589             case D3DOP_BRANCHFORWARD: {
590                 int i;
591                 TRACE("BRANCHFORWARD    (%d)\n", count);
592
593                 for (i = 0; i < count; i++) {
594                     LPD3DBRANCH ci = (LPD3DBRANCH) instr;
595
596                     if ((This->data.dsStatus.dwStatus & ci->dwMask) == ci->dwValue) {
597                         if (!ci->bNegate) {
598                             TRACE(" Should branch to %ld\n", ci->dwOffset);
599                         }
600                     } else {
601                         if (ci->bNegate) {
602                             TRACE(" Should branch to %ld\n", ci->dwOffset);
603                         }
604                     }
605
606                     instr += size;
607                 }
608             } break;
609
610             case D3DOP_SPAN: {
611                 WARN("SPAN-s           (%d)\n", count);
612
613                 instr += count * size;
614             } break;
615
616             case D3DOP_SETSTATUS: {
617                 int i;
618                 TRACE("SETSTATUS        (%d)\n", count);
619
620                 for (i = 0; i < count; i++) {
621                     LPD3DSTATUS ci = (LPD3DSTATUS) instr;
622                     
623                     This->data.dsStatus = *ci;
624
625                     instr += size;
626                 }
627             } break;
628
629             default:
630                 ERR("Unhandled OpCode !!!\n");
631                 /* Try to save ... */
632                 instr += count * size;
633                 break;
634         }
635     }
636
637 end_of_buffer:
638     LEAVE_GL();
639 }
640
641 HRESULT WINAPI
642 Main_IDirect3DExecuteBufferImpl_1_QueryInterface(LPDIRECT3DEXECUTEBUFFER iface,
643                                                  REFIID riid,
644                                                  LPVOID* obp)
645 {
646     ICOM_THIS_FROM(IDirect3DExecuteBufferImpl, IDirect3DExecuteBuffer, iface);
647     TRACE("(%p/%p)->(%s,%p)\n", This, iface, debugstr_guid(riid), obp);
648
649     *obp = NULL;
650
651     if ( IsEqualGUID( &IID_IUnknown,  riid ) ) {
652         IDirect3DExecuteBuffer_AddRef(ICOM_INTERFACE(This, IDirect3DExecuteBuffer));
653         *obp = iface;
654         TRACE("  Creating IUnknown interface at %p.\n", *obp);
655         return S_OK;
656     }
657     if ( IsEqualGUID( &IID_IDirect3DMaterial, riid ) ) {
658         IDirect3DExecuteBuffer_AddRef(ICOM_INTERFACE(This, IDirect3DExecuteBuffer));
659         *obp = ICOM_INTERFACE(This, IDirect3DExecuteBuffer);
660         TRACE("  Creating IDirect3DExecuteBuffer interface %p\n", *obp);
661         return S_OK;
662     }
663     FIXME("(%p): interface for IID %s NOT found!\n", This, debugstr_guid(riid));
664     return OLE_E_ENUM_NOMORE;
665 }
666
667 ULONG WINAPI
668 Main_IDirect3DExecuteBufferImpl_1_AddRef(LPDIRECT3DEXECUTEBUFFER iface)
669 {
670     ICOM_THIS_FROM(IDirect3DExecuteBufferImpl, IDirect3DExecuteBuffer, iface);
671     FIXME("(%p/%p)->()incrementing from %lu.\n", This, iface, This->ref );
672     return ++(This->ref);
673 }
674
675 ULONG WINAPI
676 Main_IDirect3DExecuteBufferImpl_1_Release(LPDIRECT3DEXECUTEBUFFER iface)
677 {
678     ICOM_THIS_FROM(IDirect3DExecuteBufferImpl, IDirect3DExecuteBuffer, iface);
679     TRACE("(%p/%p)->()decrementing from %lu.\n", This, iface, This->ref);
680     if (!--(This->ref)) {
681         if ((This->desc.lpData != NULL) && This->need_free)
682             HeapFree(GetProcessHeap(),0,This->desc.lpData);
683         if (This->vertex_data != NULL)
684             HeapFree(GetProcessHeap(),0,This->vertex_data);
685         HeapFree(GetProcessHeap(),0,This);
686         return 0;
687     }
688
689     return This->ref;
690 }
691
692 HRESULT WINAPI
693 Main_IDirect3DExecuteBufferImpl_1_Initialize(LPDIRECT3DEXECUTEBUFFER iface,
694                                              LPDIRECT3DDEVICE lpDirect3DDevice,
695                                              LPD3DEXECUTEBUFFERDESC lpDesc)
696 {
697     ICOM_THIS_FROM(IDirect3DExecuteBufferImpl, IDirect3DExecuteBuffer, iface);
698     TRACE("(%p/%p)->(%p,%p) no-op....\n", This, iface, lpDirect3DDevice, lpDesc);
699     return DD_OK;
700 }
701
702 HRESULT WINAPI
703 Main_IDirect3DExecuteBufferImpl_1_Lock(LPDIRECT3DEXECUTEBUFFER iface,
704                                        LPD3DEXECUTEBUFFERDESC lpDesc)
705 {
706     ICOM_THIS_FROM(IDirect3DExecuteBufferImpl, IDirect3DExecuteBuffer, iface);
707     DWORD dwSize;
708     TRACE("(%p/%p)->(%p)\n", This, iface, lpDesc);
709
710     dwSize = lpDesc->dwSize;
711     memset(lpDesc, 0, dwSize);
712     memcpy(lpDesc, &This->desc, dwSize);
713     
714     if (TRACE_ON(ddraw)) {
715         TRACE("  Returning description : \n");
716         _dump_D3DEXECUTEBUFFERDESC(lpDesc);
717     }
718     return DD_OK;
719 }
720
721 HRESULT WINAPI
722 Main_IDirect3DExecuteBufferImpl_1_Unlock(LPDIRECT3DEXECUTEBUFFER iface)
723 {
724     ICOM_THIS_FROM(IDirect3DExecuteBufferImpl, IDirect3DExecuteBuffer, iface);
725     TRACE("(%p/%p)->() no-op...\n", This, iface);
726     return DD_OK;
727 }
728
729 HRESULT WINAPI
730 Main_IDirect3DExecuteBufferImpl_1_SetExecuteData(LPDIRECT3DEXECUTEBUFFER iface,
731                                                  LPD3DEXECUTEDATA lpData)
732 {
733     ICOM_THIS_FROM(IDirect3DExecuteBufferImpl, IDirect3DExecuteBuffer, iface);
734     DWORD nbvert;
735     TRACE("(%p/%p)->(%p)\n", This, iface, lpData);
736
737     memcpy(&This->data, lpData, lpData->dwSize);
738
739     /* Get the number of vertices in the execute buffer */
740     nbvert = This->data.dwVertexCount;
741     
742     /* Prepares the transformed vertex buffer */
743     if (This->vertex_data != NULL)
744         HeapFree(GetProcessHeap(), 0, This->vertex_data);
745     This->vertex_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nbvert * sizeof(OGL_Vertex));
746
747     if (TRACE_ON(ddraw)) {
748         _dump_executedata(lpData);
749     }
750
751     return DD_OK;
752 }
753
754 HRESULT WINAPI
755 Main_IDirect3DExecuteBufferImpl_1_GetExecuteData(LPDIRECT3DEXECUTEBUFFER iface,
756                                                  LPD3DEXECUTEDATA lpData)
757 {
758     ICOM_THIS_FROM(IDirect3DExecuteBufferImpl, IDirect3DExecuteBuffer, iface);
759     DWORD dwSize;
760     TRACE("(%p/%p)->(%p): stub!\n", This, iface, lpData);
761
762     dwSize = lpData->dwSize;
763     memset(lpData, 0, dwSize);
764     memcpy(lpData, &This->data, dwSize);
765
766     if (TRACE_ON(ddraw)) {
767         TRACE("Returning data : \n");
768         _dump_executedata(lpData);
769     }
770
771     return DD_OK;
772 }
773
774 HRESULT WINAPI
775 Main_IDirect3DExecuteBufferImpl_1_Validate(LPDIRECT3DEXECUTEBUFFER iface,
776                                            LPDWORD lpdwOffset,
777                                            LPD3DVALIDATECALLBACK lpFunc,
778                                            LPVOID lpUserArg,
779                                            DWORD dwReserved)
780 {
781     ICOM_THIS_FROM(IDirect3DExecuteBufferImpl, IDirect3DExecuteBuffer, iface);
782     FIXME("(%p/%p)->(%p,%p,%p,%08lx): stub!\n", This, iface, lpdwOffset, lpFunc, lpUserArg, dwReserved);
783     return DD_OK;
784 }
785
786 HRESULT WINAPI
787 Main_IDirect3DExecuteBufferImpl_1_Optimize(LPDIRECT3DEXECUTEBUFFER iface,
788                                            DWORD dwDummy)
789 {
790     ICOM_THIS_FROM(IDirect3DExecuteBufferImpl, IDirect3DExecuteBuffer, iface);
791     TRACE("(%p/%p)->(%08lx) no-op...\n", This, iface, dwDummy);
792     return DD_OK;
793 }
794
795 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
796 # define XCAST(fun)     (typeof(VTABLE_IDirect3DExecuteBuffer.fun))
797 #else
798 # define XCAST(fun)     (void*)
799 #endif
800
801 ICOM_VTABLE(IDirect3DExecuteBuffer) VTABLE_IDirect3DExecuteBuffer =
802 {
803     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
804     XCAST(QueryInterface) Main_IDirect3DExecuteBufferImpl_1_QueryInterface,
805     XCAST(AddRef) Main_IDirect3DExecuteBufferImpl_1_AddRef,
806     XCAST(Release) Main_IDirect3DExecuteBufferImpl_1_Release,
807     XCAST(Initialize) Main_IDirect3DExecuteBufferImpl_1_Initialize,
808     XCAST(Lock) Main_IDirect3DExecuteBufferImpl_1_Lock,
809     XCAST(Unlock) Main_IDirect3DExecuteBufferImpl_1_Unlock,
810     XCAST(SetExecuteData) Main_IDirect3DExecuteBufferImpl_1_SetExecuteData,
811     XCAST(GetExecuteData) Main_IDirect3DExecuteBufferImpl_1_GetExecuteData,
812     XCAST(Validate) Main_IDirect3DExecuteBufferImpl_1_Validate,
813     XCAST(Optimize) Main_IDirect3DExecuteBufferImpl_1_Optimize,
814 };
815
816 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
817 #undef XCAST
818 #endif
819
820
821 HRESULT d3dexecutebuffer_create(IDirect3DExecuteBufferImpl **obj, IDirect3DImpl *d3d, IDirect3DDeviceImpl *d3ddev, LPD3DEXECUTEBUFFERDESC lpDesc)
822 {
823     IDirect3DExecuteBufferImpl* object;
824
825     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DExecuteBufferImpl));
826
827     ICOM_INIT_INTERFACE(object, IDirect3DExecuteBuffer, VTABLE_IDirect3DExecuteBuffer);
828     
829     object->ref = 1;
830     object->d3d = d3d;
831     object->d3ddev = d3ddev;
832
833     /* Initializes memory */
834     memcpy(&object->desc, lpDesc, lpDesc->dwSize);
835
836     /* No buffer given */
837     if ((object->desc.dwFlags & D3DDEB_LPDATA) == 0)
838         object->desc.lpData = NULL;
839
840     /* No buffer size given */
841     if ((lpDesc->dwFlags & D3DDEB_BUFSIZE) == 0)
842         object->desc.dwBufferSize = 0;
843
844     /* Create buffer if asked */
845     if ((object->desc.lpData == NULL) && (object->desc.dwBufferSize > 0)) {
846         object->need_free = TRUE;
847         object->desc.lpData = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,object->desc.dwBufferSize);
848     } else {
849         object->need_free = FALSE;
850     }
851
852     /* No vertices for the moment */
853     object->vertex_data = NULL;
854
855     object->desc.dwFlags |= D3DDEB_LPDATA;
856
857     object->execute = execute;
858
859     *obj = object;
860     
861     TRACE(" creating implementation at %p.\n", *obj);
862     
863     return DD_OK;
864 }