|
|
/*==========================================================================;
* * Copyright (C) 1998 Microsoft Corporation. All Rights Reserved. * * File: rgblt.cpp * Content: Direct3D lighting * ***************************************************************************/
#include "pch.cpp"
#pragma hdrstop
#include "light.h"
#include "drawprim.hpp"
// Functions to use when lighting is done in the camera space
LIGHT_VERTEX_FUNC_TABLE lightVertexTable = { Directional7, PointSpot7, DirectionalFirst, DirectionalNext, PointSpotFirst, PointSpotNext };
// Functions to use when lighting is done in the model space
static LIGHT_VERTEX_FUNC_TABLE lightVertexTableModel = { Directional7Model, PointSpot7Model, DirectionalFirstModel, DirectionalNextModel, PointSpotFirstModel, PointSpotNextModel }; //-------------------------------------------------------------------------
SpecularTable* CreateSpecularTable(D3DVALUE power) { SpecularTable* spec; int i; float delta = 1.0f/255.0f; float v;
D3DMalloc((void**)&spec, sizeof(SpecularTable));
if (spec == NULL) return NULL;
spec->power = power;
v = 0.0; for (i = 0; i < 256; i++) { spec->table[i] = powf(v, power); v += delta; }
for (; i < 260; i++) spec->table[i] = 1.0f;
return spec; } //-------------------------------------------------------------------------
static void inverseRotateVector(D3DVECTOR* d, D3DVECTOR* v, D3DMATRIXI* M) { D3DVALUE vx = v->x; D3DVALUE vy = v->y; D3DVALUE vz = v->z; d->x = RLDDIFMul16(vx, M->_11) + RLDDIFMul16(vy, M->_12) + RLDDIFMul16(vz, M->_13); d->y = RLDDIFMul16(vx, M->_21) + RLDDIFMul16(vy, M->_22) + RLDDIFMul16(vz, M->_23); d->z = RLDDIFMul16(vx, M->_31) + RLDDIFMul16(vy, M->_32) + RLDDIFMul16(vz, M->_33); }
static void inverseTransformVector(D3DVECTOR* result, D3DVECTOR* v, D3DMATRIXI* M) { D3DVALUE vx = v->x; D3DVALUE vy = v->y; D3DVALUE vz = v->z; vx -= M->_41; vy -= M->_42; vz -= M->_43; result->x = RLDDIFMul16(vx, M->_11) + RLDDIFMul16(vy, M->_12) + RLDDIFMul16(vz, M->_13); result->y = RLDDIFMul16(vx, M->_21) + RLDDIFMul16(vy, M->_22) + RLDDIFMul16(vz, M->_23); result->z = RLDDIFMul16(vx, M->_31) + RLDDIFMul16(vy, M->_32) + RLDDIFMul16(vz, M->_33); } //-----------------------------------------------------------------------
// Every time the world matrix is modified or lights data is changed the
// lighting vectors have to change to match the model space of the new data
// to be rendered.
// Every time light data is changed or material data is changed or lighting
// state is changed, some pre-computed lighting values sould be updated
//
void D3DFE_UpdateLights(LPD3DHAL lpDevI) { D3DFE_PROCESSVERTICES* pv = lpDevI->m_pv; D3DFE_LIGHTING& LIGHTING = pv->lighting; D3DI_LIGHT *light = LIGHTING.activeLights; D3DVECTOR t; BOOL specular; // TRUE, if specular component sould be computed
D3DMATERIAL8 *mat = &LIGHTING.material;
if (lpDevI->dwFEFlags & (D3DFE_MATERIAL_DIRTY | D3DFE_LIGHTS_DIRTY)) {
SpecularTable* spec;
for (spec = LIST_FIRST(&lpDevI->specular_tables); spec; spec = LIST_NEXT(spec,list)) { if (spec->power == pv->lighting.material.Power) break; } if (spec == NULL) { spec = CreateSpecularTable(pv->lighting.material.Power); if (spec == NULL) { D3D_ERR("Failed to allocate internal specular table"); throw E_OUTOFMEMORY; } LIST_INSERT_ROOT(&lpDevI->specular_tables, spec, list); } lpDevI->specular_table = spec;
if (pv->lighting.material.Power > D3DVAL(0.001)) pv->lighting.specThreshold = D3DVAL(pow(0.001, 1.0/pv->lighting.material.Power)); else pv->lighting.specThreshold = 0;
if (lpDevI->specular_table && pv->dwDeviceFlags & D3DDEV_SPECULARENABLE) specular = TRUE; else specular = FALSE;
LIGHTING.materialAlpha = FTOI(D3DVAL(255) * mat->Diffuse.a); if (LIGHTING.materialAlpha < 0) LIGHTING.materialAlpha = 0; else if (LIGHTING.materialAlpha > 255) LIGHTING.materialAlpha = 255 << 24; else LIGHTING.materialAlpha <<= 24;
LIGHTING.materialAlphaS = FTOI(D3DVAL(255) * mat->Specular.a); if (LIGHTING.materialAlphaS < 0) LIGHTING.materialAlphaS = 0; else if (LIGHTING.materialAlphaS > 255) LIGHTING.materialAlphaS = 255 << 24; else LIGHTING.materialAlphaS <<= 24;
LIGHTING.currentSpecTable = lpDevI->specular_table->table;
LIGHTING.diffuse0.r = LIGHTING.ambientSceneScaled.r * mat->Ambient.r; LIGHTING.diffuse0.g = LIGHTING.ambientSceneScaled.g * mat->Ambient.g; LIGHTING.diffuse0.b = LIGHTING.ambientSceneScaled.b * mat->Ambient.b; LIGHTING.diffuse0.r += mat->Emissive.r * D3DVAL(255); LIGHTING.diffuse0.g += mat->Emissive.g * D3DVAL(255); LIGHTING.diffuse0.b += mat->Emissive.b * D3DVAL(255); int r,g,b; r = (int)FTOI(LIGHTING.diffuse0.r); g = (int)FTOI(LIGHTING.diffuse0.g); b = (int)FTOI(LIGHTING.diffuse0.b); if (r < 0) r = 0; else if (r > 255) r = 255; if (g < 0) g = 0; else if (g > 255) g = 255; if (b < 0) b = 0; else if (b > 255) b = 255; LIGHTING.dwDiffuse0 = (r << 16) + (g << 8) + b; }
pv->lighting.model_eye.x = (D3DVALUE)0; pv->lighting.model_eye.y = (D3DVALUE)0; pv->lighting.model_eye.z = (D3DVALUE)0; pv->lighting.directionToCamera.x = 0; pv->lighting.directionToCamera.y = 0; pv->lighting.directionToCamera.z = -1; if (pv->dwDeviceFlags & D3DDEV_MODELSPACELIGHTING) { inverseTransformVector(&pv->lighting.model_eye, &pv->lighting.model_eye, &pv->mWV[0]); lpDevI->lightVertexFuncTable = &lightVertexTableModel; inverseRotateVector(&pv->lighting.directionToCamera, &pv->lighting.directionToCamera, &pv->mWV[0]); } else { lpDevI->lightVertexFuncTable = &lightVertexTable; } while (light) { // Whenever light type is changed the D3DFE_NEED_TRANSFORM_LIGHTS should be set
if (lpDevI->dwFEFlags & D3DFE_NEED_TRANSFORM_LIGHTS) { if (light->type != D3DLIGHT_DIRECTIONAL) { // Point and Spot lights
light->lightVertexFunc = lpDevI->lightVertexFuncTable->pfnPointSpot; light->pfnLightFirst = lpDevI->lightVertexFuncTable->pfnPointSpotFirst; light->pfnLightNext = lpDevI->lightVertexFuncTable->pfnPointSpotNext; if (!(pv->dwDeviceFlags & D3DDEV_MODELSPACELIGHTING)) { // Transform light position to the camera space
VecMatMul(&light->position, (D3DMATRIX*)&pv->view, &light->model_position); } else { inverseTransformVector(&light->model_position, &light->position, &pv->world[0]); } } else { // Directional light
light->lightVertexFunc = lpDevI->lightVertexFuncTable->pfnDirectional; light->pfnLightFirst = lpDevI->lightVertexFuncTable->pfnDirectionalFirst; light->pfnLightNext = lpDevI->lightVertexFuncTable->pfnDirectionalNext; }
if (light->type != D3DLIGHT_POINT) { // Light direction is flipped to be the direction TO the light
if (!(pv->dwDeviceFlags & D3DDEV_MODELSPACELIGHTING)) { // Transform light direction to the camera space
VecMatMul3(&light->direction, (D3DMATRIX*)&pv->view, &light->model_direction); VecNormalizeFast(light->model_direction); } else { inverseRotateVector(&light->model_direction, &light->direction, &pv->world[0]); } VecNeg(light->model_direction, light->model_direction); // For the infinite viewer the half vector is constant
if (!(pv->dwDeviceFlags & D3DDEV_LOCALVIEWER)) { VecAdd(light->model_direction, pv->lighting.directionToCamera, light->halfway); VecNormalizeFast(light->halfway); } } }
if (lpDevI->dwFEFlags & (D3DFE_MATERIAL_DIRTY | D3DFE_LIGHTS_DIRTY)) { light->diffuseMat.r = D3DVAL(255) * mat->Diffuse.r * light->diffuse.r; light->diffuseMat.g = D3DVAL(255) * mat->Diffuse.g * light->diffuse.g; light->diffuseMat.b = D3DVAL(255) * mat->Diffuse.b * light->diffuse.b;
if (!(light->flags & D3DLIGHTI_AMBIENT_IS_ZERO)) { light->ambientMat.r = D3DVAL(255) * mat->Ambient.r * light->ambient.r; light->ambientMat.g = D3DVAL(255) * mat->Ambient.g * light->ambient.g; light->ambientMat.b = D3DVAL(255) * mat->Ambient.b * light->ambient.b; }
if (specular && !(light->flags & D3DLIGHTI_SPECULAR_IS_ZERO)) { light->flags |= D3DLIGHTI_COMPUTE_SPECULAR; light->specularMat.r = D3DVAL(255) * mat->Specular.r * light->specular.r; light->specularMat.g = D3DVAL(255) * mat->Specular.g * light->specular.g; light->specularMat.b = D3DVAL(255) * mat->Specular.b * light->specular.b; } else light->flags &= ~D3DLIGHTI_COMPUTE_SPECULAR; } light = light->next; }
lpDevI->dwFEFlags &= ~(D3DFE_MATERIAL_DIRTY | D3DFE_NEED_TRANSFORM_LIGHTS | D3DFE_LIGHTS_DIRTY); } // end of updateLights()
|