windows-nt/Source/XPSP1/NT/multimedia/directx/dxg/d3d8/fe/rgblt.cpp

279 lines
10 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*==========================================================================;
*
* 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()