wined3d: Replace the light chain with a hashmap.
This commit is contained in:
parent
5fce682f41
commit
acadf3f241
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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];
|
||||
|
|
Loading…
Reference in New Issue