- beginning of implementation of Direct3D2 (DX 5.0) and associated classes
- some basic code for Direct3D and Direct3DExecuteBuffer (DX 3.0)
- added stretching to Blt function
diff --git a/graphics/d3dexecutebuffer.c b/graphics/d3dexecutebuffer.c
new file mode 100644
index 0000000..4fe4f04
--- /dev/null
+++ b/graphics/d3dexecutebuffer.c
@@ -0,0 +1,578 @@
+/* Direct3D ExecuteBuffer
+ (c) 1998 Lionel ULMER
+
+ This files contains the implementation of Direct3DExecuteBuffer. */
+
+
+#include "config.h"
+#include "windows.h"
+#include "wintypes.h"
+#include "winerror.h"
+#include "interfaces.h"
+#include "heap.h"
+#include "ddraw.h"
+#include "d3d.h"
+#include "debug.h"
+
+#include "d3d_private.h"
+
+#ifdef HAVE_MESAGL
+
+static IDirect3DExecuteBuffer_VTable executebuffer_vtable;
+
+/*******************************************************************************
+ * ExecuteBuffer static functions
+ */
+void _dump_d3dstatus(LPD3DSTATUS lpStatus) {
+
+}
+
+void _dump_executedata(LPD3DEXECUTEDATA lpData) {
+ DUMP("dwSize : %ld\n", lpData->dwSize);
+ DUMP("Vertex Offset : %ld Count : %ld\n", lpData->dwVertexOffset, lpData->dwVertexCount);
+ DUMP("Instruction Offset : %ld Length : %ld\n", lpData->dwInstructionOffset, lpData->dwInstructionLength);
+ DUMP("HVertex Offset : %ld\n", lpData->dwHVertexOffset);
+ _dump_d3dstatus(&(lpData->dsStatus));
+}
+
+#define DO_VERTEX(index) \
+ glNormal3f(tvert[index].nx.nx, \
+ tvert[index].ny.ny, \
+ tvert[index].nz.nz); \
+ glVertex3f(tvert[index].x.x, \
+ tvert[index].y.y, \
+ tvert[index].z.z);
+
+
+static void execute(LPDIRECT3DEXECUTEBUFFER lpBuff,
+ LPDIRECT3DDEVICE dev,
+ LPDIRECT3DVIEWPORT vp) {
+ DWORD bs = lpBuff->desc.dwBufferSize;
+ DWORD vs = lpBuff->data.dwVertexOffset;
+ DWORD vc = lpBuff->data.dwVertexCount;
+ DWORD is = lpBuff->data.dwInstructionOffset;
+ DWORD il = lpBuff->data.dwInstructionLength;
+
+ unsigned char *instr = lpBuff->desc.lpData + is;
+ LPD3DVERTEX vert = (LPD3DVERTEX) (lpBuff->desc.lpData + vs);
+ LPD3DVERTEX tvert = lpBuff->vertex_data;
+ OpenGL_IDirect3DDevice *odev = (OpenGL_IDirect3DDevice *) dev;
+
+ TRACE(ddraw, "ExecuteData : \n");
+ _dump_executedata(&(lpBuff->data));
+
+ while (1) {
+ LPD3DINSTRUCTION current = (LPD3DINSTRUCTION) instr;
+ BYTE size;
+ WORD count;
+
+ count = current->wCount;
+ size = current->bSize;
+ instr += sizeof(D3DINSTRUCTION);
+
+ switch (current->bOpcode) {
+ case D3DOP_POINT: {
+ TRACE(ddraw, "POINT-s (%d)\n", count);
+
+ instr += count * size;
+ } break;
+
+ case D3DOP_LINE: {
+ TRACE(ddraw, "LINE-s (%d)\n", count);
+
+ instr += count * size;
+ } break;
+
+ case D3DOP_TRIANGLE: {
+ int i;
+ TRACE(ddraw, "TRIANGLE (%d)\n", count);
+
+ /* Use given matrixes */
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity(); /* The model transformation was done during the
+ transformation phase */
+ glMatrixMode(GL_PROJECTION);
+ glLoadMatrixf((float *) odev->proj_mat);
+ glMultMatrixf((float *) odev->view_mat);
+
+ for (i = 0; i < count; i++) {
+ LPD3DTRIANGLE ci = (LPD3DTRIANGLE) instr;
+
+ TRACE(ddraw, " v1: %d v2: %d v3: %d\n",
+ ci->v1.v1, ci->v2.v2, ci->v3.v3);
+ TRACE(ddraw, " Flags : ");
+ if (TRACE_ON(ddraw)) {
+ /* Wireframe */
+ if (ci->wFlags & D3DTRIFLAG_EDGEENABLE1)
+ DUMP("EDGEENABLE1 ");
+ if (ci->wFlags & D3DTRIFLAG_EDGEENABLE2)
+ DUMP("EDGEENABLE2 ");
+ if (ci->wFlags & D3DTRIFLAG_EDGEENABLE1)
+ DUMP("EDGEENABLE3 ");
+
+ /* Strips / Fans */
+ if (ci->wFlags == D3DTRIFLAG_EVEN)
+ DUMP("EVEN ");
+ if (ci->wFlags == D3DTRIFLAG_ODD)
+ DUMP("ODD ");
+ if (ci->wFlags == D3DTRIFLAG_START)
+ DUMP("START ");
+ if ((ci->wFlags > 0) && (ci->wFlags < 30))
+ DUMP("STARTFLAT(%d) ", ci->wFlags);
+ DUMP("\n");
+ }
+
+ glBegin(GL_TRIANGLES); {
+ DO_VERTEX(ci->v1.v1);
+ DO_VERTEX(ci->v2.v2);
+ DO_VERTEX(ci->v3.v3);
+ } glEnd();
+
+ instr += size;
+ }
+ } break;
+
+ case D3DOP_MATRIXLOAD: {
+ TRACE(ddraw, "MATRIXLOAD-s (%d)\n", count);
+
+ instr += count * size;
+ } break;
+
+ case D3DOP_MATRIXMULTIPLY: {
+ int i;
+ TRACE(ddraw, "MATRIXMULTIPLY (%d)\n", count);
+
+ for (i = 0; i < count; i++) {
+ LPD3DMATRIXMULTIPLY ci = (LPD3DMATRIXMULTIPLY) instr;
+ LPD3DMATRIX a = (LPD3DMATRIX) ci->hDestMatrix;
+ LPD3DMATRIX b = (LPD3DMATRIX) ci->hSrcMatrix1;
+ LPD3DMATRIX c = (LPD3DMATRIX) ci->hSrcMatrix2;
+
+ TRACE(ddraw, " Dest : %08lx Src1 : %08lx Src2 : %08lx\n",
+ ci->hDestMatrix, ci->hSrcMatrix1, ci->hSrcMatrix2);
+
+ /* Do the multiplication..
+ As I am VERY lazy, I let OpenGL do the multiplication for me */
+ glMatrixMode(GL_PROJECTION);
+ /* Save the current matrix */
+ glPushMatrix();
+ /* Load Matrix one and do the multiplication */
+ glLoadMatrixf((float *) ci->hSrcMatrix1);
+ glMultMatrixf((float *) ci->hSrcMatrix2);
+ glGetFloatv(GL_PROJECTION_MATRIX, (float *) ci->hDestMatrix);
+ /* Restore the current matrix */
+ glPopMatrix();
+
+ instr += size;
+ }
+ } break;
+
+ case D3DOP_STATETRANSFORM: {
+ int i;
+ TRACE(ddraw, "STATETRANSFORM (%d)\n", count);
+
+ for (i = 0; i < count; i++) {
+ LPD3DSTATE ci = (LPD3DSTATE) instr;
+
+ /* Handle the state transform */
+ switch (ci->t.dtstTransformStateType) {
+ case D3DTRANSFORMSTATE_WORLD: {
+ TRACE(ddraw, " WORLD (%p)\n", (D3DMATRIX*) ci->v.dwArg[0]);
+ odev->world_mat = (D3DMATRIX*) ci->v.dwArg[0];
+ } break;
+
+ case D3DTRANSFORMSTATE_VIEW: {
+ TRACE(ddraw, " VIEW (%p)\n", (D3DMATRIX*) ci->v.dwArg[0]);
+ odev->view_mat = (D3DMATRIX*) ci->v.dwArg[0];
+ } break;
+
+ case D3DTRANSFORMSTATE_PROJECTION: {
+ TRACE(ddraw, " PROJECTION (%p)\n", (D3DMATRIX*) ci->v.dwArg[0]);
+ odev->proj_mat = (D3DMATRIX*) ci->v.dwArg[0];
+ } break;
+
+ default:
+ ERR(ddraw, " Unhandled state transformation !! (%d)\n", (int) ci->t.dtstTransformStateType);
+ break;
+
+ }
+
+ instr += size;
+ }
+ } break;
+
+ case D3DOP_STATELIGHT: {
+ int i;
+ TRACE(ddraw, "STATELIGHT (%d)\n", count);
+
+ for (i = 0; i < count; i++) {
+ LPD3DSTATE ci = (LPD3DSTATE) instr;
+
+ /* Handle the state transform */
+ switch (ci->t.dlstLightStateType) {
+ case D3DLIGHTSTATE_MATERIAL: {
+ LPDIRECT3DMATERIAL mat = (LPDIRECT3DMATERIAL) ci->v.dwArg[0];
+ TRACE(ddraw, " MATERIAL\n");
+
+ if (mat != NULL) {
+ mat->activate(mat);
+ } else {
+ TRACE(ddraw, " bad Material Handle\n");
+ }
+ } break ;
+
+ case D3DLIGHTSTATE_AMBIENT: {
+ float light[4];
+ DWORD dwLightState = ci->v.dwArg[0];
+ TRACE(ddraw, " AMBIENT\n");
+
+ light[0] = ((dwLightState >> 16) & 0xFF) / 255.0;
+ light[1] = ((dwLightState >> 8) & 0xFF) / 255.0;
+ light[2] = ((dwLightState >> 0) & 0xFF) / 255.0;
+ light[3] = 1.0;
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT, (float *) light);
+
+ TRACE(ddraw, " R:%02lx G:%02lx B:%02lx A:%02lx\n",
+ ((dwLightState >> 16) & 0xFF),
+ ((dwLightState >> 8) & 0xFF),
+ ((dwLightState >> 0) & 0xFF),
+ ((dwLightState >> 24) & 0xFF));
+ } break ;
+
+ case D3DLIGHTSTATE_COLORMODEL: {
+ TRACE(ddraw, " COLORMODEL\n");
+ } break ;
+
+ case D3DLIGHTSTATE_FOGMODE: {
+ TRACE(ddraw, " FOGMODE\n");
+ } break ;
+
+ case D3DLIGHTSTATE_FOGSTART: {
+ TRACE(ddraw, " FOGSTART\n");
+ } break ;
+
+ case D3DLIGHTSTATE_FOGEND: {
+ TRACE(ddraw, " FOGEND\n");
+ } break ;
+
+ case D3DLIGHTSTATE_FOGDENSITY: {
+ TRACE(ddraw, " FOGDENSITY\n");
+ } break ;
+
+ default:
+ ERR(ddraw, " Unhandled light state !! (%d)\n", (int) ci->t.dlstLightStateType);
+ break;
+ }
+ instr += size;
+ }
+ } break;
+
+ case D3DOP_STATERENDER: {
+ int i;
+ TRACE(ddraw, "STATERENDER (%d)\n", count);
+
+ for (i = 0; i < count; i++) {
+ LPD3DSTATE ci = (LPD3DSTATE) instr;
+
+ /* Handle the state transform */
+ set_render_state(ci->t.drstRenderStateType, ci->v.dwArg[0]);
+
+ instr += size;
+ }
+ } break;
+
+ case D3DOP_PROCESSVERTICES: {
+ int i;
+ TRACE(ddraw, "PROCESSVERTICES (%d)\n", count);
+
+ for (i = 0; i < count; i++) {
+ LPD3DPROCESSVERTICES ci = (LPD3DPROCESSVERTICES) instr;
+
+ TRACE(ddraw, " Start : %d Dest : %d Count : %ld\n",
+ ci->wStart, ci->wDest, ci->dwCount);
+ TRACE(ddraw, " Flags : ");
+ if (TRACE_ON(ddraw)) {
+ if (ci->dwFlags & D3DPROCESSVERTICES_COPY)
+ DUMP("COPY ");
+ if (ci->dwFlags & D3DPROCESSVERTICES_NOCOLOR)
+ DUMP("NOCOLOR ");
+ if (ci->dwFlags == D3DPROCESSVERTICES_OPMASK)
+ DUMP("OPMASK ");
+ if (ci->dwFlags & D3DPROCESSVERTICES_TRANSFORM)
+ DUMP("TRANSFORM ");
+ if (ci->dwFlags == D3DPROCESSVERTICES_TRANSFORMLIGHT)
+ DUMP("TRANSFORMLIGHT ");
+ if (ci->dwFlags & D3DPROCESSVERTICES_UPDATEEXTENTS)
+ DUMP("UPDATEEXTENTS ");
+ DUMP("\n");
+ }
+
+ /* This is where doing Direct3D on top on OpenGL is quite difficult.
+ This method transforms a set of vertices using the CURRENT state
+ (lighting, projection, ...) but does not rasterize them.
+ They will oinly be put on screen later (with the POINT / LINE and
+ TRIANGLE op-codes). The problem is that you can have a triangle
+ with each point having been transformed using another state...
+
+ In this implementation, I will emulate only ONE thing : each
+ vertex can have its own "WORLD" transformation (this is used in the
+ TWIST.EXE demo of the 5.2 SDK). I suppose that all vertices of the
+ execute buffer use the same state.
+
+ If I find applications that change other states, I will try to do a
+ more 'fine-tuned' state emulation (but I may become quite tricky if
+ it changes a light position in the middle of a triangle).
+
+ In this case, a 'direct' approach (i.e. without using OpenGL, but
+ writing our own 3D rasterizer) would be easier. */
+
+ /* The current method (with the hypothesis that only the WORLD matrix
+ will change between two points) is like this :
+ - I transform 'manually' all the vertices with the current WORLD
+ matrix and store them in the vertex buffer
+ - during the rasterization phase, the WORLD matrix will be set to
+ the Identity matrix */
+
+ /* Enough for the moment */
+ if (ci->dwFlags == D3DPROCESSVERTICES_TRANSFORMLIGHT) {
+ /* Enable lighting, so that when the rasterization will take place,
+ the correct LIGHTING state is active. */
+ glEnable(GL_LIGHTING);
+
+ /* */
+ }
+
+ instr += size;
+ }
+ } break;
+
+ case D3DOP_TEXTURELOAD: {
+ TRACE(ddraw, "TEXTURELOAD-s (%d)\n", count);
+
+ instr += count * size;
+ } break;
+
+ case D3DOP_EXIT: {
+ TRACE(ddraw, "EXIT (%d)\n", count);
+ /* We did this instruction */
+ instr += size;
+ /* Exit this loop */
+ goto end_of_buffer;
+ } break;
+
+ case D3DOP_BRANCHFORWARD: {
+ TRACE(ddraw, "BRANCHFORWARD-s (%d)\n", count);
+
+ instr += count * size;
+ } break;
+
+ case D3DOP_SPAN: {
+ TRACE(ddraw, "SPAN-s (%d)\n", count);
+
+ instr += count * size;
+ } break;
+
+ case D3DOP_SETSTATUS: {
+ TRACE(ddraw, "SETSTATUS-s (%d)\n", count);
+
+ instr += count * size;
+ } break;
+
+ default:
+ ERR(ddraw, "Unhandled OpCode !!!\n");
+ /* Try to save ... */
+ instr += count * size;
+ break;
+ }
+ }
+
+ end_of_buffer:
+}
+
+/*******************************************************************************
+ * ExecuteBuffer Creation functions
+ */
+LPDIRECT3DEXECUTEBUFFER d3dexecutebuffer_create(LPDIRECT3DDEVICE d3ddev, LPD3DEXECUTEBUFFERDESC lpDesc)
+{
+ LPDIRECT3DEXECUTEBUFFER eb;
+
+ eb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirect3DExecuteBuffer));
+ eb->ref = 1;
+ eb->lpvtbl = &executebuffer_vtable;
+ eb->d3ddev = d3ddev;
+
+ /* Initializes memory */
+ eb->desc = *lpDesc;
+
+ /* No buffer given */
+ if (!(eb->desc.dwFlags & D3DDEB_LPDATA))
+ eb->desc.lpData = NULL;
+
+ /* No buffer size given */
+ if (!(lpDesc->dwFlags & D3DDEB_BUFSIZE))
+ eb->desc.dwBufferSize = 0;
+
+ /* Create buffer if asked */
+ if ((eb->desc.lpData == NULL) && (eb->desc.dwBufferSize > 0)) {
+ eb->need_free = TRUE;
+ eb->desc.lpData = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,eb->desc.dwBufferSize);
+ } else {
+ eb->need_free = FALSE;
+ }
+
+ /* No vertices for the moment */
+ eb->vertex_data = NULL;
+
+ eb->desc.dwFlags |= D3DDEB_LPDATA;
+
+ eb->execute = execute;
+
+ return eb;
+}
+
+/*******************************************************************************
+ * IDirect3DLight methods
+ */
+
+static HRESULT WINAPI IDirect3DExecuteBuffer_QueryInterface(LPDIRECT3DEXECUTEBUFFER this,
+ REFIID riid,
+ LPVOID* ppvObj)
+{
+ char xrefiid[50];
+
+ WINE_StringFromCLSID((LPCLSID)riid,xrefiid);
+ FIXME(ddraw, "(%p)->(%s,%p): stub\n", this, xrefiid,ppvObj);
+
+ return S_OK;
+}
+
+
+
+static ULONG WINAPI IDirect3DExecuteBuffer_AddRef(LPDIRECT3DEXECUTEBUFFER this)
+{
+ TRACE(ddraw, "(%p)->()incrementing from %lu.\n", this, this->ref );
+
+ return ++(this->ref);
+}
+
+
+
+static ULONG WINAPI IDirect3DExecuteBuffer_Release(LPDIRECT3DEXECUTEBUFFER this)
+{
+ FIXME( ddraw, "(%p)->() decrementing from %lu.\n", this, this->ref );
+
+ if (!--(this->ref)) {
+ if ((this->desc.lpData != NULL) && this->need_free)
+ HeapFree(GetProcessHeap(),0,this->desc.lpData);
+
+ if (this->vertex_data != NULL)
+ HeapFree(GetProcessHeap(),0,this->vertex_data);
+
+ HeapFree(GetProcessHeap(),0,this);
+ return 0;
+ }
+
+ return this->ref;
+}
+
+static HRESULT WINAPI IDirect3DExecuteBuffer_Initialize(LPDIRECT3DEXECUTEBUFFER this,
+ LPDIRECT3DDEVICE lpDirect3DDevice,
+ LPD3DEXECUTEBUFFERDESC lpDesc)
+{
+ FIXME(ddraw, "(%p)->(%p,%p): stub\n", this, lpDirect3DDevice, lpDesc);
+
+ return DD_OK;
+}
+
+static HRESULT WINAPI IDirect3DExecuteBuffer_Lock(LPDIRECT3DEXECUTEBUFFER this,
+ LPD3DEXECUTEBUFFERDESC lpDesc)
+{
+ TRACE(ddraw, "(%p)->(%p)\n", this, lpDesc);
+
+ /* Copies the buffer description */
+ *lpDesc = this->desc;
+
+ return DD_OK;
+}
+
+static HRESULT WINAPI IDirect3DExecuteBuffer_Unlock(LPDIRECT3DEXECUTEBUFFER this)
+{
+ TRACE(ddraw, "(%p)->()\n", this);
+
+ return DD_OK;
+}
+
+static HRESULT WINAPI IDirect3DExecuteBuffer_SetExecuteData(LPDIRECT3DEXECUTEBUFFER this,
+ LPD3DEXECUTEDATA lpData)
+{
+ DWORD nbvert;
+
+ TRACE(ddraw, "(%p)->(%p)\n", this, lpData);
+
+ this->data = *lpData;
+
+ /* Get the number of vertices in the execute buffer */
+ nbvert = this->data.dwVertexCount;
+
+ /* Prepares the transformed vertex buffer */
+ if (this->vertex_data != NULL)
+ HeapFree(GetProcessHeap(), 0, this->vertex_data);
+ this->vertex_data = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,nbvert * sizeof(D3DVERTEX));
+
+
+ if (TRACE_ON(ddraw)) {
+ _dump_executedata(lpData);
+ }
+
+ return DD_OK;
+}
+
+static HRESULT WINAPI IDirect3DExecuteBuffer_GetExecuteData(LPDIRECT3DEXECUTEBUFFER this,
+ LPD3DEXECUTEDATA lpData)
+{
+ TRACE(ddraw, "(%p)->(%p): stub\n", this, lpData);
+
+ *lpData = this->data;
+
+ return DD_OK;
+}
+
+static HRESULT WINAPI IDirect3DExecuteBuffer_Validate(LPDIRECT3DEXECUTEBUFFER this,
+ LPDWORD lpdwOffset,
+ LPD3DVALIDATECALLBACK lpFunc,
+ LPVOID lpUserArg,
+ DWORD dwReserved)
+{
+ TRACE(ddraw, "(%p)->(%p,%p,%p,%lu)\n", this, lpdwOffset, lpFunc, lpUserArg, dwReserved);
+
+ return DD_OK;
+}
+
+static HRESULT WINAPI IDirect3DExecuteBuffer_Optimize(LPDIRECT3DEXECUTEBUFFER this,
+ DWORD dwReserved)
+{
+ TRACE(ddraw, "(%p)->(%lu)\n", this, dwReserved);
+
+ return DD_OK;
+}
+
+
+/*******************************************************************************
+ * IDirect3DLight VTable
+ */
+static IDirect3DExecuteBuffer_VTable executebuffer_vtable = {
+ /*** IUnknown methods ***/
+ IDirect3DExecuteBuffer_QueryInterface,
+ IDirect3DExecuteBuffer_AddRef,
+ IDirect3DExecuteBuffer_Release,
+ /*** IDirect3DExecuteBuffer methods ***/
+ IDirect3DExecuteBuffer_Initialize,
+ IDirect3DExecuteBuffer_Lock,
+ IDirect3DExecuteBuffer_Unlock,
+ IDirect3DExecuteBuffer_SetExecuteData,
+ IDirect3DExecuteBuffer_GetExecuteData,
+ IDirect3DExecuteBuffer_Validate,
+ IDirect3DExecuteBuffer_Optimize
+};
+
+#endif /* HAVE_MESAGL */