1 /* Direct3D ExecuteBuffer
4 This files contains the implementation of Direct3DExecuteBuffer. */
11 #include "interfaces.h"
17 #include "d3d_private.h"
21 static IDirect3DExecuteBuffer_VTable executebuffer_vtable
;
23 /*******************************************************************************
24 * ExecuteBuffer static functions
26 void _dump_d3dstatus(LPD3DSTATUS lpStatus
) {
30 void _dump_executedata(LPD3DEXECUTEDATA lpData
) {
31 DUMP("dwSize : %ld\n", lpData
->dwSize
);
32 DUMP("Vertex Offset : %ld Count : %ld\n", lpData
->dwVertexOffset
, lpData
->dwVertexCount
);
33 DUMP("Instruction Offset : %ld Length : %ld\n", lpData
->dwInstructionOffset
, lpData
->dwInstructionLength
);
34 DUMP("HVertex Offset : %ld\n", lpData
->dwHVertexOffset
);
35 _dump_d3dstatus(&(lpData
->dsStatus
));
38 #define DO_VERTEX(index) \
39 glNormal3f(tvert[index].nx.nx, \
41 tvert[index].nz.nz); \
42 glVertex3f(tvert[index].x.x, \
47 static void execute(LPDIRECT3DEXECUTEBUFFER lpBuff
,
49 LPDIRECT3DVIEWPORT vp
) {
50 DWORD bs
= lpBuff
->desc
.dwBufferSize
;
51 DWORD vs
= lpBuff
->data
.dwVertexOffset
;
52 DWORD vc
= lpBuff
->data
.dwVertexCount
;
53 DWORD is
= lpBuff
->data
.dwInstructionOffset
;
54 DWORD il
= lpBuff
->data
.dwInstructionLength
;
56 unsigned char *instr
= lpBuff
->desc
.lpData
+ is
;
57 LPD3DVERTEX vert
= (LPD3DVERTEX
) (lpBuff
->desc
.lpData
+ vs
);
58 LPD3DVERTEX tvert
= lpBuff
->vertex_data
;
59 OpenGL_IDirect3DDevice
*odev
= (OpenGL_IDirect3DDevice
*) dev
;
61 TRACE(ddraw
, "ExecuteData : \n");
62 _dump_executedata(&(lpBuff
->data
));
65 LPD3DINSTRUCTION current
= (LPD3DINSTRUCTION
) instr
;
69 count
= current
->wCount
;
70 size
= current
->bSize
;
71 instr
+= sizeof(D3DINSTRUCTION
);
73 switch (current
->bOpcode
) {
75 TRACE(ddraw
, "POINT-s (%d)\n", count
);
77 instr
+= count
* size
;
81 TRACE(ddraw
, "LINE-s (%d)\n", count
);
83 instr
+= count
* size
;
86 case D3DOP_TRIANGLE
: {
88 TRACE(ddraw
, "TRIANGLE (%d)\n", count
);
90 /* Use given matrixes */
91 glMatrixMode(GL_MODELVIEW
);
92 glLoadIdentity(); /* The model transformation was done during the
93 transformation phase */
94 glMatrixMode(GL_PROJECTION
);
95 glLoadMatrixf((float *) odev
->proj_mat
);
96 glMultMatrixf((float *) odev
->view_mat
);
98 for (i
= 0; i
< count
; i
++) {
99 LPD3DTRIANGLE ci
= (LPD3DTRIANGLE
) instr
;
101 TRACE(ddraw
, " v1: %d v2: %d v3: %d\n",
102 ci
->v1
.v1
, ci
->v2
.v2
, ci
->v3
.v3
);
103 TRACE(ddraw
, " Flags : ");
104 if (TRACE_ON(ddraw
)) {
106 if (ci
->wFlags
& D3DTRIFLAG_EDGEENABLE1
)
107 DUMP("EDGEENABLE1 ");
108 if (ci
->wFlags
& D3DTRIFLAG_EDGEENABLE2
)
109 DUMP("EDGEENABLE2 ");
110 if (ci
->wFlags
& D3DTRIFLAG_EDGEENABLE1
)
111 DUMP("EDGEENABLE3 ");
114 if (ci
->wFlags
== D3DTRIFLAG_EVEN
)
116 if (ci
->wFlags
== D3DTRIFLAG_ODD
)
118 if (ci
->wFlags
== D3DTRIFLAG_START
)
120 if ((ci
->wFlags
> 0) && (ci
->wFlags
< 30))
121 DUMP("STARTFLAT(%d) ", ci
->wFlags
);
125 glBegin(GL_TRIANGLES
); {
126 DO_VERTEX(ci
->v1
.v1
);
127 DO_VERTEX(ci
->v2
.v2
);
128 DO_VERTEX(ci
->v3
.v3
);
135 case D3DOP_MATRIXLOAD
: {
136 TRACE(ddraw
, "MATRIXLOAD-s (%d)\n", count
);
138 instr
+= count
* size
;
141 case D3DOP_MATRIXMULTIPLY
: {
143 TRACE(ddraw
, "MATRIXMULTIPLY (%d)\n", count
);
145 for (i
= 0; i
< count
; i
++) {
146 LPD3DMATRIXMULTIPLY ci
= (LPD3DMATRIXMULTIPLY
) instr
;
147 LPD3DMATRIX a
= (LPD3DMATRIX
) ci
->hDestMatrix
;
148 LPD3DMATRIX b
= (LPD3DMATRIX
) ci
->hSrcMatrix1
;
149 LPD3DMATRIX c
= (LPD3DMATRIX
) ci
->hSrcMatrix2
;
151 TRACE(ddraw
, " Dest : %08lx Src1 : %08lx Src2 : %08lx\n",
152 ci
->hDestMatrix
, ci
->hSrcMatrix1
, ci
->hSrcMatrix2
);
154 /* Do the multiplication..
155 As I am VERY lazy, I let OpenGL do the multiplication for me */
156 glMatrixMode(GL_PROJECTION
);
157 /* Save the current matrix */
159 /* Load Matrix one and do the multiplication */
160 glLoadMatrixf((float *) ci
->hSrcMatrix1
);
161 glMultMatrixf((float *) ci
->hSrcMatrix2
);
162 glGetFloatv(GL_PROJECTION_MATRIX
, (float *) ci
->hDestMatrix
);
163 /* Restore the current matrix */
170 case D3DOP_STATETRANSFORM
: {
172 TRACE(ddraw
, "STATETRANSFORM (%d)\n", count
);
174 for (i
= 0; i
< count
; i
++) {
175 LPD3DSTATE ci
= (LPD3DSTATE
) instr
;
177 /* Handle the state transform */
178 switch (ci
->t
.dtstTransformStateType
) {
179 case D3DTRANSFORMSTATE_WORLD
: {
180 TRACE(ddraw
, " WORLD (%p)\n", (D3DMATRIX
*) ci
->v
.dwArg
[0]);
181 odev
->world_mat
= (D3DMATRIX
*) ci
->v
.dwArg
[0];
184 case D3DTRANSFORMSTATE_VIEW
: {
185 TRACE(ddraw
, " VIEW (%p)\n", (D3DMATRIX
*) ci
->v
.dwArg
[0]);
186 odev
->view_mat
= (D3DMATRIX
*) ci
->v
.dwArg
[0];
189 case D3DTRANSFORMSTATE_PROJECTION
: {
190 TRACE(ddraw
, " PROJECTION (%p)\n", (D3DMATRIX
*) ci
->v
.dwArg
[0]);
191 odev
->proj_mat
= (D3DMATRIX
*) ci
->v
.dwArg
[0];
195 ERR(ddraw
, " Unhandled state transformation !! (%d)\n", (int) ci
->t
.dtstTransformStateType
);
204 case D3DOP_STATELIGHT
: {
206 TRACE(ddraw
, "STATELIGHT (%d)\n", count
);
208 for (i
= 0; i
< count
; i
++) {
209 LPD3DSTATE ci
= (LPD3DSTATE
) instr
;
211 /* Handle the state transform */
212 switch (ci
->t
.dlstLightStateType
) {
213 case D3DLIGHTSTATE_MATERIAL
: {
214 LPDIRECT3DMATERIAL mat
= (LPDIRECT3DMATERIAL
) ci
->v
.dwArg
[0];
215 TRACE(ddraw
, " MATERIAL\n");
220 TRACE(ddraw
, " bad Material Handle\n");
224 case D3DLIGHTSTATE_AMBIENT
: {
226 DWORD dwLightState
= ci
->v
.dwArg
[0];
227 TRACE(ddraw
, " AMBIENT\n");
229 light
[0] = ((dwLightState
>> 16) & 0xFF) / 255.0;
230 light
[1] = ((dwLightState
>> 8) & 0xFF) / 255.0;
231 light
[2] = ((dwLightState
>> 0) & 0xFF) / 255.0;
233 glLightModelfv(GL_LIGHT_MODEL_AMBIENT
, (float *) light
);
235 TRACE(ddraw
, " R:%02lx G:%02lx B:%02lx A:%02lx\n",
236 ((dwLightState
>> 16) & 0xFF),
237 ((dwLightState
>> 8) & 0xFF),
238 ((dwLightState
>> 0) & 0xFF),
239 ((dwLightState
>> 24) & 0xFF));
242 case D3DLIGHTSTATE_COLORMODEL
: {
243 TRACE(ddraw
, " COLORMODEL\n");
246 case D3DLIGHTSTATE_FOGMODE
: {
247 TRACE(ddraw
, " FOGMODE\n");
250 case D3DLIGHTSTATE_FOGSTART
: {
251 TRACE(ddraw
, " FOGSTART\n");
254 case D3DLIGHTSTATE_FOGEND
: {
255 TRACE(ddraw
, " FOGEND\n");
258 case D3DLIGHTSTATE_FOGDENSITY
: {
259 TRACE(ddraw
, " FOGDENSITY\n");
263 ERR(ddraw
, " Unhandled light state !! (%d)\n", (int) ci
->t
.dlstLightStateType
);
270 case D3DOP_STATERENDER
: {
272 TRACE(ddraw
, "STATERENDER (%d)\n", count
);
274 for (i
= 0; i
< count
; i
++) {
275 LPD3DSTATE ci
= (LPD3DSTATE
) instr
;
277 /* Handle the state transform */
278 set_render_state(ci
->t
.drstRenderStateType
, ci
->v
.dwArg
[0], &(odev
->rs
));
284 case D3DOP_PROCESSVERTICES
: {
286 TRACE(ddraw
, "PROCESSVERTICES (%d)\n", count
);
288 for (i
= 0; i
< count
; i
++) {
289 LPD3DPROCESSVERTICES ci
= (LPD3DPROCESSVERTICES
) instr
;
291 TRACE(ddraw
, " Start : %d Dest : %d Count : %ld\n",
292 ci
->wStart
, ci
->wDest
, ci
->dwCount
);
293 TRACE(ddraw
, " Flags : ");
294 if (TRACE_ON(ddraw
)) {
295 if (ci
->dwFlags
& D3DPROCESSVERTICES_COPY
)
297 if (ci
->dwFlags
& D3DPROCESSVERTICES_NOCOLOR
)
299 if (ci
->dwFlags
== D3DPROCESSVERTICES_OPMASK
)
301 if (ci
->dwFlags
& D3DPROCESSVERTICES_TRANSFORM
)
303 if (ci
->dwFlags
== D3DPROCESSVERTICES_TRANSFORMLIGHT
)
304 DUMP("TRANSFORMLIGHT ");
305 if (ci
->dwFlags
& D3DPROCESSVERTICES_UPDATEEXTENTS
)
306 DUMP("UPDATEEXTENTS ");
310 /* This is where doing Direct3D on top on OpenGL is quite difficult.
311 This method transforms a set of vertices using the CURRENT state
312 (lighting, projection, ...) but does not rasterize them.
313 They will oinly be put on screen later (with the POINT / LINE and
314 TRIANGLE op-codes). The problem is that you can have a triangle
315 with each point having been transformed using another state...
317 In this implementation, I will emulate only ONE thing : each
318 vertex can have its own "WORLD" transformation (this is used in the
319 TWIST.EXE demo of the 5.2 SDK). I suppose that all vertices of the
320 execute buffer use the same state.
322 If I find applications that change other states, I will try to do a
323 more 'fine-tuned' state emulation (but I may become quite tricky if
324 it changes a light position in the middle of a triangle).
326 In this case, a 'direct' approach (i.e. without using OpenGL, but
327 writing our own 3D rasterizer) would be easier. */
329 /* The current method (with the hypothesis that only the WORLD matrix
330 will change between two points) is like this :
331 - I transform 'manually' all the vertices with the current WORLD
332 matrix and store them in the vertex buffer
333 - during the rasterization phase, the WORLD matrix will be set to
334 the Identity matrix */
336 /* Enough for the moment */
337 if (ci
->dwFlags
== D3DPROCESSVERTICES_TRANSFORMLIGHT
) {
338 /* Enable lighting, so that when the rasterization will take place,
339 the correct LIGHTING state is active. */
340 glEnable(GL_LIGHTING
);
349 case D3DOP_TEXTURELOAD
: {
350 TRACE(ddraw
, "TEXTURELOAD-s (%d)\n", count
);
352 instr
+= count
* size
;
356 TRACE(ddraw
, "EXIT (%d)\n", count
);
357 /* We did this instruction */
363 case D3DOP_BRANCHFORWARD
: {
364 TRACE(ddraw
, "BRANCHFORWARD-s (%d)\n", count
);
366 instr
+= count
* size
;
370 TRACE(ddraw
, "SPAN-s (%d)\n", count
);
372 instr
+= count
* size
;
375 case D3DOP_SETSTATUS
: {
376 TRACE(ddraw
, "SETSTATUS-s (%d)\n", count
);
378 instr
+= count
* size
;
382 ERR(ddraw
, "Unhandled OpCode !!!\n");
383 /* Try to save ... */
384 instr
+= count
* size
;
392 /*******************************************************************************
393 * ExecuteBuffer Creation functions
395 LPDIRECT3DEXECUTEBUFFER
d3dexecutebuffer_create(LPDIRECT3DDEVICE d3ddev
, LPD3DEXECUTEBUFFERDESC lpDesc
)
397 LPDIRECT3DEXECUTEBUFFER eb
;
399 eb
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirect3DExecuteBuffer
));
401 eb
->lpvtbl
= &executebuffer_vtable
;
404 /* Initializes memory */
407 /* No buffer given */
408 if (!(eb
->desc
.dwFlags
& D3DDEB_LPDATA
))
409 eb
->desc
.lpData
= NULL
;
411 /* No buffer size given */
412 if (!(lpDesc
->dwFlags
& D3DDEB_BUFSIZE
))
413 eb
->desc
.dwBufferSize
= 0;
415 /* Create buffer if asked */
416 if ((eb
->desc
.lpData
== NULL
) && (eb
->desc
.dwBufferSize
> 0)) {
417 eb
->need_free
= TRUE
;
418 eb
->desc
.lpData
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,eb
->desc
.dwBufferSize
);
420 eb
->need_free
= FALSE
;
423 /* No vertices for the moment */
424 eb
->vertex_data
= NULL
;
426 eb
->desc
.dwFlags
|= D3DDEB_LPDATA
;
428 eb
->execute
= execute
;
433 /*******************************************************************************
434 * IDirect3DLight methods
437 static HRESULT WINAPI
IDirect3DExecuteBuffer_QueryInterface(LPDIRECT3DEXECUTEBUFFER
this,
443 WINE_StringFromCLSID((LPCLSID
)riid
,xrefiid
);
444 FIXME(ddraw
, "(%p)->(%s,%p): stub\n", this, xrefiid
,ppvObj
);
451 static ULONG WINAPI
IDirect3DExecuteBuffer_AddRef(LPDIRECT3DEXECUTEBUFFER
this)
453 TRACE(ddraw
, "(%p)->()incrementing from %lu.\n", this, this->ref
);
455 return ++(this->ref
);
460 static ULONG WINAPI
IDirect3DExecuteBuffer_Release(LPDIRECT3DEXECUTEBUFFER
this)
462 FIXME( ddraw
, "(%p)->() decrementing from %lu.\n", this, this->ref
);
464 if (!--(this->ref
)) {
465 if ((this->desc
.lpData
!= NULL
) && this->need_free
)
466 HeapFree(GetProcessHeap(),0,this->desc
.lpData
);
468 if (this->vertex_data
!= NULL
)
469 HeapFree(GetProcessHeap(),0,this->vertex_data
);
471 HeapFree(GetProcessHeap(),0,this);
478 static HRESULT WINAPI
IDirect3DExecuteBuffer_Initialize(LPDIRECT3DEXECUTEBUFFER
this,
479 LPDIRECT3DDEVICE lpDirect3DDevice
,
480 LPD3DEXECUTEBUFFERDESC lpDesc
)
482 FIXME(ddraw
, "(%p)->(%p,%p): stub\n", this, lpDirect3DDevice
, lpDesc
);
487 static HRESULT WINAPI
IDirect3DExecuteBuffer_Lock(LPDIRECT3DEXECUTEBUFFER
this,
488 LPD3DEXECUTEBUFFERDESC lpDesc
)
490 TRACE(ddraw
, "(%p)->(%p)\n", this, lpDesc
);
492 /* Copies the buffer description */
493 *lpDesc
= this->desc
;
498 static HRESULT WINAPI
IDirect3DExecuteBuffer_Unlock(LPDIRECT3DEXECUTEBUFFER
this)
500 TRACE(ddraw
, "(%p)->()\n", this);
505 static HRESULT WINAPI
IDirect3DExecuteBuffer_SetExecuteData(LPDIRECT3DEXECUTEBUFFER
this,
506 LPD3DEXECUTEDATA lpData
)
510 TRACE(ddraw
, "(%p)->(%p)\n", this, lpData
);
512 this->data
= *lpData
;
514 /* Get the number of vertices in the execute buffer */
515 nbvert
= this->data
.dwVertexCount
;
517 /* Prepares the transformed vertex buffer */
518 if (this->vertex_data
!= NULL
)
519 HeapFree(GetProcessHeap(), 0, this->vertex_data
);
520 this->vertex_data
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,nbvert
* sizeof(D3DVERTEX
));
523 if (TRACE_ON(ddraw
)) {
524 _dump_executedata(lpData
);
530 static HRESULT WINAPI
IDirect3DExecuteBuffer_GetExecuteData(LPDIRECT3DEXECUTEBUFFER
this,
531 LPD3DEXECUTEDATA lpData
)
533 TRACE(ddraw
, "(%p)->(%p): stub\n", this, lpData
);
535 *lpData
= this->data
;
540 static HRESULT WINAPI
IDirect3DExecuteBuffer_Validate(LPDIRECT3DEXECUTEBUFFER
this,
542 LPD3DVALIDATECALLBACK lpFunc
,
546 TRACE(ddraw
, "(%p)->(%p,%p,%p,%lu)\n", this, lpdwOffset
, lpFunc
, lpUserArg
, dwReserved
);
551 static HRESULT WINAPI
IDirect3DExecuteBuffer_Optimize(LPDIRECT3DEXECUTEBUFFER
this,
554 TRACE(ddraw
, "(%p)->(%lu)\n", this, dwReserved
);
560 /*******************************************************************************
561 * IDirect3DLight VTable
563 static IDirect3DExecuteBuffer_VTable executebuffer_vtable
= {
564 /*** IUnknown methods ***/
565 IDirect3DExecuteBuffer_QueryInterface
,
566 IDirect3DExecuteBuffer_AddRef
,
567 IDirect3DExecuteBuffer_Release
,
568 /*** IDirect3DExecuteBuffer methods ***/
569 IDirect3DExecuteBuffer_Initialize
,
570 IDirect3DExecuteBuffer_Lock
,
571 IDirect3DExecuteBuffer_Unlock
,
572 IDirect3DExecuteBuffer_SetExecuteData
,
573 IDirect3DExecuteBuffer_GetExecuteData
,
574 IDirect3DExecuteBuffer_Validate
,
575 IDirect3DExecuteBuffer_Optimize
578 #endif /* HAVE_MESAGL */