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