wined3d: Replace the light chain with a hashmap.

This commit is contained in:
Stefan Dösinger 2007-02-14 17:46:54 +01:00 committed by Alexandre Julliard
parent 5fce682f41
commit acadf3f241
4 changed files with 216 additions and 318 deletions

View File

@ -584,6 +584,10 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface,
D3DCREATEOBJECTINSTANCE(object, StateBlock)
object->blockType = Type;
for(i = 0; i < LIGHTMAP_SIZE; i++) {
list_init(&object->lightMap[i]);
}
/* Special case - Used during initialization to produce a placeholder stateblock
so other functions called can update a state block */
if (Type == WINED3DSBT_INIT) {
@ -614,6 +618,15 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface,
TRACE("ALL => Pretend everything has changed\n");
stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
/* Lights are not part of the changed / set structure */
for(j = 0; j < LIGHTMAP_SIZE; j++) {
struct list *e;
LIST_FOR_EACH(e, &object->lightMap[j]) {
PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
light->changed = TRUE;
light->enabledChanged = TRUE;
}
}
} else if (Type == WINED3DSBT_PIXELSTATE) {
TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
@ -673,33 +686,14 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface,
}
}
/* Duplicate light chain */
{
PLIGHTINFOEL *src = NULL;
PLIGHTINFOEL *dst = NULL;
PLIGHTINFOEL *newEl = NULL;
src = This->stateBlock->lights;
object->lights = NULL;
while (src) {
newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
memcpy(newEl, src, sizeof(PLIGHTINFOEL));
newEl->prev = dst;
newEl->changed = TRUE;
newEl->enabledChanged = TRUE;
if (dst == NULL) {
object->lights = newEl;
} else {
dst->next = newEl;
for(j = 0; j < LIGHTMAP_SIZE; j++) {
struct list *e;
LIST_FOR_EACH(e, &object->lightMap[j]) {
PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
light->changed = TRUE;
light->enabledChanged = TRUE;
}
dst = newEl;
src = src->next;
}
}
} else {
FIXME("Unrecognized state block type %d\n", Type);
}
@ -2329,73 +2323,30 @@ static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface
static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
float rho;
PLIGHTINFOEL *object, *temp;
PLIGHTINFOEL *object = NULL;
UINT Hi = LIGHTMAP_HASHFUNC(Index);
struct list *e;
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
/* 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 WINED3DERR_OUTOFVIDEOMEMORY;
LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
if(object->OriginalIndex == Index) break;
object = NULL;
}
memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
object->OriginalIndex = Index;
if(!object) {
TRACE("Adding new light\n");
object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
if(!object) {
ERR("Out of memory error when allocating a light\n");
return E_OUTOFMEMORY;
}
list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
object->glIndex = -1;
object->OriginalIndex = Index;
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 WINED3D_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 WINED3DERR_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;
}
}
/* Initialize the object */
@ -2471,7 +2422,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD I
}
/* Update the live definitions if the light is currently assigned a glIndex */
if (object->glIndex != -1) {
if (object->glIndex != -1 && !This->isRecordingState) {
setup_light(iface, object->glIndex, object);
}
return WINED3D_OK;
@ -2480,11 +2431,15 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD I
static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
PLIGHTINFOEL *lightInfo = NULL;
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
DWORD Hi = LIGHTMAP_HASHFUNC(Index);
struct list *e;
TRACE("(%p) : Idx(%d), 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;
LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
if(lightInfo->OriginalIndex == Index) break;
lightInfo = NULL;
}
if (lightInfo == NULL) {
TRACE("Light information requested but light not defined\n");
@ -2502,38 +2457,19 @@ static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD I
static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
PLIGHTINFOEL *lightInfo = NULL;
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
UINT Hi = LIGHTMAP_HASHFUNC(Index);
struct list *e;
TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
/* Tests show true = 128...not clear why */
Enable = Enable? 128: 0;
/* 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 WINED3DERR_OUTOFVIDEOMEMORY;
LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
if(lightInfo->OriginalIndex == Index) break;
lightInfo = NULL;
}
lightInfo->OriginalIndex = Index;
lightInfo->glIndex = -1;
lightInfo->enabledChanged = TRUE;
lightInfo->lightEnabled = Enable;
/* 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 WINED3D_OK;
}
/* Not recording... So, locate the light in the live lights */
lightInfo = This->stateBlock->lights;
while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
TRACE("Found light: %p\n", lightInfo);
/* Special case - enabling an undefined light creates one with a strict set of parms! */
if (lightInfo == NULL) {
@ -2542,164 +2478,62 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, D
IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
/* 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;
LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
if(lightInfo->OriginalIndex == Index) break;
lightInfo = NULL;
}
if (lightInfo == NULL) {
FIXME("Adding default lights has failed dismally\n");
return WINED3DERR_INVALIDCALL;
}
}
/* OK, we now have a light... */
lightInfo->enabledChanged = TRUE;
if(!Enable) {
/* 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) && (lightInfo->glIndex != -1)) {
TRACE("Disabling light set up at gl idx %d\n", lightInfo->glIndex);
if(lightInfo->glIndex != -1) {
if(!This->isRecordingState) {
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 = Enable;
} else {
/* We are enabling it. If it is enabled, it's really simple */
if (lightInfo->lightEnabled) {
This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
lightInfo->glIndex = -1;
} else {
TRACE("Light already disabled, nothing to do\n");
}
} else {
if (lightInfo->glIndex != -1) {
/* nop */
TRACE("Nothing to do as light was enabled\n");
/* If it already has a glIndex, it's still simple */
} else if (lightInfo->glIndex != -1) {
TRACE("Reusing light as already set up at gl idx %d\n", lightInfo->glIndex);
lightInfo->lightEnabled = Enable;
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) {
/* Found a light we can replace, save as best replacement */
bsf = pos;
int i;
/* Find a free gl light */
for(i = 0; i < This->maxConcurrentLights; i++) {
if(This->stateBlock->activeLights[i] == NULL) {
This->stateBlock->activeLights[i] = lightInfo;
lightInfo->glIndex = i;
break;
}
/* 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");
if(lightInfo->glIndex == -1) {
ERR("Too many concurrently active lights\n");
return WINED3DERR_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 = Enable;
/* Finally set up the light in gl itself */
TRACE("Replacing light which was set up at gl idx %d\n", lightInfo->glIndex);
/* i == lightInfo->glIndex */
if(!This->isRecordingState) {
setup_light(iface, i, lightInfo);
ENTER_GL();
setup_light(iface, glIndex, lightInfo);
glEnable(GL_LIGHT0 + glIndex);
checkGLcall("glEnable GL_LIGHT0 new setup");
glEnable(GL_LIGHT0 + i);
checkGLcall("glEnable(GL_LIGHT0 + i)");
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 = Enable;
/* In an ideal world, it's 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 %d\n", lightInfo->glIndex);
ENTER_GL();
setup_light(iface, glIndex, lightInfo);
glEnable(GL_LIGHT0 + glIndex);
checkGLcall("glEnable GL_LIGHT0 new setup");
LEAVE_GL();
}
}
}
return WINED3D_OK;
}
@ -2707,17 +2541,22 @@ static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, D
PLIGHTINFOEL *lightInfo = NULL;
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
struct list *e;
UINT Hi = LIGHTMAP_HASHFUNC(Index);
TRACE("(%p) : for idx(%d)\n", This, Index);
/* Locate the light in the live lights */
lightInfo = This->stateBlock->lights;
while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
if(lightInfo->OriginalIndex == Index) break;
lightInfo = NULL;
}
if (lightInfo == NULL) {
TRACE("Light enabled state requested but light not defined\n");
return WINED3DERR_INVALIDCALL;
}
*pEnable = lightInfo->lightEnabled;
/* true is 128 according to SetLightEnable */
*pEnable = lightInfo->glIndex != -1 ? 128 : 0;
return WINED3D_OK;
}
@ -4327,6 +4166,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface)
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
IWineD3DStateBlockImpl *object;
HRESULT temp_result;
int i;
TRACE("(%p)\n", This);
@ -4347,6 +4187,10 @@ static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface)
object->ref = 1;
object->lpVtbl = &IWineD3DStateBlock_Vtbl;
for(i = 0; i < LIGHTMAP_SIZE; i++) {
list_init(&object->lightMap[i]);
}
temp_result = allocate_shader_constants(object);
if (WINED3D_OK != temp_result)
return temp_result;

View File

@ -1987,7 +1987,7 @@ static void transform_view(DWORD state, IWineD3DStateBlockImpl *stateblock, Wine
* NOTE2: Apparently texture transforms do NOT need reapplying
*/
PLIGHTINFOEL *lightChain = NULL;
PLIGHTINFOEL *light = NULL;
glMatrixMode(GL_MODELVIEW);
checkGLcall("glMatrixMode(GL_MODELVIEW)");
@ -1995,13 +1995,13 @@ static void transform_view(DWORD state, IWineD3DStateBlockImpl *stateblock, Wine
checkGLcall("glLoadMatrixf(...)");
/* Reset lights. TODO: Call light apply func */
lightChain = stateblock->lights;
while (lightChain && lightChain->glIndex != -1) {
glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
for(k = 0; k < stateblock->wineD3DDevice->maxConcurrentLights; k++) {
light = stateblock->activeLights[k];
if(!light) continue;
glLightfv(GL_LIGHT0 + light->glIndex, GL_POSITION, light->lightPosn);
checkGLcall("glLightfv posn");
glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
glLightfv(GL_LIGHT0 + light->glIndex, GL_SPOT_DIRECTION, light->lightDirn);
checkGLcall("glLightfv dirn");
lightChain = lightChain->next;
}
/* Reset Clipping Planes if clipping is enabled. TODO: Call clipplane apply func */

View File

@ -140,6 +140,7 @@ void stateblock_savedstates_set(
void stateblock_copy(
IWineD3DStateBlock* destination,
IWineD3DStateBlock* source) {
int l;
IWineD3DStateBlockImpl *This = (IWineD3DStateBlockImpl *)source;
IWineD3DStateBlockImpl *Dest = (IWineD3DStateBlockImpl *)destination;
@ -164,7 +165,7 @@ void stateblock_copy(
Dest->streamIsUP = This->streamIsUP;
Dest->pIndexData = This->pIndexData;
Dest->baseVertexIndex = This->baseVertexIndex;
Dest->lights = This->lights;
/* Dest->lights = This->lights; */
Dest->clip_status = This->clip_status;
Dest->viewport = This->viewport;
Dest->material = This->material;
@ -172,6 +173,25 @@ void stateblock_copy(
Dest->glsl_program = This->glsl_program;
memcpy(&Dest->scissorRect, &This->scissorRect, sizeof(Dest->scissorRect));
/* Lights */
memset(This->activeLights, 0, sizeof(This->activeLights));
for(l = 0; l < LIGHTMAP_SIZE; l++) {
struct list *e1, *e2;
LIST_FOR_EACH_SAFE(e1, e2, &Dest->lightMap[l]) {
PLIGHTINFOEL *light = LIST_ENTRY(e1, PLIGHTINFOEL, entry);
list_remove(&light->entry);
HeapFree(GetProcessHeap(), 0, light);
}
LIST_FOR_EACH(e1, &This->lightMap[l]) {
PLIGHTINFOEL *light = LIST_ENTRY(e1, PLIGHTINFOEL, entry), *light2;
light2 = HeapAlloc(GetProcessHeap(), 0, sizeof(*light));
memcpy(light2, light, sizeof(*light));
list_add_tail(&This->lightMap[l], &light2->entry);
if(light2->glIndex != -1) This->activeLights[light2->glIndex] = light2;
}
}
/* Fixed size arrays */
memcpy(Dest->vertexShaderConstantB, This->vertexShaderConstantB, sizeof(BOOL) * MAX_CONST_B);
memcpy(Dest->vertexShaderConstantI, This->vertexShaderConstantI, sizeof(INT) * MAX_CONST_I * 4);
@ -230,10 +250,10 @@ static ULONG WINAPI IWineD3DStateBlockImpl_Release(IWineD3DStateBlock *iface) {
if (!refCount) {
constant_entry *constant, *constant2;
int counter;
/* type 0 represents the primary stateblock, so free all the resources */
if (This->blockType == WINED3DSBT_INIT) {
int counter;
FIXME("Releasing primary stateblock\n");
/* NOTE: according to MSDN: The application is responsible for making sure the texture references are cleared down */
@ -248,6 +268,15 @@ static ULONG WINAPI IWineD3DStateBlockImpl_Release(IWineD3DStateBlock *iface) {
}
for(counter = 0; counter < LIGHTMAP_SIZE; counter++) {
struct list *e1, *e2;
LIST_FOR_EACH_SAFE(e1, e2, &This->lightMap[counter]) {
PLIGHTINFOEL *light = LIST_ENTRY(e1, PLIGHTINFOEL, entry);
list_remove(&light->entry);
HeapFree(GetProcessHeap(), 0, light);
}
}
HeapFree(GetProcessHeap(), 0, This->vertexShaderConstantF);
HeapFree(GetProcessHeap(), 0, This->set.vertexShaderConstantsF);
HeapFree(GetProcessHeap(), 0, This->changed.vertexShaderConstantsF);
@ -298,23 +327,27 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface)
/* If not recorded, then update can just recapture */
if (/*TODO: 'magic' statetype, replace with BOOL This->blockType == D3DSBT_RECORDED */ 0) {
IWineD3DStateBlockImpl* tmpBlock;
PLIGHTINFOEL *tmp = This->lights;
int i;
IWineD3DDevice_CreateStateBlock((IWineD3DDevice *)This->wineD3DDevice, This->blockType, (IWineD3DStateBlock**) &tmpBlock, NULL/*parent*/);
/* Note just swap the light chains over so when deleting, the old one goes */
memcpy(This, tmpBlock, sizeof(IWineD3DStateBlockImpl));
tmpBlock->lights = tmp;
/* Delete the temporary one (which points to the old light chain though */
/* Move the light elements from the tmpBlock to This. No need to duplicate them, but they have to be removed from tmpBlock
* and the pointers updated for the base element in This.
*
* No need to update This->activeLights because the lights objects are untouched(same address)
*/
for(i = 0; i < LIGHTMAP_SIZE; i++) {
list_init(&This->lightMap[i]); /* This element contains rubish due to the memcpy */
list_move_tail(&This->lightMap[i], &tmpBlock->lightMap[i]); /* Cleans the list entry in tmpBlock */
}
IWineD3DStateBlock_Release((IWineD3DStateBlock *)tmpBlock);
/*IDirect3DDevice_DeleteStateBlock(pDevice, tmpBlock);*/
} else {
unsigned int i, j;
PLIGHTINFOEL *src;
/* Recorded => Only update 'changed' values */
if (This->vertexShader != targetStateBlock->vertexShader) {
TRACE("Updating vertex shader from %p to %p\n", This->vertexShader, targetStateBlock->vertexShader);
@ -366,34 +399,49 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface)
/* Lights... For a recorded state block, we just had a chain of actions to perform,
so we need to walk that chain and update any actions which differ */
src = This->lights;
while (src != NULL) {
PLIGHTINFOEL *realLight = NULL;
for(i = 0; i < LIGHTMAP_SIZE; i++) {
struct list *e, *f;
LIST_FOR_EACH(e, &This->lightMap[i]) {
BOOL updated = FALSE;
PLIGHTINFOEL *src = LIST_ENTRY(e, PLIGHTINFOEL, entry), *realLight;
if(!src->changed || !src->enabledChanged) continue;
/* Locate the light in the live lights */
realLight = targetStateBlock->lights;
while (realLight != NULL && realLight->OriginalIndex != src->OriginalIndex) realLight = realLight->next;
/* If 'changed' then its a SetLight command. Rather than comparing to see
if the OriginalParms have changed and then copy them (twice through
memory) just do the copy */
/* Look up the light in the destination */
LIST_FOR_EACH(f, &targetStateBlock->lightMap[i]) {
realLight = LIST_ENTRY(f, PLIGHTINFOEL, entry);
if(realLight->OriginalIndex == src->OriginalIndex) {
if(src->changed) {
/* If the light exists, copy its parameters, otherwise copy the default parameters */
const WINED3DLIGHT* params = realLight? &realLight->OriginalParms: &WINED3D_default_light;
TRACE("Updating lights for light %d\n", src->OriginalIndex);
memcpy(&src->OriginalParms, params, sizeof(*params));
memcpy(&src->OriginalParms, &realLight->OriginalParms, sizeof(src->OriginalParms));
}
/* If 'enabledchanged' then its a LightEnable command */
if(src->enabledChanged) {
/* If the light exists, check if it's enabled, otherwise default is disabled state */
TRACE("Updating lightEnabled for light %d\n", src->OriginalIndex);
src->lightEnabled = realLight? realLight->lightEnabled: FALSE;
/* Need to double check because enabledChanged does not catch enabled -> disabled -> enabled
* or disabled -> enabled -> disabled changes
*/
if(realLight->glIndex == -1 && src->glIndex != -1) {
/* Light disabled */
This->activeLights[src->glIndex] = NULL;
} else if(realLight->glIndex != -1 && src->glIndex == -1){
/* Light enabled */
This->activeLights[realLight->glIndex] = src;
}
src->glIndex = realLight->glIndex;
}
updated = TRUE;
break;
}
}
src = src->next;
if(updated) {
/* Found a light, all done, proceed with next hash entry */
continue;
} else if(src->changed) {
/* Otherwise assign defaul params */
memcpy(&src->OriginalParms, &WINED3D_default_light, sizeof(src->OriginalParms));
} else {
/* Not enabled by default */
src->glIndex = -1;
}
}
}
/* Recorded => Only update 'changed' values */
@ -587,14 +635,19 @@ should really perform a delta so that only the changes get updated*/
if (/*TODO: 'magic' statetype, replace with BOOL This->blockType == D3DSBT_RECORDED || */This->blockType == WINED3DSBT_INIT || This->blockType == WINED3DSBT_ALL || This->blockType == WINED3DSBT_VERTEXSTATE) {
for(i = 0; i < LIGHTMAP_SIZE; i++) {
struct list *e;
PLIGHTINFOEL *toDo = This->lights;
while (toDo != NULL) {
if (toDo->changed)
IWineD3DDevice_SetLight(pDevice, toDo->OriginalIndex, &toDo->OriginalParms);
if (toDo->enabledChanged)
IWineD3DDevice_SetLightEnable(pDevice, toDo->OriginalIndex, toDo->lightEnabled);
toDo = toDo->next;
LIST_FOR_EACH(e, &This->lightMap[i]) {
PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
if(light->changed) {
IWineD3DDevice_SetLight(pDevice, light->OriginalIndex, &light->OriginalParms);
}
if(light->enabledChanged) {
IWineD3DDevice_SetLightEnable(pDevice, light->OriginalIndex, light->glIndex != -1);
}
}
}
/* Vertex Shader */

View File

@ -517,7 +517,6 @@ struct PLIGHTINFOEL {
WINED3DLIGHT OriginalParms; /* Note D3D8LIGHT == D3D9LIGHT */
DWORD OriginalIndex;
LONG glIndex;
BOOL lightEnabled;
BOOL changed;
BOOL enabledChanged;
@ -527,8 +526,7 @@ struct PLIGHTINFOEL {
float exponent;
float cutoff;
PLIGHTINFOEL *next;
PLIGHTINFOEL *prev;
struct list entry;
};
/* The default light parameters */
@ -1204,8 +1202,11 @@ struct IWineD3DStateBlockImpl
/* Transform */
WINED3DMATRIX transforms[HIGHEST_TRANSFORMSTATE + 1];
/* Lights */
PLIGHTINFOEL *lights; /* NOTE: active GL lights must be front of the chain */
/* Light hashmap . Collisions are handled using standard wine double linked lists */
#define LIGHTMAP_SIZE 43 /* Use of a prime number recommended. Set to 1 for a linked list! */
#define LIGHTMAP_HASHFUNC(x) ((x) % LIGHTMAP_SIZE) /* Primitive and simple function */
struct list lightMap[LIGHTMAP_SIZE]; /* Mashmap containing the lights */
PLIGHTINFOEL *activeLights[MAX_ACTIVE_LIGHTS]; /* Map of opengl lights to d3d lights */
/* Clipping */
double clipplane[MAX_CLIPPLANES][4];