Commit 78a9bf87 authored by Jason Edmeades's avatar Jason Edmeades Committed by Alexandre Julliard

Significantly improve the lighting code.

parent ab5063b2
...@@ -300,6 +300,10 @@ struct IDirect3DDevice8Impl ...@@ -300,6 +300,10 @@ struct IDirect3DDevice8Impl
STATEBLOCK StateBlock; STATEBLOCK StateBlock;
STATEBLOCK *UpdateStateBlock; STATEBLOCK *UpdateStateBlock;
/* Other required values */
float lightPosn[MAX_ACTIVE_LIGHTS][4];
float lightDirn[MAX_ACTIVE_LIGHTS][4];
/* OpenGL related */ /* OpenGL related */
GLXContext glCtx; GLXContext glCtx;
XVisualInfo *visInfo; XVisualInfo *visInfo;
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "winuser.h" #include "winuser.h"
#include "wingdi.h" #include "wingdi.h"
#include "wine/debug.h" #include "wine/debug.h"
#include "math.h"
#include "d3d8_private.h" #include "d3d8_private.h"
...@@ -995,6 +996,7 @@ HRESULT WINAPI IDirect3DDevice8Impl_Clear(LPDIRECT3DDEVICE8 iface, DWORD Count ...@@ -995,6 +996,7 @@ HRESULT WINAPI IDirect3DDevice8Impl_Clear(LPDIRECT3DDEVICE8 iface, DWORD Count
} }
HRESULT WINAPI IDirect3DDevice8Impl_SetTransform(LPDIRECT3DDEVICE8 iface, D3DTRANSFORMSTATETYPE d3dts,CONST D3DMATRIX* lpmatrix) { HRESULT WINAPI IDirect3DDevice8Impl_SetTransform(LPDIRECT3DDEVICE8 iface, D3DTRANSFORMSTATETYPE d3dts,CONST D3DMATRIX* lpmatrix) {
ICOM_THIS(IDirect3DDevice8Impl,iface); ICOM_THIS(IDirect3DDevice8Impl,iface);
int k;
/* Most of this routine, comments included copied from ddraw tree initially: */ /* Most of this routine, comments included copied from ddraw tree initially: */
TRACE("(%p) : State=%d\n", This, d3dts); TRACE("(%p) : State=%d\n", This, d3dts);
...@@ -1064,6 +1066,17 @@ HRESULT WINAPI IDirect3DDevice8Impl_SetTransform(LPDIRECT3DDEVICE8 iface, D3DT ...@@ -1064,6 +1066,17 @@ HRESULT WINAPI IDirect3DDevice8Impl_SetTransform(LPDIRECT3DDEVICE8 iface, D3DT
checkGLcall("glMatrixMode"); checkGLcall("glMatrixMode");
glLoadMatrixf((float *) &This->StateBlock.transforms[D3DTS_VIEW].u.m[0][0]); glLoadMatrixf((float *) &This->StateBlock.transforms[D3DTS_VIEW].u.m[0][0]);
checkGLcall("glLoadMatrixf"); checkGLcall("glLoadMatrixf");
/* If we are changing the View matrix, reset the light information to the new view */
if (d3dts == D3DTS_VIEW) {
for (k = 0; k < MAX_ACTIVE_LIGHTS; k++) {
glLightfv(GL_LIGHT0 + k, GL_POSITION, &This->lightPosn[k][0]);
checkGLcall("glLightfv posn");
glLightfv(GL_LIGHT0 + k, GL_SPOT_DIRECTION, &This->lightDirn[k][0]);
checkGLcall("glLightfv dirn");
}
}
glMultMatrixf((float *) &This->StateBlock.transforms[D3DTS_WORLDMATRIX(0)].u.m[0][0]); glMultMatrixf((float *) &This->StateBlock.transforms[D3DTS_WORLDMATRIX(0)].u.m[0][0]);
checkGLcall("glMultMatrixf"); checkGLcall("glMultMatrixf");
...@@ -1165,7 +1178,8 @@ HRESULT WINAPI IDirect3DDevice8Impl_GetMaterial(LPDIRECT3DDEVICE8 iface, D3DMA ...@@ -1165,7 +1178,8 @@ HRESULT WINAPI IDirect3DDevice8Impl_GetMaterial(LPDIRECT3DDEVICE8 iface, D3DMA
HRESULT WINAPI IDirect3DDevice8Impl_SetLight(LPDIRECT3DDEVICE8 iface, DWORD Index,CONST D3DLIGHT8* pLight) { HRESULT WINAPI IDirect3DDevice8Impl_SetLight(LPDIRECT3DDEVICE8 iface, DWORD Index,CONST D3DLIGHT8* pLight) {
float colRGBA[] = {0.0, 0.0, 0.0, 0.0}; float colRGBA[] = {0.0, 0.0, 0.0, 0.0};
float coords[] = {0.0, 0.0, 0.0, 0.0}; float rho;
float quad_att;
ICOM_THIS(IDirect3DDevice8Impl,iface); ICOM_THIS(IDirect3DDevice8Impl,iface);
TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight); TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
...@@ -1212,52 +1226,80 @@ HRESULT WINAPI IDirect3DDevice8Impl_SetLight(LPDIRECT3DDEVICE8 iface, DWORD In ...@@ -1212,52 +1226,80 @@ HRESULT WINAPI IDirect3DDevice8Impl_SetLight(LPDIRECT3DDEVICE8 iface, DWORD In
glLightfv(GL_LIGHT0+Index, GL_AMBIENT, colRGBA); glLightfv(GL_LIGHT0+Index, GL_AMBIENT, colRGBA);
checkGLcall("glLightfv"); 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... */ /* Attenuation - Are these right? guessing... */
glLightf(GL_LIGHT0+Index, GL_CONSTANT_ATTENUATION, pLight->Attenuation0); glLightf(GL_LIGHT0+Index, GL_CONSTANT_ATTENUATION, pLight->Attenuation0);
checkGLcall("glLightf"); checkGLcall("glLightf");
glLightf(GL_LIGHT0+Index, GL_LINEAR_ATTENUATION, pLight->Attenuation1); glLightf(GL_LIGHT0+Index, GL_LINEAR_ATTENUATION, pLight->Attenuation1);
checkGLcall("glLightf"); checkGLcall("glLightf");
glLightf(GL_LIGHT0+Index, GL_QUADRATIC_ATTENUATION, pLight->Attenuation2);
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"); checkGLcall("glLightf");
switch (pLight->Type) { switch (pLight->Type) {
case D3DLIGHT_POINT: case D3DLIGHT_POINT:
/* Position */ /* Position */
coords[0] = pLight->Position.x; This->lightPosn[Index][0] = pLight->Position.x;
coords[1] = pLight->Position.y; This->lightPosn[Index][1] = pLight->Position.y;
coords[2] = pLight->Position.z; This->lightPosn[Index][2] = pLight->Position.z;
coords[3] = 1.0; This->lightPosn[Index][3] = 1.0;
glLightfv(GL_LIGHT0+Index, GL_POSITION, coords); glLightfv(GL_LIGHT0+Index, GL_POSITION, &This->lightPosn[Index][0]);
checkGLcall("glLightfv"); checkGLcall("glLightfv");
glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, 180);
checkGLcall("glLightf");
/* FIXME: Range */ /* FIXME: Range */
break; break;
case D3DLIGHT_SPOT: case D3DLIGHT_SPOT:
/* Position */ /* Position */
coords[0] = pLight->Position.x; This->lightPosn[Index][0] = pLight->Position.x;
coords[1] = pLight->Position.y; This->lightPosn[Index][1] = pLight->Position.y;
coords[2] = pLight->Position.z; This->lightPosn[Index][2] = pLight->Position.z;
coords[3] = 0.0; This->lightPosn[Index][3] = 1.0;
glLightfv(GL_LIGHT0+Index, GL_POSITION, coords); glLightfv(GL_LIGHT0+Index, GL_POSITION, &This->lightPosn[Index][0]);
checkGLcall("glLightfv"); checkGLcall("glLightfv");
/* Direction */ /* Direction */
coords[0] = pLight->Direction.x; This->lightDirn[Index][0] = pLight->Direction.x;
coords[1] = pLight->Direction.y; This->lightDirn[Index][1] = pLight->Direction.y;
coords[2] = pLight->Direction.z; This->lightDirn[Index][2] = pLight->Direction.z;
coords[3] = 1.0; This->lightDirn[Index][3] = 1.0;
glLightfv(GL_LIGHT0+Index, GL_SPOT_DIRECTION, coords); glLightfv(GL_LIGHT0+Index, GL_SPOT_DIRECTION, &This->lightDirn[Index][0]);
checkGLcall("glLightfv"); checkGLcall("glLightfv");
/*
* 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;
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);
/* FIXME: Range */ /* FIXME: Range */
break; break;
case D3DLIGHT_DIRECTIONAL: case D3DLIGHT_DIRECTIONAL:
/* Direction */ /* Direction */
coords[0] = -pLight->Direction.x; This->lightPosn[Index][0] = -pLight->Direction.x;
coords[1] = pLight->Direction.y; This->lightPosn[Index][1] = -pLight->Direction.y;
coords[2] = -pLight->Direction.z; This->lightPosn[Index][2] = -pLight->Direction.z;
coords[3] = 0.0; This->lightPosn[Index][3] = 0.0;
glLightfv(GL_LIGHT0+Index, GL_POSITION, coords); /* Note gl uses w position of 0 for direction! */ glLightfv(GL_LIGHT0+Index, GL_POSITION, &This->lightPosn[Index][0]); /* Note gl uses w position of 0 for direction! */
checkGLcall("glLightfv"); checkGLcall("glLightfv");
glLightf(GL_LIGHT0+Index, GL_SPOT_CUTOFF, 180.0f); glLightf(GL_LIGHT0+Index, GL_SPOT_CUTOFF, 180.0f);
...@@ -1269,7 +1311,9 @@ HRESULT WINAPI IDirect3DDevice8Impl_SetLight(LPDIRECT3DDEVICE8 iface, DWORD In ...@@ -1269,7 +1311,9 @@ HRESULT WINAPI IDirect3DDevice8Impl_SetLight(LPDIRECT3DDEVICE8 iface, DWORD In
FIXME("Unrecognized light type %d\n", pLight->Type); FIXME("Unrecognized light type %d\n", pLight->Type);
} }
/* FIXME: Falloff, Theta, Phi; */ /* Restore the modelview matrix */
glPopMatrix();
return D3D_OK; return D3D_OK;
} }
HRESULT WINAPI IDirect3DDevice8Impl_GetLight(LPDIRECT3DDEVICE8 iface, DWORD Index,D3DLIGHT8* pLight) { HRESULT WINAPI IDirect3DDevice8Impl_GetLight(LPDIRECT3DDEVICE8 iface, DWORD Index,D3DLIGHT8* pLight) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment