MaxActiveLights means number of concurrent lights, but any number can

be  set up. Change support for lights into a linked list and only set
up an equivalent gl light when the light is enabled.
This commit is contained in:
Jason Edmeades 2003-09-30 00:21:07 +00:00 committed by Alexandre Julliard
parent ba69d05022
commit 8b2c10bcd4
4 changed files with 566 additions and 179 deletions

View File

@ -67,7 +67,6 @@ extern int num_lock;
/* Device caps */
#define MAX_PALETTES 256
#define MAX_STREAMS 16
#define MAX_ACTIVE_LIGHTS 8
#define MAX_CLIPPLANES D3DMAXUSERCLIPPLANES
#define MAX_LEVELS 256
@ -174,6 +173,27 @@ typedef struct PSHADEROUTPUTDATA8 {
D3DSHADERVECTOR oDepth;
} PSHADEROUTPUTDATA8;
/*
* Private definitions for internal use only
*/
typedef struct PLIGHTINFOEL PLIGHTINFOEL;
struct PLIGHTINFOEL {
D3DLIGHT8 OriginalParms;
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;
};
/*
* Macros
@ -326,10 +346,6 @@ struct IDirect3DDevice8Impl
IDirect3DStateBlockImpl *StateBlock;
IDirect3DStateBlockImpl *UpdateStateBlock;
/* Other required values */
float lightPosn[MAX_ACTIVE_LIGHTS][4];
float lightDirn[MAX_ACTIVE_LIGHTS][4];
/* palettes texture management */
PALETTEENTRY palettes[MAX_PALETTES][256];
UINT currentPalette;
@ -354,6 +370,7 @@ struct IDirect3DDevice8Impl
Window win;
GLXContext render_ctx;
Drawable drawable;
GLint maxConcurrentLights;
/* OpenGL Extension related */
@ -1015,9 +1032,7 @@ extern HRESULT WINAPI IDirect3DVolumeTexture8Impl_AddDirtyBox(LPDIRECT3D
/* Note: Very long winded but I do not believe gl Lists will */
/* resolve everything we need, so doing it manually for now */
typedef struct SAVEDSTATES {
BOOL lightEnable[MAX_ACTIVE_LIGHTS];
BOOL Indices;
BOOL lights[MAX_ACTIVE_LIGHTS];
BOOL material;
BOOL stream_source[MAX_STREAMS];
BOOL textures[8];
@ -1059,9 +1074,6 @@ struct IDirect3DStateBlockImpl {
SAVEDSTATES Changed;
SAVEDSTATES Set;
/* Light Enable */
BOOL lightEnable[MAX_ACTIVE_LIGHTS];
/* ClipPlane */
double clipplane[MAX_CLIPPLANES][4];
@ -1081,7 +1093,7 @@ struct IDirect3DStateBlockImpl {
DWORD texture_state[8][HIGHEST_TEXTURE_STATE];
/* Lights */
D3DLIGHT8 lights[MAX_ACTIVE_LIGHTS];
PLIGHTINFOEL *lights; /* NOTE: active GL lights must be front of the chain */
/* Material */
D3DMATERIAL8 material;
@ -1321,4 +1333,13 @@ extern LONG primCounter;
#define TRACE_VECTOR(name) TRACE( #name "=(%f, %f, %f, %f)\n", name.x, name.y, name.z, name.w);
#define TRACE_STRIDED(sd,name) TRACE( #name "=(data:%p, stride:%ld, type:%ld)\n", sd->u.s.name.lpData, sd->u.s.name.dwStride, sd->u.s.name.dwType);
#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; \
} \
}
#endif /* __WINE_D3DX8_PRIVATE_H */

View File

@ -144,6 +144,95 @@ void setupTextureStates(LPDIRECT3DDEVICE8 iface, DWORD Stage, DWORD Flags) {
TRACE("-----------------------> Updated the texture at stage %ld to have new texture state information\n", Stage);
}
/* Convert the D3DLIGHT8 properties into equivalent gl lights */
void setup_light(LPDIRECT3DDEVICE8 iface, LONG Index, PLIGHTINFOEL *lightInfo) {
float quad_att;
float colRGBA[] = {0.0, 0.0, 0.0, 0.0};
ICOM_THIS(IDirect3DDevice8Impl,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();
}
/* Setup this textures matrix */
static void set_texture_matrix(float *smat, DWORD flags)
{
@ -407,7 +496,7 @@ HRESULT WINAPI IDirect3DDevice8Impl_Present(LPDIRECT3DDEVICE8 iface, CONST REC
frames++;
/* every 1.5 seconds */
if (time - prev_time > 1500) {
TRACE_(fps)("@@@ %.2ffps\n", 1000.0*frames/(time - prev_time));
TRACE_(fps)("@ approx %.2ffps\n", 1000.0*frames/(time - prev_time));
prev_time = time;
frames = 0;
}
@ -1411,6 +1500,8 @@ HRESULT WINAPI IDirect3DDevice8Impl_SetTransform(LPDIRECT3DDEVICE8 iface, D3DT
}
} else if (d3dts == D3DTS_VIEW) { /* handle the VIEW matrice */
PLIGHTINFOEL *lightChain = NULL;
float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};
This->modelview_valid = FALSE;
This->view_ident = !memcmp(lpmatrix, identity, 16*sizeof(float));
@ -1427,11 +1518,13 @@ HRESULT WINAPI IDirect3DDevice8Impl_SetTransform(LPDIRECT3DDEVICE8 iface, D3DT
*/
/* Reset lights */
for (k = 0; k < GL_LIMITS(lights); k++) {
glLightfv(GL_LIGHT0 + k, GL_POSITION, This->lightPosn[k]);
lightChain = This->StateBlock->lights;
while (lightChain && lightChain->glIndex != -1) {
glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
checkGLcall("glLightfv posn");
glLightfv(GL_LIGHT0 + k, GL_SPOT_DIRECTION, This->lightDirn[k]);
glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
checkGLcall("glLightfv dirn");
lightChain = lightChain->next;
}
/* Reset Clipping Planes if clipping is enabled */
for (k = 0; k < GL_LIMITS(clipplanes); k++) {
@ -1586,19 +1679,84 @@ HRESULT WINAPI IDirect3DDevice8Impl_GetMaterial(LPDIRECT3DDEVICE8 iface, D3DMA
return D3D_OK;
}
/* 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 IDirect3DDevice8Impl_SetLight(LPDIRECT3DDEVICE8 iface, DWORD Index, CONST D3DLIGHT8* pLight) {
float colRGBA[] = {0.0, 0.0, 0.0, 0.0};
float rho;
float quad_att;
PLIGHTINFOEL *object, *temp;
ICOM_THIS(IDirect3DDevice8Impl,iface);
TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
if (Index >= GL_LIMITS(lights)) {
TRACE("Cannot handle more lights than device supports\n");
return D3DERR_INVALIDCALL;
/* 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(D3DLIGHT8));
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 didnt 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,
@ -1607,90 +1765,32 @@ HRESULT WINAPI IDirect3DDevice8Impl_SetLight(LPDIRECT3DDEVICE8 iface, DWORD In
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);
This->UpdateStateBlock->Changed.lights[Index] = TRUE;
This->UpdateStateBlock->Set.lights[Index] = TRUE;
memcpy(&This->UpdateStateBlock->lights[Index], pLight, sizeof(D3DLIGHT8));
/* Handle recording of state blocks */
if (This->isRecordingState) {
TRACE("Recording... not performing anything\n");
return D3D_OK;
}
ENTER_GL();
/* Diffuse: */
colRGBA[0] = pLight->Diffuse.r;
colRGBA[1] = pLight->Diffuse.g;
colRGBA[2] = pLight->Diffuse.b;
colRGBA[3] = pLight->Diffuse.a;
glLightfv(GL_LIGHT0+Index, GL_DIFFUSE, colRGBA);
checkGLcall("glLightfv");
/* Specular */
colRGBA[0] = pLight->Specular.r;
colRGBA[1] = pLight->Specular.g;
colRGBA[2] = pLight->Specular.b;
colRGBA[3] = pLight->Specular.a;
glLightfv(GL_LIGHT0+Index, GL_SPECULAR, colRGBA);
checkGLcall("glLightfv");
/* Ambient */
colRGBA[0] = pLight->Ambient.r;
colRGBA[1] = pLight->Ambient.g;
colRGBA[2] = pLight->Ambient.b;
colRGBA[3] = pLight->Ambient.a;
glLightfv(GL_LIGHT0+Index, GL_AMBIENT, colRGBA);
checkGLcall("glLightfv");
/* 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]);
/* Attenuation - Are these right? guessing... */
glLightf(GL_LIGHT0+Index, GL_CONSTANT_ATTENUATION, pLight->Attenuation0);
checkGLcall("glLightf");
glLightf(GL_LIGHT0+Index, GL_LINEAR_ATTENUATION, pLight->Attenuation1);
checkGLcall("glLightf");
quad_att = 1.4/(pLight->Range*pLight->Range);
if (quad_att < pLight->Attenuation2) quad_att = pLight->Attenuation2;
glLightf(GL_LIGHT0+Index, GL_QUADRATIC_ATTENUATION, quad_att);
checkGLcall("glLightf");
/* Save away the information */
memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT8));
switch (pLight->Type) {
case D3DLIGHT_POINT:
/* Position */
This->lightPosn[Index][0] = pLight->Position.x;
This->lightPosn[Index][1] = pLight->Position.y;
This->lightPosn[Index][2] = pLight->Position.z;
This->lightPosn[Index][3] = 1.0;
glLightfv(GL_LIGHT0+Index, GL_POSITION, &This->lightPosn[Index][0]);
checkGLcall("glLightfv");
glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, 180);
checkGLcall("glLightf");
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_SPOT:
/* Position */
This->lightPosn[Index][0] = pLight->Position.x;
This->lightPosn[Index][1] = pLight->Position.y;
This->lightPosn[Index][2] = pLight->Position.z;
This->lightPosn[Index][3] = 1.0;
glLightfv(GL_LIGHT0+Index, GL_POSITION, &This->lightPosn[Index][0]);
checkGLcall("glLightfv");
object->lightPosn[0] = pLight->Position.x;
object->lightPosn[1] = pLight->Position.y;
object->lightPosn[2] = pLight->Position.z;
object->lightPosn[3] = 1.0;
/* Direction */
This->lightDirn[Index][0] = pLight->Direction.x;
This->lightDirn[Index][1] = pLight->Direction.y;
This->lightDirn[Index][2] = pLight->Direction.z;
This->lightDirn[Index][3] = 1.0;
glLightfv(GL_LIGHT0+Index, GL_SPOT_DIRECTION, &This->lightDirn[Index][0]);
checkGLcall("glLightfv");
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
@ -1705,89 +1805,293 @@ HRESULT WINAPI IDirect3DDevice8Impl_SetLight(LPDIRECT3DDEVICE8 iface, DWORD In
rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
}
if (rho < 0.0001) rho = 0.0001f;
glLightf(GL_LIGHT0 + Index, GL_SPOT_EXPONENT, -0.3/log(cos(rho/2)));
glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, pLight->Phi*90/M_PI);
object->exponent = -0.3/log(cos(rho/2));
object->cutoff = pLight->Phi*90/M_PI;
/* FIXME: Range */
break;
case D3DLIGHT_DIRECTIONAL:
/* Direction */
This->lightPosn[Index][0] = -pLight->Direction.x;
This->lightPosn[Index][1] = -pLight->Direction.y;
This->lightPosn[Index][2] = -pLight->Direction.z;
This->lightPosn[Index][3] = 0.0;
glLightfv(GL_LIGHT0+Index, GL_POSITION, &This->lightPosn[Index][0]); /* Note gl uses w position of 0 for direction! */
checkGLcall("glLightfv");
glLightf(GL_LIGHT0+Index, GL_SPOT_CUTOFF, 180.0f);
glLightf(GL_LIGHT0+Index, GL_SPOT_EXPONENT, 0.0f);
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;
default:
FIXME("Unrecognized light type %d\n", pLight->Type);
}
/* Restore the modelview matrix */
glPopMatrix();
LEAVE_GL();
/* Update the live definitions if the light is currently assigned a glIndex */
if (object->glIndex != -1) {
setup_light(iface, object->glIndex, object);
}
DUMP_LIGHT_CHAIN();
return D3D_OK;
}
HRESULT WINAPI IDirect3DDevice8Impl_GetLight(LPDIRECT3DDEVICE8 iface, DWORD Index,D3DLIGHT8* pLight) {
ICOM_THIS(IDirect3DDevice8Impl,iface);
PLIGHTINFOEL *lightInfo = NULL;
ICOM_THIS(IDirect3DDevice8Impl,iface);
TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
if (Index >= GL_LIMITS(lights)) {
TRACE("Cannot handle more lights than device supports\n");
/* 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, &This->StateBlock->lights[Index], sizeof(D3DLIGHT8));
memcpy(pLight, &lightInfo->OriginalParms, sizeof(D3DLIGHT8));
return D3D_OK;
}
HRESULT WINAPI IDirect3DDevice8Impl_LightEnable(LPDIRECT3DDEVICE8 iface, DWORD Index,BOOL Enable) {
PLIGHTINFOEL *lightInfo = NULL;
ICOM_THIS(IDirect3DDevice8Impl,iface);
TRACE("(%p) : Idx(%ld), enable? %d\n", This, Index, Enable);
if (Index >= GL_LIMITS(lights)) {
TRACE("Cannot handle more lights than device supports\n");
return D3DERR_INVALIDCALL;
}
This->UpdateStateBlock->Changed.lightEnable[Index] = TRUE;
This->UpdateStateBlock->Set.lightEnable[Index] = TRUE;
This->UpdateStateBlock->lightEnable[Index] = Enable;
/* Handle recording of state blocks */
/* If recording state block, just add to end of lights chain with changedEnable set to true */
if (This->isRecordingState) {
TRACE("Recording... not performing anything\n");
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;
}
ENTER_GL();
if (Enable) {
glEnable(GL_LIGHT0 + Index);
checkGLcall("glEnable GL_LIGHT0+Index");
} else {
glDisable(GL_LIGHT0 + Index);
checkGLcall("glDisable GL_LIGHT0+Index");
}
LEAVE_GL();
/* 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) {
D3DLIGHT8 lightParms;
/* Warning - untested code :-) Prob safe to change fixme to a trace but
wait until someone confirms it seems to work! */
FIXME("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;
IDirect3DDevice8Impl_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();
}
}
}
DUMP_LIGHT_CHAIN();
return D3D_OK;
}
HRESULT WINAPI IDirect3DDevice8Impl_GetLightEnable(LPDIRECT3DDEVICE8 iface, DWORD Index,BOOL* pEnable) {
ICOM_THIS(IDirect3DDevice8Impl,iface);
TRACE("(%p) : for idx(%ld)\n", This, Index);
if (Index >= GL_LIMITS(lights)) {
TRACE("Cannot handle more lights than device supports\n");
PLIGHTINFOEL *lightInfo = NULL;
ICOM_THIS(IDirect3DDevice8Impl,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 = This->StateBlock->lightEnable[Index];
*pEnable = lightInfo->lightEnabled;
return D3D_OK;
}
HRESULT WINAPI IDirect3DDevice8Impl_SetClipPlane(LPDIRECT3DDEVICE8 iface, DWORD Index,CONST float* pPlane) {

View File

@ -160,9 +160,9 @@ UINT WINAPI IDirect3D8Impl_GetAdapterModeCount (LPDIRECT3D8 iface,
int i = 0;
while (EnumDisplaySettingsExW(NULL, i, &DevModeW, 0)) {
TRACE("(%p}->(Adapter: %d) => %d\n", This, Adapter, i);
i++;
}
TRACE("(%p}->(Adapter: %d) => %d\n", This, Adapter, i);
return i;
} else {
FIXME("Adapter not primary display\n");
@ -190,8 +190,12 @@ HRESULT WINAPI IDirect3D8Impl_EnumAdapterModes (LPDIRECT3D8 iface,
{
pMode->Width = DevModeW.dmPelsWidth;
pMode->Height = DevModeW.dmPelsHeight;
bpp = DevModeW.dmBitsPerPel;
pMode->RefreshRate = D3DADAPTER_DEFAULT;
bpp = DevModeW.dmBitsPerPel;
if (DevModeW.dmFields&DM_DISPLAYFREQUENCY)
{
pMode->RefreshRate = DevModeW.dmDisplayFrequency;
}
}
else
{
@ -229,16 +233,18 @@ HRESULT WINAPI IDirect3D8Impl_GetAdapterDisplayMode (LPDIRECT3D8 iface,
}
if (Adapter == 0) { /* Display */
HDC hdc;
int bpp = 0;
DEVMODEW DevModeW;
pMode->Width = GetSystemMetrics(SM_CXSCREEN);
pMode->Height = GetSystemMetrics(SM_CYSCREEN);
pMode->RefreshRate = 85; /*FIXME: How to identify? */
hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
bpp = GetDeviceCaps(hdc, BITSPIXEL);
DeleteDC(hdc);
EnumDisplaySettingsExW(NULL, (DWORD)-1, &DevModeW, 0);
pMode->Width = DevModeW.dmPelsWidth;
pMode->Height = DevModeW.dmPelsHeight;
bpp = DevModeW.dmBitsPerPel;
pMode->RefreshRate = D3DADAPTER_DEFAULT;
if (DevModeW.dmFields&DM_DISPLAYFREQUENCY)
{
pMode->RefreshRate = DevModeW.dmDisplayFrequency;
}
switch (bpp) {
case 8: pMode->Format = D3DFMT_R3G3B2; break;
@ -621,7 +627,7 @@ HRESULT WINAPI IDirect3D8Impl_GetDeviceCaps(LPDIRECT3D8 iface, UINT Adapter, D
TRACE("GLCaps: GL_MAX_CLIP_PLANES=%ld\n", pCaps->MaxUserClipPlanes);
glGetIntegerv(GL_MAX_LIGHTS, &gl_max);
pCaps->MaxActiveLights = min(MAX_ACTIVE_LIGHTS, gl_max);
pCaps->MaxActiveLights = gl_max;
TRACE("GLCaps: GL_MAX_LIGHTS=%ld\n", pCaps->MaxActiveLights);
#if defined(GL_ARB_vertex_blend)
@ -716,7 +722,7 @@ static void IDirect3D8Impl_FillGLCaps(LPDIRECT3D8 iface, Display* display) {
TRACE("ClipPlanes support - num Planes=%d\n", gl_max);
glGetIntegerv(GL_MAX_LIGHTS, &gl_max);
This->gl_info.max_lights = min(MAX_ACTIVE_LIGHTS, gl_max);
This->gl_info.max_lights = gl_max;
TRACE("Lights support - max lights=%d\n", gl_max);
/* Parse the gl supported features, in theory enabling parts of our code appropriately */
@ -1151,7 +1157,7 @@ HRESULT WINAPI IDirect3D8Impl_CreateDevice (LPDIRECT3D8 iface,
object->proj_valid = 0;
object->view_ident = 1;
object->last_was_rhw = 0;
glGetIntegerv(GL_MAX_LIGHTS, &object->maxConcurrentLights);
TRACE("(%p,%d) All defaults now set up, leaving CreateDevice with %p\n", This, Adapter, object);
return D3D_OK;
}

View File

@ -321,9 +321,31 @@ HRESULT WINAPI IDirect3DDeviceImpl_CreateStateBlock(IDirect3DDevice8Impl* This,
object->Changed.texture_state[j][SavedVertexStates_T[i]] = TRUE;
}
}
for (i = 0; i < GL_LIMITS(lights); i++) {
object->Changed.lightEnable[i] = TRUE;
object->Changed.lights[i] = TRUE;
/* 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 D3DERR_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;
}
dst = newEl;
src = src->next;
}
}
} else {
@ -337,7 +359,16 @@ HRESULT WINAPI IDirect3DDeviceImpl_CreateStateBlock(IDirect3DDevice8Impl* This,
/** yakkk temporary waiting for Release */
HRESULT WINAPI IDirect3DDeviceImpl_DeleteStateBlock(IDirect3DDevice8Impl* This, IDirect3DStateBlockImpl* pSB) {
PLIGHTINFOEL *tmp;
TRACE("(%p) : freeing StateBlock %p\n", This, pSB);
tmp = pSB->lights;
if (tmp) tmp = tmp->next;
while (tmp != NULL) {
HeapFree(GetProcessHeap(), 0, (void *)(tmp->prev));
tmp = tmp->next;
}
if (tmp) HeapFree(GetProcessHeap(), 0, (void *)tmp);
HeapFree(GetProcessHeap(), 0, (void *)pSB);
return D3D_OK;
}
@ -397,12 +428,13 @@ HRESULT WINAPI IDirect3DDeviceImpl_ApplyStateBlock(IDirect3DDevice8Impl* This,
if (pSB->blockType == D3DSBT_RECORDED || pSB->blockType == D3DSBT_ALL || pSB->blockType == D3DSBT_VERTEXSTATE) {
for (i = 0; i < GL_LIMITS(lights); i++) {
if (pSB->Set.lightEnable[i] && pSB->Changed.lightEnable[i])
IDirect3DDevice8Impl_LightEnable(iface, i, pSB->lightEnable[i]);
if (pSB->Set.lights[i] && pSB->Changed.lights[i])
IDirect3DDevice8Impl_SetLight(iface, i, &pSB->lights[i]);
PLIGHTINFOEL *toDo = pSB->lights;
while (toDo != NULL) {
if (toDo->changed)
IDirect3DDevice8Impl_SetLight(iface, toDo->OriginalIndex, &toDo->OriginalParms);
if (toDo->enabledChanged)
IDirect3DDevice8Impl_LightEnable(iface, toDo->OriginalIndex, toDo->lightEnabled);
toDo = toDo->next;
}
if (pSB->Set.vertexShader && pSB->Changed.vertexShader)
@ -514,6 +546,7 @@ HRESULT WINAPI IDirect3DDeviceImpl_ApplyStateBlock(IDirect3DDevice8Impl* This,
HRESULT WINAPI IDirect3DDeviceImpl_CaptureStateBlock(IDirect3DDevice8Impl* This, IDirect3DStateBlockImpl* updateBlock) {
LPDIRECT3DDEVICE8 iface = (LPDIRECT3DDEVICE8) This;
PLIGHTINFOEL *tmp;
TRACE("(%p) : Updating state block %p ------------------v \n", This, updateBlock);
@ -521,14 +554,18 @@ HRESULT WINAPI IDirect3DDeviceImpl_CaptureStateBlock(IDirect3DDevice8Impl* This,
if (updateBlock->blockType != D3DSBT_RECORDED) {
IDirect3DStateBlockImpl* tmpBlock;
IDirect3DDeviceImpl_CreateStateBlock(This, updateBlock->blockType, &tmpBlock);
memcpy(updateBlock, tmpBlock, sizeof(IDirect3DStateBlockImpl));
IDirect3DDeviceImpl_DeleteStateBlock(This, tmpBlock);
/* FIXME: This will record states of new lights! May need to have and save set_lights
across this action */
/* Note just swap the light chains over so when deleting, the old one goes */
tmp = updateBlock->lights;
memcpy(updateBlock, tmpBlock, sizeof(IDirect3DStateBlockImpl));
tmpBlock->lights = tmp;
/* Delete the temporary one (which points to the old light chain though */
IDirect3DDeviceImpl_DeleteStateBlock(This, tmpBlock);
} else {
int i, j;
PLIGHTINFOEL *src;
/* Recorded => Only update 'changed' values */
if (updateBlock->Set.vertexShader && updateBlock->VertexShader != This->StateBlock->VertexShader) {
@ -538,23 +575,42 @@ HRESULT WINAPI IDirect3DDeviceImpl_CaptureStateBlock(IDirect3DDevice8Impl* This,
/* TODO: Vertex Shader Constants */
for (i = 0; i < GL_LIMITS(lights); i++) {
if (updateBlock->Set.lightEnable[i] && This->StateBlock->lightEnable[i] != updateBlock->lightEnable[i]) {
TRACE("Updating light enable for light %d to %d\n", i, This->StateBlock->lightEnable[i]);
updateBlock->lightEnable[i] = This->StateBlock->lightEnable[i];
}
/* 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 = updateBlock->lights;
while (src != NULL) {
PLIGHTINFOEL *realLight = NULL;
/* Locate the light in the live lights */
realLight = This->StateBlock->lights;
while (realLight != NULL && realLight->OriginalIndex != src->OriginalIndex) realLight = realLight->next;
if (updateBlock->Set.lights[i] && memcmp(&This->StateBlock->lights[i],
&updateBlock->lights[i],
sizeof(D3DLIGHT8)) != 0) {
TRACE("Updating lights for light %d\n", i);
memcpy(&updateBlock->lights[i], &This->StateBlock->lights[i], sizeof(D3DLIGHT8));
}
if (realLight == NULL) {
FIXME("A captured light no longer exists...?\n");
} else {
/* 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 */
if (src->changed) {
TRACE("Updating lights for light %ld\n", src->OriginalIndex);
memcpy(&src->OriginalParms, &realLight->OriginalParms, sizeof(PLIGHTINFOEL));
}
/* If 'enabledChanged' then its a LightEnable command */
if (src->enabledChanged) {
TRACE("Updating lightEnabled for light %ld\n", src->OriginalIndex);
src->lightEnabled = realLight->lightEnabled;
}
}
src = src->next;
}
if (updateBlock->Set.pixelShader && updateBlock->PixelShader != This->StateBlock->PixelShader) {
TRACE("Updating pixel shader to %ld\n", This->StateBlock->PixelShader);
updateBlock->lights[i] = This->StateBlock->lights[i];
IDirect3DDevice8Impl_SetVertexShader(iface, updateBlock->PixelShader);
}