Implement Material, Clip plane and Light support plus
MultiplyTransform.
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 610e4c5..bd0867c 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -35,6 +35,94 @@
/**********************************************************
* Utility functions follow
**********************************************************/
+/* Convert the D3DLIGHT properties into equivalent gl lights */
+void setup_light(IWineD3DDevice *iface, LONG Index, PLIGHTINFOEL *lightInfo) {
+
+ float quad_att;
+ float colRGBA[] = {0.0, 0.0, 0.0, 0.0};
+ IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+
+ /* Light settings are affected by the model view in OpenGL, the View transform in direct3d*/
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadMatrixf((float *) &This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
+
+ /* Diffuse: */
+ colRGBA[0] = lightInfo->OriginalParms.Diffuse.r;
+ colRGBA[1] = lightInfo->OriginalParms.Diffuse.g;
+ colRGBA[2] = lightInfo->OriginalParms.Diffuse.b;
+ colRGBA[3] = lightInfo->OriginalParms.Diffuse.a;
+ glLightfv(GL_LIGHT0+Index, GL_DIFFUSE, colRGBA);
+ checkGLcall("glLightfv");
+
+ /* Specular */
+ colRGBA[0] = lightInfo->OriginalParms.Specular.r;
+ colRGBA[1] = lightInfo->OriginalParms.Specular.g;
+ colRGBA[2] = lightInfo->OriginalParms.Specular.b;
+ colRGBA[3] = lightInfo->OriginalParms.Specular.a;
+ glLightfv(GL_LIGHT0+Index, GL_SPECULAR, colRGBA);
+ checkGLcall("glLightfv");
+
+ /* Ambient */
+ colRGBA[0] = lightInfo->OriginalParms.Ambient.r;
+ colRGBA[1] = lightInfo->OriginalParms.Ambient.g;
+ colRGBA[2] = lightInfo->OriginalParms.Ambient.b;
+ colRGBA[3] = lightInfo->OriginalParms.Ambient.a;
+ glLightfv(GL_LIGHT0+Index, GL_AMBIENT, colRGBA);
+ checkGLcall("glLightfv");
+
+ /* Attenuation - Are these right? guessing... */
+ glLightf(GL_LIGHT0+Index, GL_CONSTANT_ATTENUATION, lightInfo->OriginalParms.Attenuation0);
+ checkGLcall("glLightf");
+ glLightf(GL_LIGHT0+Index, GL_LINEAR_ATTENUATION, lightInfo->OriginalParms.Attenuation1);
+ checkGLcall("glLightf");
+
+ quad_att = 1.4/(lightInfo->OriginalParms.Range*lightInfo->OriginalParms.Range);
+ if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2;
+ glLightf(GL_LIGHT0+Index, GL_QUADRATIC_ATTENUATION, quad_att);
+ checkGLcall("glLightf");
+
+ switch (lightInfo->OriginalParms.Type) {
+ case D3DLIGHT_POINT:
+ /* Position */
+ glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
+ checkGLcall("glLightfv");
+ glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
+ checkGLcall("glLightf");
+ /* FIXME: Range */
+ break;
+
+ case D3DLIGHT_SPOT:
+ /* Position */
+ glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
+ checkGLcall("glLightfv");
+ /* Direction */
+ glLightfv(GL_LIGHT0+Index, GL_SPOT_DIRECTION, &lightInfo->lightDirn[0]);
+ checkGLcall("glLightfv");
+ glLightf(GL_LIGHT0 + Index, GL_SPOT_EXPONENT, lightInfo->exponent);
+ checkGLcall("glLightf");
+ glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
+ checkGLcall("glLightf");
+ /* FIXME: Range */
+ break;
+
+ case D3DLIGHT_DIRECTIONAL:
+ /* Direction */
+ glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]); /* Note gl uses w position of 0 for direction! */
+ checkGLcall("glLightfv");
+ glLightf(GL_LIGHT0+Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
+ checkGLcall("glLightf");
+ glLightf(GL_LIGHT0+Index, GL_SPOT_EXPONENT, 0.0f);
+ checkGLcall("glLightf");
+ break;
+
+ default:
+ FIXME("Unrecognized light type %d\n", lightInfo->OriginalParms.Type);
+ }
+
+ /* Restore the modelview matrix */
+ glPopMatrix();
+}
/**********************************************************
* IWineD3DDevice implementation follows
@@ -194,7 +282,7 @@
}
/*****
- * Get / Set Transform
+ * Get / Set & Multipy Transform
*****/
HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE d3dts, CONST D3DMATRIX* lpmatrix) {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
@@ -264,10 +352,7 @@
}
} else if (d3dts == D3DTS_VIEW) { /* handle the VIEW matrice */
-
-#if 0 /* TODO: */
unsigned int k;
-#endif
/* If we are changing the View matrix, reset the light and clipping planes to the new view
* NOTE: We have to reset the positions even if the light/plane is not currently
@@ -277,18 +362,16 @@
This->modelview_valid = FALSE;
This->view_ident = !memcmp(lpmatrix, identity, 16*sizeof(float));
-#if 0 /* TODO: */
PLIGHTINFOEL *lightChain = NULL;
-#endif
+
glMatrixMode(GL_MODELVIEW);
checkGLcall("glMatrixMode(GL_MODELVIEW)");
glPushMatrix();
glLoadMatrixf((float *)lpmatrix);
checkGLcall("glLoadMatrixf(...)");
-#if 0 /* TODO: */
/* Reset lights */
- lightChain = This->StateBlock->lights;
+ lightChain = This->stateBlock->lights;
while (lightChain && lightChain->glIndex != -1) {
glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
checkGLcall("glLightfv posn");
@@ -296,12 +379,12 @@
checkGLcall("glLightfv dirn");
lightChain = lightChain->next;
}
+
/* Reset Clipping Planes if clipping is enabled */
for (k = 0; k < GL_LIMITS(clipplanes); k++) {
- glClipPlane(GL_CLIP_PLANE0 + k, This->StateBlock->clipplane[k]);
+ glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
checkGLcall("glClipPlane");
}
-#endif
glPopMatrix();
} else { /* What was requested!?? */
@@ -320,6 +403,626 @@
return D3D_OK;
}
+HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix) {
+ D3DMATRIX *mat = NULL;
+ D3DMATRIX temp;
+
+ /* Note: Using 'updateStateBlock' rather then 'stateblock' in the code below
+ means it will be recorded in a state block change, but iworks regardless of recording being on.
+ If this is found to be wrong, change to StateBlock. */
+ IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+ TRACE("(%p) : For state %u\n", This, State);
+
+ if (State < HIGHEST_TRANSFORMSTATE)
+ {
+ mat = &This->updateStateBlock->transforms[State];
+ } else {
+ FIXME("Unhandled transform state!!\n");
+ }
+
+ /* Copied from ddraw code: */
+ temp.u.s._11 = (mat->u.s._11 * pMatrix->u.s._11) + (mat->u.s._21 * pMatrix->u.s._12) + (mat->u.s._31 * pMatrix->u.s._13) + (mat->u.s._41 * pMatrix->u.s._14);
+ temp.u.s._21 = (mat->u.s._11 * pMatrix->u.s._21) + (mat->u.s._21 * pMatrix->u.s._22) + (mat->u.s._31 * pMatrix->u.s._23) + (mat->u.s._41 * pMatrix->u.s._24);
+ temp.u.s._31 = (mat->u.s._11 * pMatrix->u.s._31) + (mat->u.s._21 * pMatrix->u.s._32) + (mat->u.s._31 * pMatrix->u.s._33) + (mat->u.s._41 * pMatrix->u.s._34);
+ temp.u.s._41 = (mat->u.s._11 * pMatrix->u.s._41) + (mat->u.s._21 * pMatrix->u.s._42) + (mat->u.s._31 * pMatrix->u.s._43) + (mat->u.s._41 * pMatrix->u.s._44);
+
+ temp.u.s._12 = (mat->u.s._12 * pMatrix->u.s._11) + (mat->u.s._22 * pMatrix->u.s._12) + (mat->u.s._32 * pMatrix->u.s._13) + (mat->u.s._42 * pMatrix->u.s._14);
+ temp.u.s._22 = (mat->u.s._12 * pMatrix->u.s._21) + (mat->u.s._22 * pMatrix->u.s._22) + (mat->u.s._32 * pMatrix->u.s._23) + (mat->u.s._42 * pMatrix->u.s._24);
+ temp.u.s._32 = (mat->u.s._12 * pMatrix->u.s._31) + (mat->u.s._22 * pMatrix->u.s._32) + (mat->u.s._32 * pMatrix->u.s._33) + (mat->u.s._42 * pMatrix->u.s._34);
+ temp.u.s._42 = (mat->u.s._12 * pMatrix->u.s._41) + (mat->u.s._22 * pMatrix->u.s._42) + (mat->u.s._32 * pMatrix->u.s._43) + (mat->u.s._42 * pMatrix->u.s._44);
+
+ temp.u.s._13 = (mat->u.s._13 * pMatrix->u.s._11) + (mat->u.s._23 * pMatrix->u.s._12) + (mat->u.s._33 * pMatrix->u.s._13) + (mat->u.s._43 * pMatrix->u.s._14);
+ temp.u.s._23 = (mat->u.s._13 * pMatrix->u.s._21) + (mat->u.s._23 * pMatrix->u.s._22) + (mat->u.s._33 * pMatrix->u.s._23) + (mat->u.s._43 * pMatrix->u.s._24);
+ temp.u.s._33 = (mat->u.s._13 * pMatrix->u.s._31) + (mat->u.s._23 * pMatrix->u.s._32) + (mat->u.s._33 * pMatrix->u.s._33) + (mat->u.s._43 * pMatrix->u.s._34);
+ temp.u.s._43 = (mat->u.s._13 * pMatrix->u.s._41) + (mat->u.s._23 * pMatrix->u.s._42) + (mat->u.s._33 * pMatrix->u.s._43) + (mat->u.s._43 * pMatrix->u.s._44);
+
+ temp.u.s._14 = (mat->u.s._14 * pMatrix->u.s._11) + (mat->u.s._24 * pMatrix->u.s._12) + (mat->u.s._34 * pMatrix->u.s._13) + (mat->u.s._44 * pMatrix->u.s._14);
+ temp.u.s._24 = (mat->u.s._14 * pMatrix->u.s._21) + (mat->u.s._24 * pMatrix->u.s._22) + (mat->u.s._34 * pMatrix->u.s._23) + (mat->u.s._44 * pMatrix->u.s._24);
+ temp.u.s._34 = (mat->u.s._14 * pMatrix->u.s._31) + (mat->u.s._24 * pMatrix->u.s._32) + (mat->u.s._34 * pMatrix->u.s._33) + (mat->u.s._44 * pMatrix->u.s._34);
+ temp.u.s._44 = (mat->u.s._14 * pMatrix->u.s._41) + (mat->u.s._24 * pMatrix->u.s._42) + (mat->u.s._34 * pMatrix->u.s._43) + (mat->u.s._44 * pMatrix->u.s._44);
+
+ /* Apply change via set transform - will reapply to eg. lights this way */
+ IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
+ return D3D_OK;
+}
+
+/*****
+ * Get / Set Light
+ * WARNING: This code relies on the fact that D3DLIGHT8 == D3DLIGHT9
+ *****/
+/* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
+ you can reference any indexes you want as long as that number max are enabled are any
+ one point in time! Therefore since the indexes can be anything, we need a linked list of them.
+ However, this causes stateblock problems. When capturing the state block, I duplicate the list,
+ but when recording, just build a chain pretty much of commands to be replayed. */
+
+HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
+ float rho;
+ PLIGHTINFOEL *object, *temp;
+
+ IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+ TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
+
+ /* If recording state block, just add to end of lights chain */
+ if (This->isRecordingState) {
+ object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
+ if (NULL == object) {
+ return D3DERR_OUTOFVIDEOMEMORY;
+ }
+ memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
+ object->OriginalIndex = Index;
+ object->glIndex = -1;
+ object->changed = TRUE;
+
+ /* Add to the END of the chain of lights changes to be replayed */
+ if (This->updateStateBlock->lights == NULL) {
+ This->updateStateBlock->lights = object;
+ } else {
+ temp = This->updateStateBlock->lights;
+ while (temp->next != NULL) temp=temp->next;
+ temp->next = object;
+ }
+ TRACE("Recording... not performing anything more\n");
+ return D3D_OK;
+ }
+
+ /* Ok, not recording any longer so do real work */
+ object = This->stateBlock->lights;
+ while (object != NULL && object->OriginalIndex != Index) object = object->next;
+
+ /* If we didn't find it in the list of lights, time to add it */
+ if (object == NULL) {
+ PLIGHTINFOEL *insertAt,*prevPos;
+
+ object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
+ if (NULL == object) {
+ return D3DERR_OUTOFVIDEOMEMORY;
+ }
+ object->OriginalIndex = Index;
+ object->glIndex = -1;
+
+ /* Add it to the front of list with the idea that lights will be changed as needed
+ BUT after any lights currently assigned GL indexes */
+ insertAt = This->stateBlock->lights;
+ prevPos = NULL;
+ while (insertAt != NULL && insertAt->glIndex != -1) {
+ prevPos = insertAt;
+ insertAt = insertAt->next;
+ }
+
+ if (insertAt == NULL && prevPos == NULL) { /* Start of list */
+ This->stateBlock->lights = object;
+ } else if (insertAt == NULL) { /* End of list */
+ prevPos->next = object;
+ object->prev = prevPos;
+ } else { /* Middle of chain */
+ if (prevPos == NULL) {
+ This->stateBlock->lights = object;
+ } else {
+ prevPos->next = object;
+ }
+ object->prev = prevPos;
+ object->next = insertAt;
+ insertAt->prev = object;
+ }
+ }
+
+ /* Initialze the object */
+ TRACE("Light %ld setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type,
+ pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
+ pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
+ pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
+ TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
+ pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
+ TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
+
+ /* Save away the information */
+ memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
+
+ switch (pLight->Type) {
+ case D3DLIGHT_POINT:
+ /* Position */
+ object->lightPosn[0] = pLight->Position.x;
+ object->lightPosn[1] = pLight->Position.y;
+ object->lightPosn[2] = pLight->Position.z;
+ object->lightPosn[3] = 1.0f;
+ object->cutoff = 180.0f;
+ /* FIXME: Range */
+ break;
+
+ case D3DLIGHT_DIRECTIONAL:
+ /* Direction */
+ object->lightPosn[0] = -pLight->Direction.x;
+ object->lightPosn[1] = -pLight->Direction.y;
+ object->lightPosn[2] = -pLight->Direction.z;
+ object->lightPosn[3] = 0.0;
+ object->exponent = 0.0f;
+ object->cutoff = 180.0f;
+ break;
+
+ case D3DLIGHT_SPOT:
+ /* Position */
+ object->lightPosn[0] = pLight->Position.x;
+ object->lightPosn[1] = pLight->Position.y;
+ object->lightPosn[2] = pLight->Position.z;
+ object->lightPosn[3] = 1.0;
+
+ /* Direction */
+ object->lightDirn[0] = pLight->Direction.x;
+ object->lightDirn[1] = pLight->Direction.y;
+ object->lightDirn[2] = pLight->Direction.z;
+ object->lightDirn[3] = 1.0;
+
+ /*
+ * opengl-ish and d3d-ish spot lights use too different models for the
+ * light "intensity" as a function of the angle towards the main light direction,
+ * so we only can approximate very roughly.
+ * however spot lights are rather rarely used in games (if ever used at all).
+ * furthermore if still used, probably nobody pays attention to such details.
+ */
+ if (pLight->Falloff == 0) {
+ rho = 6.28f;
+ } else {
+ rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
+ }
+ if (rho < 0.0001) rho = 0.0001f;
+ object->exponent = -0.3/log(cos(rho/2));
+ object->cutoff = pLight->Phi*90/M_PI;
+
+ /* FIXME: Range */
+ break;
+
+ default:
+ FIXME("Unrecognized light type %d\n", pLight->Type);
+ }
+
+ /* Update the live definitions if the light is currently assigned a glIndex */
+ if (object->glIndex != -1) {
+ setup_light(iface, object->glIndex, object);
+ }
+ return D3D_OK;
+}
+
+HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
+ PLIGHTINFOEL *lightInfo = NULL;
+ IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+ TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
+
+ /* Locate the light in the live lights */
+ lightInfo = This->stateBlock->lights;
+ while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
+
+ if (lightInfo == NULL) {
+ TRACE("Light information requested but light not defined\n");
+ return D3DERR_INVALIDCALL;
+ }
+
+ memcpy(pLight, &lightInfo->OriginalParms, sizeof(D3DLIGHT9));
+ return D3D_OK;
+}
+
+/*****
+ * Get / Set Light Enable
+ * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
+ *****/
+HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
+ PLIGHTINFOEL *lightInfo = NULL;
+ IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+ TRACE("(%p) : Idx(%ld), enable? %d\n", This, Index, Enable);
+
+ /* If recording state block, just add to end of lights chain with changedEnable set to true */
+ if (This->isRecordingState) {
+ lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
+ if (NULL == lightInfo) {
+ return D3DERR_OUTOFVIDEOMEMORY;
+ }
+ lightInfo->OriginalIndex = Index;
+ lightInfo->glIndex = -1;
+ lightInfo->enabledChanged = TRUE;
+
+ /* Add to the END of the chain of lights changes to be replayed */
+ if (This->updateStateBlock->lights == NULL) {
+ This->updateStateBlock->lights = lightInfo;
+ } else {
+ PLIGHTINFOEL *temp = This->updateStateBlock->lights;
+ while (temp->next != NULL) temp=temp->next;
+ temp->next = lightInfo;
+ }
+ TRACE("Recording... not performing anything more\n");
+ return D3D_OK;
+ }
+
+ /* Not recording... So, locate the light in the live lights */
+ lightInfo = This->stateBlock->lights;
+ while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
+
+ /* Special case - enabling an undefined light creates one with a strict set of parms! */
+ if (lightInfo == NULL) {
+ D3DLIGHT9 lightParms;
+ /* Warning - untested code :-) Prob safe to change fixme to a trace but
+ wait until someone confirms it seems to work! */
+ TRACE("Light enabled requested but light not defined, so defining one!\n");
+ lightParms.Type = D3DLIGHT_DIRECTIONAL;
+ lightParms.Diffuse.r = 1.0;
+ lightParms.Diffuse.g = 1.0;
+ lightParms.Diffuse.b = 1.0;
+ lightParms.Diffuse.a = 0.0;
+ lightParms.Specular.r = 0.0;
+ lightParms.Specular.g = 0.0;
+ lightParms.Specular.b = 0.0;
+ lightParms.Specular.a = 0.0;
+ lightParms.Ambient.r = 0.0;
+ lightParms.Ambient.g = 0.0;
+ lightParms.Ambient.b = 0.0;
+ lightParms.Ambient.a = 0.0;
+ lightParms.Position.x = 0.0;
+ lightParms.Position.y = 0.0;
+ lightParms.Position.z = 0.0;
+ lightParms.Direction.x = 0.0;
+ lightParms.Direction.y = 0.0;
+ lightParms.Direction.z = 1.0;
+ lightParms.Range = 0.0;
+ lightParms.Falloff = 0.0;
+ lightParms.Attenuation0 = 0.0;
+ lightParms.Attenuation1 = 0.0;
+ lightParms.Attenuation2 = 0.0;
+ lightParms.Theta = 0.0;
+ lightParms.Phi = 0.0;
+ IWineD3DDeviceImpl_SetLight(iface, Index, &lightParms);
+
+ /* Search for it again! Should be fairly quick as near head of list */
+ lightInfo = This->stateBlock->lights;
+ while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
+ if (lightInfo == NULL) {
+ FIXME("Adding default lights has failed dismally\n");
+ return D3DERR_INVALIDCALL;
+ }
+ }
+
+ /* OK, we now have a light... */
+ if (Enable == FALSE) {
+
+ /* If we are disabling it, check it was enabled, and
+ still only do something if it has assigned a glIndex (which it should have!) */
+ if ((lightInfo->lightEnabled == TRUE) && (lightInfo->glIndex != -1)) {
+ TRACE("Disabling light set up at gl idx %ld\n", lightInfo->glIndex);
+ ENTER_GL();
+ glDisable(GL_LIGHT0 + lightInfo->glIndex);
+ checkGLcall("glDisable GL_LIGHT0+Index");
+ LEAVE_GL();
+ } else {
+ TRACE("Nothing to do as light was not enabled\n");
+ }
+ lightInfo->lightEnabled = FALSE;
+ } else {
+
+ /* We are enabling it. If it is enabled, its really simple */
+ if (lightInfo->lightEnabled == TRUE) {
+ /* nop */
+ TRACE("Nothing to do as light was enabled\n");
+
+ /* If it already has a glIndex, its still simple */
+ } else if (lightInfo->glIndex != -1) {
+ TRACE("Reusing light as already set up at gl idx %ld\n", lightInfo->glIndex);
+ lightInfo->lightEnabled = TRUE;
+ ENTER_GL();
+ glEnable(GL_LIGHT0 + lightInfo->glIndex);
+ checkGLcall("glEnable GL_LIGHT0+Index already setup");
+ LEAVE_GL();
+
+ /* Otherwise got to find space - lights are ordered gl indexes first */
+ } else {
+ PLIGHTINFOEL *bsf = NULL;
+ PLIGHTINFOEL *pos = This->stateBlock->lights;
+ PLIGHTINFOEL *prev = NULL;
+ int Index= 0;
+ int glIndex = -1;
+
+ /* Try to minimize changes as much as possible */
+ while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
+
+ /* Try to remember which index can be replaced if necessary */
+ if (bsf==NULL && pos->lightEnabled == FALSE) {
+ /* Found a light we can replace, save as best replacement */
+ bsf = pos;
+ }
+
+ /* Step to next space */
+ prev = pos;
+ pos = pos->next;
+ Index ++;
+ }
+
+ /* If we have too many active lights, fail the call */
+ if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
+ FIXME("Program requests too many concurrent lights\n");
+ return D3DERR_INVALIDCALL;
+
+ /* If we have allocated all lights, but not all are enabled,
+ reuse one which is not enabled */
+ } else if (Index == This->maxConcurrentLights) {
+ /* use bsf - Simply swap the new light and the BSF one */
+ PLIGHTINFOEL *bsfNext = bsf->next;
+ PLIGHTINFOEL *bsfPrev = bsf->prev;
+
+ /* Sort out ends */
+ if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
+ if (bsf->prev != NULL) {
+ bsf->prev->next = lightInfo;
+ } else {
+ This->stateBlock->lights = lightInfo;
+ }
+
+ /* If not side by side, lots of chains to update */
+ if (bsf->next != lightInfo) {
+ lightInfo->prev->next = bsf;
+ bsf->next->prev = lightInfo;
+ bsf->next = lightInfo->next;
+ bsf->prev = lightInfo->prev;
+ lightInfo->next = bsfNext;
+ lightInfo->prev = bsfPrev;
+
+ } else {
+ /* Simple swaps */
+ bsf->prev = lightInfo;
+ bsf->next = lightInfo->next;
+ lightInfo->next = bsf;
+ lightInfo->prev = bsfPrev;
+ }
+
+
+ /* Update states */
+ glIndex = bsf->glIndex;
+ bsf->glIndex = -1;
+ lightInfo->glIndex = glIndex;
+ lightInfo->lightEnabled = TRUE;
+
+ /* Finally set up the light in gl itself */
+ TRACE("Replacing light which was set up at gl idx %ld\n", lightInfo->glIndex);
+ ENTER_GL();
+ setup_light(iface, glIndex, lightInfo);
+ glEnable(GL_LIGHT0 + glIndex);
+ checkGLcall("glEnable GL_LIGHT0 new setup");
+ LEAVE_GL();
+
+ /* If we reached the end of the allocated lights, with space in the
+ gl lights, setup a new light */
+ } else if (pos->glIndex == -1) {
+
+ /* We reached the end of the allocated gl lights, so already
+ know the index of the next one! */
+ glIndex = Index;
+ lightInfo->glIndex = glIndex;
+ lightInfo->lightEnabled = TRUE;
+
+ /* In an ideal world, its already in the right place */
+ if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
+ /* No need to move it */
+ } else {
+ /* Remove this light from the list */
+ lightInfo->prev->next = lightInfo->next;
+ if (lightInfo->next != NULL) {
+ lightInfo->next->prev = lightInfo->prev;
+ }
+
+ /* Add in at appropriate place (inbetween prev and pos) */
+ lightInfo->prev = prev;
+ lightInfo->next = pos;
+ if (prev == NULL) {
+ This->stateBlock->lights = lightInfo;
+ } else {
+ prev->next = lightInfo;
+ }
+ if (pos != NULL) {
+ pos->prev = lightInfo;
+ }
+ }
+
+ /* Finally set up the light in gl itself */
+ TRACE("Defining new light at gl idx %ld\n", lightInfo->glIndex);
+ ENTER_GL();
+ setup_light(iface, glIndex, lightInfo);
+ glEnable(GL_LIGHT0 + glIndex);
+ checkGLcall("glEnable GL_LIGHT0 new setup");
+ LEAVE_GL();
+
+ }
+ }
+ }
+ return D3D_OK;
+}
+
+HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
+
+ PLIGHTINFOEL *lightInfo = NULL;
+ IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+ TRACE("(%p) : for idx(%ld)\n", This, Index);
+
+ /* Locate the light in the live lights */
+ lightInfo = This->stateBlock->lights;
+ while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
+
+ if (lightInfo == NULL) {
+ TRACE("Light enabled state requested but light not defined\n");
+ return D3DERR_INVALIDCALL;
+ }
+ *pEnable = lightInfo->lightEnabled;
+ return D3D_OK;
+}
+
+/*****
+ * Get / Set Clip Planes
+ *****/
+HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
+ IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+ TRACE("(%p) : for idx %ld, %p\n", This, Index, pPlane);
+
+ /* Validate Index */
+ if (Index >= GL_LIMITS(clipplanes)) {
+ TRACE("Application has requested clipplane this device doesn't support\n");
+ return D3DERR_INVALIDCALL;
+ }
+
+ This->updateStateBlock->changed.clipplane[Index] = TRUE;
+ This->updateStateBlock->set.clipplane[Index] = TRUE;
+ This->updateStateBlock->clipplane[Index][0] = pPlane[0];
+ This->updateStateBlock->clipplane[Index][1] = pPlane[1];
+ This->updateStateBlock->clipplane[Index][2] = pPlane[2];
+ This->updateStateBlock->clipplane[Index][3] = pPlane[3];
+
+ /* Handle recording of state blocks */
+ if (This->isRecordingState) {
+ TRACE("Recording... not performing anything\n");
+ return D3D_OK;
+ }
+
+ /* Apply it */
+
+ ENTER_GL();
+
+ /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadMatrixf((float *) &This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
+
+ TRACE("Clipplane [%f,%f,%f,%f]\n",
+ This->updateStateBlock->clipplane[Index][0],
+ This->updateStateBlock->clipplane[Index][1],
+ This->updateStateBlock->clipplane[Index][2],
+ This->updateStateBlock->clipplane[Index][3]);
+ glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
+ checkGLcall("glClipPlane");
+
+ glPopMatrix();
+ LEAVE_GL();
+
+ return D3D_OK;
+}
+
+HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
+ IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+ TRACE("(%p) : for idx %ld\n", This, Index);
+
+ /* Validate Index */
+ if (Index >= GL_LIMITS(clipplanes)) {
+ TRACE("Application has requested clipplane this device doesn't support\n");
+ return D3DERR_INVALIDCALL;
+ }
+
+ pPlane[0] = This->stateBlock->clipplane[Index][0];
+ pPlane[1] = This->stateBlock->clipplane[Index][1];
+ pPlane[2] = This->stateBlock->clipplane[Index][2];
+ pPlane[3] = This->stateBlock->clipplane[Index][3];
+ return D3D_OK;
+}
+
+/*****
+ * Get / Set Clip Plane Status
+ * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
+ *****/
+HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
+ IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+ FIXME("(%p) : stub\n", This);
+ if (NULL == pClipStatus) {
+ return D3DERR_INVALIDCALL;
+ }
+ This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
+ This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
+ return D3D_OK;
+}
+
+HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
+ IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+ FIXME("(%p) : stub\n", This);
+ if (NULL == pClipStatus) {
+ return D3DERR_INVALIDCALL;
+ }
+ pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
+ pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
+ return D3D_OK;
+}
+
+/*****
+ * Get / Set Material
+ * WARNING: This code relies on the fact that D3DMATERIAL8 == D3DMATERIAL9
+ *****/
+HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
+ IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+
+ This->updateStateBlock->changed.material = TRUE;
+ This->updateStateBlock->set.material = TRUE;
+ memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
+
+ /* Handle recording of state blocks */
+ if (This->isRecordingState) {
+ TRACE("Recording... not performing anything\n");
+ return D3D_OK;
+ }
+
+ ENTER_GL();
+ TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g, pMaterial->Diffuse.b, pMaterial->Diffuse.a);
+ TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g, pMaterial->Ambient.b, pMaterial->Ambient.a);
+ TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g, pMaterial->Specular.b, pMaterial->Specular.a);
+ TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g, pMaterial->Emissive.b, pMaterial->Emissive.a);
+ TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
+
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
+ checkGLcall("glMaterialfv");
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
+ checkGLcall("glMaterialfv");
+
+ /* Only change material color if specular is enabled, otherwise it is set to black */
+#if 0 /* TODO */
+ if (This->StateBlock->renderstate[D3DRS_SPECULARENABLE]) {
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->UpdateStateBlock->material.Specular);
+ checkGLcall("glMaterialfv");
+ } else {
+#endif
+ {
+ float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
+ checkGLcall("glMaterialfv");
+ }
+ glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
+ checkGLcall("glMaterialfv");
+ glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
+ checkGLcall("glMaterialf");
+
+ LEAVE_GL();
+ return D3D_OK;
+}
+
+HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
+ IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+ memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
+ TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g, pMaterial->Diffuse.b, pMaterial->Diffuse.a);
+ TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g, pMaterial->Ambient.b, pMaterial->Ambient.a);
+ TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g, pMaterial->Specular.b, pMaterial->Specular.a);
+ TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g, pMaterial->Emissive.b, pMaterial->Emissive.a);
+ TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
+ return D3D_OK;
+}
+
/*****
* Scene related functions
*****/
@@ -378,5 +1081,16 @@
IWineD3DDeviceImpl_GetStreamSource,
IWineD3DDeviceImpl_SetTransform,
IWineD3DDeviceImpl_GetTransform,
+ IWineD3DDeviceImpl_MultiplyTransform,
+ IWineD3DDeviceImpl_SetLight,
+ IWineD3DDeviceImpl_GetLight,
+ IWineD3DDeviceImpl_SetLightEnable,
+ IWineD3DDeviceImpl_GetLightEnable,
+ IWineD3DDeviceImpl_SetClipPlane,
+ IWineD3DDeviceImpl_GetClipPlane,
+ IWineD3DDeviceImpl_SetClipStatus,
+ IWineD3DDeviceImpl_GetClipStatus,
+ IWineD3DDeviceImpl_SetMaterial,
+ IWineD3DDeviceImpl_GetMaterial,
IWineD3DDeviceImpl_BeginScene
};
diff --git a/dlls/wined3d/indexbuffer.c b/dlls/wined3d/indexbuffer.c
index 8ee3efb..617cd18 100644
--- a/dlls/wined3d/indexbuffer.c
+++ b/dlls/wined3d/indexbuffer.c
@@ -24,6 +24,7 @@
#include "wined3d_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(d3d);
+#define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->resource.wineD3DDevice)->wineD3D))->gl_info
/* *******************************************
IWineD3DIndexBuffer IUnknown parts follow
@@ -52,7 +53,7 @@
IWineD3DDevice_Release(This->resource.wineD3DDevice);
HeapFree(GetProcessHeap(), 0, This);
} else {
- IUnknown_Release(This->resource.parent); /* Released the reference to the d3dx VB */
+ IUnknown_Release(This->resource.parent); /* Released the reference to the d3dx object */
}
return ref;
}
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 8abcae1..dc68095 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -24,6 +24,7 @@
#define __WINE_WINED3D_PRIVATE_H
#include <stdarg.h>
+#include <math.h>
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#define COBJMACROS
@@ -77,6 +78,7 @@
/* Highest value in D3DTRANSFORMSTATETYPE */
#define WINED3D_VSHADER_MAX_CONSTANTS 96
/* Maximum number of constants provided to the shaders */
+#define MAX_CLIPPLANES D3DMAXUSERCLIPPLANES
#define checkGLcall(A) \
{ \
@@ -108,11 +110,43 @@
checkGLcall("glActiveTextureARB");
#endif
+/* Macro to dump out the current state of the light chain */
+#define DUMP_LIGHT_CHAIN() \
+{ \
+ PLIGHTINFOEL *el = This->stateBlock->lights;\
+ while (el) { \
+ TRACE("Light %p (glIndex %ld, d3dIndex %ld, enabled %d)\n", el, el->glIndex, el->OriginalIndex, el->lightEnabled);\
+ el = el->next; \
+ } \
+}
+
typedef struct IWineD3DStateBlockImpl IWineD3DStateBlockImpl;
extern const float identity[16];
/*****************************************************************************
+ * Internal representation of a light
+ */
+typedef struct PLIGHTINFOEL PLIGHTINFOEL;
+struct PLIGHTINFOEL {
+ WINED3DLIGHT OriginalParms; /* Note D3D8LIGHT == D3D9LIGHT */
+ DWORD OriginalIndex;
+ LONG glIndex;
+ BOOL lightEnabled;
+ BOOL changed;
+ BOOL enabledChanged;
+
+ /* Converted parms to speed up swapping lights */
+ float lightPosn[4];
+ float lightDirn[4];
+ float exponent;
+ float cutoff;
+
+ PLIGHTINFOEL *next;
+ PLIGHTINFOEL *prev;
+};
+
+/*****************************************************************************
* IWineD3D implementation structure
*/
typedef struct IWineD3DImpl
@@ -242,9 +276,11 @@
/* Note: Very long winded but gl Lists are not flexible enough */
/* to resolve everything we need, so doing it manually for now */
typedef struct SAVEDSTATES {
+ BOOL material;
BOOL fvf;
BOOL stream_source[MAX_STREAMS];
BOOL transform[HIGHEST_TRANSFORMSTATE];
+ BOOL clipplane[MAX_CLIPPLANES];
} SAVEDSTATES;
struct IWineD3DStateBlockImpl
@@ -273,6 +309,16 @@
/* Transform */
D3DMATRIX transforms[HIGHEST_TRANSFORMSTATE];
+ /* Lights */
+ PLIGHTINFOEL *lights; /* NOTE: active GL lights must be front of the chain */
+
+ /* Clipping */
+ double clipplane[MAX_CLIPPLANES][4];
+ WINED3DCLIPSTATUS clip_status;
+
+ /* Material */
+ WINED3DMATERIAL material;
+
};
extern IWineD3DStateBlockVtbl IWineD3DStateBlock_Vtbl;