Added version information.
[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(" Branch to %ld\n", ci->dwOffset);
599                             instr = (char*)current + ci->dwOffset;
600                             break;
601                         }
602                     } else {
603                         if (ci->bNegate) {
604                             TRACE(" Branch to %ld\n", ci->dwOffset);
605                             instr = (char*)current + ci->dwOffset;
606                             break;
607                         }
608                     }
609
610                     instr += size;
611                 }
612             } break;
613
614             case D3DOP_SPAN: {
615                 WARN("SPAN-s           (%d)\n", count);
616
617                 instr += count * size;
618             } break;
619
620             case D3DOP_SETSTATUS: {
621                 int i;
622                 TRACE("SETSTATUS        (%d)\n", count);
623
624                 for (i = 0; i < count; i++) {
625                     LPD3DSTATUS ci = (LPD3DSTATUS) instr;
626                     
627                     This->data.dsStatus = *ci;
628
629                     instr += size;
630                 }
631             } break;
632
633             default:
634                 ERR("Unhandled OpCode %d !!!\n",current->bOpcode);
635                 /* Try to save ... */
636                 instr += count * size;
637                 break;
638         }
639     }
640
641 end_of_buffer:
642     LEAVE_GL();
643 }
644
645 HRESULT WINAPI
646 Main_IDirect3DExecuteBufferImpl_1_QueryInterface(LPDIRECT3DEXECUTEBUFFER iface,
647                                                  REFIID riid,
648                                                  LPVOID* obp)
649 {
650     ICOM_THIS_FROM(IDirect3DExecuteBufferImpl, IDirect3DExecuteBuffer, iface);
651     TRACE("(%p/%p)->(%s,%p)\n", This, iface, debugstr_guid(riid), obp);
652
653     *obp = NULL;
654
655     if ( IsEqualGUID( &IID_IUnknown,  riid ) ) {
656         IDirect3DExecuteBuffer_AddRef(ICOM_INTERFACE(This, IDirect3DExecuteBuffer));
657         *obp = iface;
658         TRACE("  Creating IUnknown interface at %p.\n", *obp);
659         return S_OK;
660     }
661     if ( IsEqualGUID( &IID_IDirect3DMaterial, riid ) ) {
662         IDirect3DExecuteBuffer_AddRef(ICOM_INTERFACE(This, IDirect3DExecuteBuffer));
663         *obp = ICOM_INTERFACE(This, IDirect3DExecuteBuffer);
664         TRACE("  Creating IDirect3DExecuteBuffer interface %p\n", *obp);
665         return S_OK;
666     }
667     FIXME("(%p): interface for IID %s NOT found!\n", This, debugstr_guid(riid));
668     return OLE_E_ENUM_NOMORE;
669 }
670
671 ULONG WINAPI
672 Main_IDirect3DExecuteBufferImpl_1_AddRef(LPDIRECT3DEXECUTEBUFFER iface)
673 {
674     ICOM_THIS_FROM(IDirect3DExecuteBufferImpl, IDirect3DExecuteBuffer, iface);
675     FIXME("(%p/%p)->()incrementing from %lu.\n", This, iface, This->ref );
676     return ++(This->ref);
677 }
678
679 ULONG WINAPI
680 Main_IDirect3DExecuteBufferImpl_1_Release(LPDIRECT3DEXECUTEBUFFER iface)
681 {
682     ICOM_THIS_FROM(IDirect3DExecuteBufferImpl, IDirect3DExecuteBuffer, iface);
683     TRACE("(%p/%p)->()decrementing from %lu.\n", This, iface, This->ref);
684     if (!--(This->ref)) {
685         if ((This->desc.lpData != NULL) && This->need_free)
686             HeapFree(GetProcessHeap(),0,This->desc.lpData);
687         if (This->vertex_data != NULL)
688             HeapFree(GetProcessHeap(),0,This->vertex_data);
689         HeapFree(GetProcessHeap(),0,This);
690         return 0;
691     }
692
693     return This->ref;
694 }
695
696 HRESULT WINAPI
697 Main_IDirect3DExecuteBufferImpl_1_Initialize(LPDIRECT3DEXECUTEBUFFER iface,
698                                              LPDIRECT3DDEVICE lpDirect3DDevice,
699                                              LPD3DEXECUTEBUFFERDESC lpDesc)
700 {
701     ICOM_THIS_FROM(IDirect3DExecuteBufferImpl, IDirect3DExecuteBuffer, iface);
702     TRACE("(%p/%p)->(%p,%p) no-op....\n", This, iface, lpDirect3DDevice, lpDesc);
703     return DD_OK;
704 }
705
706 HRESULT WINAPI
707 Main_IDirect3DExecuteBufferImpl_1_Lock(LPDIRECT3DEXECUTEBUFFER iface,
708                                        LPD3DEXECUTEBUFFERDESC lpDesc)
709 {
710     ICOM_THIS_FROM(IDirect3DExecuteBufferImpl, IDirect3DExecuteBuffer, iface);
711     DWORD dwSize;
712     TRACE("(%p/%p)->(%p)\n", This, iface, lpDesc);
713
714     dwSize = lpDesc->dwSize;
715     memset(lpDesc, 0, dwSize);
716     memcpy(lpDesc, &This->desc, dwSize);
717     
718     if (TRACE_ON(ddraw)) {
719         TRACE("  Returning description : \n");
720         _dump_D3DEXECUTEBUFFERDESC(lpDesc);
721     }
722     return DD_OK;
723 }
724
725 HRESULT WINAPI
726 Main_IDirect3DExecuteBufferImpl_1_Unlock(LPDIRECT3DEXECUTEBUFFER iface)
727 {
728     ICOM_THIS_FROM(IDirect3DExecuteBufferImpl, IDirect3DExecuteBuffer, iface);
729     TRACE("(%p/%p)->() no-op...\n", This, iface);
730     return DD_OK;
731 }
732
733 HRESULT WINAPI
734 Main_IDirect3DExecuteBufferImpl_1_SetExecuteData(LPDIRECT3DEXECUTEBUFFER iface,
735                                                  LPD3DEXECUTEDATA lpData)
736 {
737     ICOM_THIS_FROM(IDirect3DExecuteBufferImpl, IDirect3DExecuteBuffer, iface);
738     DWORD nbvert;
739     TRACE("(%p/%p)->(%p)\n", This, iface, lpData);
740
741     memcpy(&This->data, lpData, lpData->dwSize);
742
743     /* Get the number of vertices in the execute buffer */
744     nbvert = This->data.dwVertexCount;
745     
746     /* Prepares the transformed vertex buffer */
747     if (This->vertex_data != NULL)
748         HeapFree(GetProcessHeap(), 0, This->vertex_data);
749     This->vertex_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nbvert * sizeof(OGL_Vertex));
750
751     if (TRACE_ON(ddraw)) {
752         _dump_executedata(lpData);
753     }
754
755     return DD_OK;
756 }
757
758 HRESULT WINAPI
759 Main_IDirect3DExecuteBufferImpl_1_GetExecuteData(LPDIRECT3DEXECUTEBUFFER iface,
760                                                  LPD3DEXECUTEDATA lpData)
761 {
762     ICOM_THIS_FROM(IDirect3DExecuteBufferImpl, IDirect3DExecuteBuffer, iface);
763     DWORD dwSize;
764     TRACE("(%p/%p)->(%p): stub!\n", This, iface, lpData);
765
766     dwSize = lpData->dwSize;
767     memset(lpData, 0, dwSize);
768     memcpy(lpData, &This->data, dwSize);
769
770     if (TRACE_ON(ddraw)) {
771         TRACE("Returning data : \n");
772         _dump_executedata(lpData);
773     }
774
775     return DD_OK;
776 }
777
778 HRESULT WINAPI
779 Main_IDirect3DExecuteBufferImpl_1_Validate(LPDIRECT3DEXECUTEBUFFER iface,
780                                            LPDWORD lpdwOffset,
781                                            LPD3DVALIDATECALLBACK lpFunc,
782                                            LPVOID lpUserArg,
783                                            DWORD dwReserved)
784 {
785     ICOM_THIS_FROM(IDirect3DExecuteBufferImpl, IDirect3DExecuteBuffer, iface);
786     FIXME("(%p/%p)->(%p,%p,%p,%08lx): stub!\n", This, iface, lpdwOffset, lpFunc, lpUserArg, dwReserved);
787     return DD_OK;
788 }
789
790 HRESULT WINAPI
791 Main_IDirect3DExecuteBufferImpl_1_Optimize(LPDIRECT3DEXECUTEBUFFER iface,
792                                            DWORD dwDummy)
793 {
794     ICOM_THIS_FROM(IDirect3DExecuteBufferImpl, IDirect3DExecuteBuffer, iface);
795     TRACE("(%p/%p)->(%08lx) no-op...\n", This, iface, dwDummy);
796     return DD_OK;
797 }
798
799 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
800 # define XCAST(fun)     (typeof(VTABLE_IDirect3DExecuteBuffer.fun))
801 #else
802 # define XCAST(fun)     (void*)
803 #endif
804
805 ICOM_VTABLE(IDirect3DExecuteBuffer) VTABLE_IDirect3DExecuteBuffer =
806 {
807     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
808     XCAST(QueryInterface) Main_IDirect3DExecuteBufferImpl_1_QueryInterface,
809     XCAST(AddRef) Main_IDirect3DExecuteBufferImpl_1_AddRef,
810     XCAST(Release) Main_IDirect3DExecuteBufferImpl_1_Release,
811     XCAST(Initialize) Main_IDirect3DExecuteBufferImpl_1_Initialize,
812     XCAST(Lock) Main_IDirect3DExecuteBufferImpl_1_Lock,
813     XCAST(Unlock) Main_IDirect3DExecuteBufferImpl_1_Unlock,
814     XCAST(SetExecuteData) Main_IDirect3DExecuteBufferImpl_1_SetExecuteData,
815     XCAST(GetExecuteData) Main_IDirect3DExecuteBufferImpl_1_GetExecuteData,
816     XCAST(Validate) Main_IDirect3DExecuteBufferImpl_1_Validate,
817     XCAST(Optimize) Main_IDirect3DExecuteBufferImpl_1_Optimize,
818 };
819
820 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
821 #undef XCAST
822 #endif
823
824
825 HRESULT d3dexecutebuffer_create(IDirect3DExecuteBufferImpl **obj, IDirect3DImpl *d3d, IDirect3DDeviceImpl *d3ddev, LPD3DEXECUTEBUFFERDESC lpDesc)
826 {
827     IDirect3DExecuteBufferImpl* object;
828
829     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DExecuteBufferImpl));
830
831     ICOM_INIT_INTERFACE(object, IDirect3DExecuteBuffer, VTABLE_IDirect3DExecuteBuffer);
832     
833     object->ref = 1;
834     object->d3d = d3d;
835     object->d3ddev = d3ddev;
836
837     /* Initializes memory */
838     memcpy(&object->desc, lpDesc, lpDesc->dwSize);
839
840     /* No buffer given */
841     if ((object->desc.dwFlags & D3DDEB_LPDATA) == 0)
842         object->desc.lpData = NULL;
843
844     /* No buffer size given */
845     if ((lpDesc->dwFlags & D3DDEB_BUFSIZE) == 0)
846         object->desc.dwBufferSize = 0;
847
848     /* Create buffer if asked */
849     if ((object->desc.lpData == NULL) && (object->desc.dwBufferSize > 0)) {
850         object->need_free = TRUE;
851         object->desc.lpData = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,object->desc.dwBufferSize);
852     } else {
853         object->need_free = FALSE;
854     }
855
856     /* No vertices for the moment */
857     object->vertex_data = NULL;
858
859     object->desc.dwFlags |= D3DDEB_LPDATA;
860
861     object->execute = execute;
862
863     *obj = object;
864     
865     TRACE(" creating implementation at %p.\n", *obj);
866     
867     return DD_OK;
868 }