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