📄 tnl.c
字号:
/******************************************************************************
<module>
* Name : tnl.c
* Title : D3DM software tnl functions
* Author(s) : Imagination Technologies
* Created : 2 March 2004
*
* Copyright : 2004 by Imagination Technologies Limited.
* All rights reserved. No part of this software, either
* material or conceptual may be copied or distributed,
* transmitted, transcribed, stored in a retrieval system
* or translated into any human or computer language in any
* form by any means, electronic, mechanical, manual or
* other-wise, or disclosed to third parties without the
* express written permission of Imagination Technologies
* Limited, Unit 8, HomePark Industrial Estate,
* King's Langley, Hertfordshire, WD4 8LZ, U.K.
*
* Description : Transformation and lighting code for software tnl
*
* Platform : Windows CE
*
$Log: tnl.c $
--- Revision Logs Removed ---
********************************************************************************/
#include "context.h"
#if (defined(SUPPORT_VGP) && (COREVERSION < 13)) || \
(defined(SUPPORT_VGP_LITE) && (COREVERSION < 120)) || \
(!defined(SUPPORT_VGP) && !defined(SUPPORT_VGP_LITE))
/***********************************************************************************
Function Name : DoClipTestandVPTransform
Inputs : psContext, ppsVertex, ui32Count
Outputs :
Description : Performs front and rear clip plane test on a primitive. transforms
vertex obj co-ords to window co-ords.
************************************************************************************/
IMG_VOID DoClipTestandVPTransform(LPD3DM_CONTEXT psContext,
PVR_NATIVE_VERTEX **ppsVertex,
IMG_UINT32 ui32Count)
{
IMG_UINT32 ui32ClipCode = 0;
IMG_UINT32 i;
NTV_TYPE x, y, z, w, invw;
NTV_TYPE wx, wy, wz;
PVR_VP_TRANSFORM *psVPTransform = &psContext->sHWState.sTACtl3DState.sVPTrans;
PVR_NATIVE_VERTEX *psVertex;
PROFILE_START_FUNC(DO_CLIP_TEST_AND_VP_TRANSFORM);
for (i=0; i<ui32Count; i++)
{
/* set up the vertex */
psVertex = *ppsVertex++;
if(!(psVertex->ui32Flags & D3DM_HASFLAG_RHW))
{
/* transform to post projection */
TransformVector4_PRZW(&psContext->sTState.sSWTNLState.sWorldViewProj, &psVertex->sObj, &psVertex->sClip);
w = psVertex->sClip.w;
invw = w ? DivPR_Y(D3DM_One, w) : D3DM_Zero;
x = psVertex->sClip.x;
y = psVertex->sClip.y;
z = psVertex->sClip.z;
/* Set clip codes */
ui32ClipCode = 0;
if(psContext->sTState.dwRSFlags & TSTATE_RSFLAGS_CLIPPING)
{
/*
** NOTE: it is possible for x to be less than negW and greater than w
** (if w is negative). Otherwise there would be "else" clauses here.
*/
if (z < D3DM_Zero)
{
ui32ClipCode |= D3DM_CLIPFLAG_NEAR; /* FIXME - SetClipStatus */
}
if (z > w)
{
ui32ClipCode |= D3DM_CLIPFLAG_FAR;
}
}
psVertex->ui32Flags |= D3DM_HASFLAG_CLIP | ui32ClipCode;
/*
Compute window coordinates unless clipped
(BFCulling won't work if clip w is outside -1 to 1 range)
*/
/* Rotate if this is a presentable rendertarget */
if(psContext->dwRotationAngle == 0 ||
psContext->dwRotationAngle == 180 ||
psContext->psCurrentRenderTarget->eSurfaceType == D3DMRTYPE_SURFACE ||
psContext->psCurrentRenderTarget->eSurfaceType == D3DMRTYPE_TEXTURE)
{
wx = Add(Mul(Mul(x, psVPTransform->XScale), PR_UNSHIFT(invw)), psVPTransform->XOffset);
wy = Add(Mul(Mul(y, psVPTransform->YScale), PR_UNSHIFT(invw)), psVPTransform->YOffset);
}
else
{
wx = Add(Mul(Mul(y, psVPTransform->XScale), PR_UNSHIFT(invw)), psVPTransform->XOffset);
wy = Add(Mul(Mul(x, psVPTransform->YScale), PR_UNSHIFT(invw)), psVPTransform->YOffset);
}
wz = Add(MulPR_XY(MulPR_X(z, psVPTransform->ZScale), invw), PR_SHIFT(psVPTransform->ZOffset));
psVertex->sWindow.x = wx;
psVertex->sWindow.y = wy;
psVertex->sWindow.z = wz;
psVertex->sWindow.w = invw;
}
else
{
if(psContext->dwRotationAngle == 0 ||
psContext->psCurrentRenderTarget->eSurfaceType == D3DMRTYPE_SURFACE ||
psContext->psCurrentRenderTarget->eSurfaceType == D3DMRTYPE_TEXTURE)
{
/* Copy co-ordinates straight to window vector */
psVertex->sWindow.x = psVertex->sObj.x;
psVertex->sWindow.y = psVertex->sObj.y;
psVertex->sWindow.z = PR_SHIFT(psVertex->sObj.z);
psVertex->sWindow.w = PR_SHIFT(psVertex->sObj.w);
}
else
{
GetRotatedVertex(psContext,
psVertex->sObj.x,
psVertex->sObj.y,
&psVertex->sWindow.x,
&psVertex->sWindow.y,
psContext->psCurrentRenderTarget->dwWidth,
psContext->psCurrentRenderTarget->dwHeight,
psContext->dwRotationAngle);
psVertex->sWindow.z = PR_SHIFT(psVertex->sObj.z);
psVertex->sWindow.w = PR_SHIFT(psVertex->sObj.w);
}
/* Pretransformed, so no clipping required */
psVertex->ui32Flags |= D3DM_HASFLAG_CLIP | ui32ClipCode;
}
}
PROFILE_STOP_FUNC(DO_CLIP_TEST_AND_VP_TRANSFORM);
}
/***********************************************************************************
Function Name : CalcRGBColor
Inputs : psContext, ui32Face, psVertex
Outputs : psVertex
Returns : -
Description : Generates the vertex color through lighting. An implementation
concerned with performing an exponent for the spot/sSpecular
calculations on a per vertex basis, could use table lookup
(calculated at validation time and cached) for performance.
************************************************************************************/
IMG_VOID CalcRGBColor(LPD3DM_CONTEXT psContext, PVR_NATIVE_VERTEX *psVertex)
{
PROFILE_START_FUNC(CALC_RGB_COLOUR);
/* If vertex is pre-transformed then we dont need to calculate lighting */
if(psVertex->ui32Flags & D3DM_HASFLAG_RHW)
{
if(psVertex->ui32Flags & D3DM_HASFLAG_DIFFUSE_COLOR)
{
/* copy diffuse color (HWFormat) */
psVertex->sDiffuseOut = psVertex->sDiffuseIn;
}
else
{
/* default to all F's (From d3dm spec) */
psVertex->sDiffuseOut.r = D3DM_One;
psVertex->sDiffuseOut.g = D3DM_One;
psVertex->sDiffuseOut.b = D3DM_One;
psVertex->sDiffuseOut.a = D3DM_One;
psVertex->sDiffuseOut.ui32Colour = 0xFFFFFFFF;
}
/* Pre-transformed, so default to 0 (From d3dm spec) */
psVertex->sSpecularOut.r = D3DM_Zero;
psVertex->sSpecularOut.g = D3DM_Zero;
psVertex->sSpecularOut.b = D3DM_Zero;
if(psVertex->ui32Flags & D3DM_HASFLAG_FOG)
{
psVertex->sSpecularOut.a = NTV_MAX(D3DM_Zero, NTV_MIN(psVertex->Fog, D3DM_One));
}
else
{
psVertex->sSpecularOut.a = D3DM_Zero;
}
return;
}
if(psContext->sTState.dwRSFlags & TSTATE_RSFLAGS_LIGHTING)
{
NTV_TYPE NLd[PVR_SWTNL_MAX_LIGHTS];
NTV_TYPE NAtten[PVR_SWTNL_MAX_LIGHTS];
PVR_MATERIAL *psMaterial = &psContext->sTState.sSWTNLState.sMaterial;
PVR_COLORVALUE *psVa, *psVd, *psVs, sSum, sTmpCol1;
PVR_VECTOR3 sTmpVec;
PLIGHTDATA psLight;
NTV_TYPE AlphaChnl;
IMG_UINT32 i, ui32LightCount;
PSWTNLSTATE psSWTNLState;
PLIGHTDATA *ppsEnabledLight;
psSWTNLState = &psContext->sTState.sSWTNLState;
ppsEnabledLight = psSWTNLState->ppsEnabledLights;
ui32LightCount = psSWTNLState->dwLightCount;
/********************************************
DIFFUSE LIGHTING CALCULATION
********************************************/
/*
Drgb = Va * La + sum[Vd * (N.Ld) * Atteni*Lci + Va * Lcai]
*/
/*
define ambient color at vertex, Va
select material ambient by default
*/
psVa = &psMaterial->Ambient;
/*
define diffuse alpha as material diffuse alpha by default
*/
AlphaChnl = psMaterial->Diffuse.a;
/*
define diffuse color at vertex, Vd
select material diffuse by default
*/
psVd = &psMaterial->Diffuse;
/* override defaults? */
if (psContext->sTState.dwRSFlags & TSTATE_RSFLAGS_COLORVERTEX)
{
/* override Va? */
if ((psContext->sTState.sSWTNLState.psD3DColourSourceSel[TNLCOLSRCTYPE_AMBIENT] == D3DMMCS_COLOR1)
&& (psVertex->ui32Flags & D3DM_HASFLAG_DIFFUSE_COLOR))
{
psVa = &psVertex->sDiffuseIn;
}
else if ((psContext->sTState.sSWTNLState.psD3DColourSourceSel[TNLCOLSRCTYPE_AMBIENT] == D3DMMCS_COLOR2)
&& (psVertex->ui32Flags & D3DM_HASFLAG_SPECULAR_COLOR))
{
psVa = &psVertex->sSpecularIn;
}
/* override Vd, AlphaChnl? */
if ((psContext->sTState.sSWTNLState.psD3DColourSourceSel[TNLCOLSRCTYPE_DIFFUSE] == D3DMMCS_COLOR1)
&& (psVertex->ui32Flags & D3DM_HASFLAG_DIFFUSE_COLOR))
{
psVd = &psVertex->sDiffuseIn;
AlphaChnl = psVertex->sDiffuseIn.a;
}
else if ((psContext->sTState.sSWTNLState.psD3DColourSourceSel[TNLCOLSRCTYPE_DIFFUSE] == D3DMMCS_COLOR2)
&& (psVertex->ui32Flags & D3DM_HASFLAG_SPECULAR_COLOR))
{
psVd = &psVertex->sSpecularIn;
AlphaChnl = psVertex->sSpecularIn.a;
}
}
/*
first (global) term of the diffuse lighting calculation.
Drgb = Va * La
*/
ColorMultiply(psVa, &psContext->sTState.sSWTNLState.sAmbientColour, &sSum);
/* tranverse lights, adding contributions as we go */
for(i=0; i < ui32LightCount; i++)
{
psLight = ppsEnabledLight[i];
if(psLight->dwFlags & LIGHTDATA_FLAGS_ENABLED)
{
PVR_COLORVALUE sTmpCol2;
if(psVertex->ui32Flags & D3DM_HASFLAG_NORMAL)
{
/* Work out attenuation value */
if(psLight->sLightInfo.Type == D3DMLIGHT_DIRECTIONAL)
{
NAtten[i] = D3DM_One;
}
else /* D3DMLIGHT_POINT */
{
NTV_TYPE NDist;
/* Calculate Ldi */
DistanceVector((PVR_VECTOR3*)&psLight->sLightInfo.EyePosition, (PVR_VECTOR3*)&psVertex->sEye, &sTmpVec);
/* Get Magnitude of distance vector before normalization */
NDist = Magnitude(&sTmpVec);
Normalized((PVR_VECTOR3*)&sTmpVec, (PVR_VECTOR3*)&psLight->sLightInfo.EyeDirection);
if(NDist > psLight->sLightInfo.Range)
{
NAtten[i] = D3DM_Zero;
}
else
{
/* Attenuation = 1 / (Latt0i + LAtt1i * Ldi + LAtt2i * Ldi^2) */
NTV_TYPE NTemp1, NTemp2/*, NMag*/;
/* LAtt1i * Ldi */
NTemp1 = Mul(psLight->sLightInfo.Attenuation1, NDist);
/* LAtt2i * Ldi^2 */
NTemp2 = Mul(psLight->sLightInfo.Attenuation2, LPow(NDist, D3DM_Two));
/* (LAtt1i * Ldi) + (LAtt2i * Ldi^2) */
NTemp1 = Add(NTemp1, NTemp2);
/* Latt0i + (LAtt1i * Ldi) + (LAtt2i * Ldi^2) */
NTemp2 = Add(psLight->sLightInfo.Attenuation0, NTemp1);
/* 1 / (Latt0i + LAtt1i * Ldi + LAtt2i * Ldi^2) */
if(NTemp2 != D3DM_Zero)
{
NAtten[i]= Div(D3DM_One, NTemp2);
}
else
{
NAtten[i] = D3DM_One;
}
}
}
/* (N.Ldi) */
NLd[i] = DotProduct((PVR_VECTOR3*)&psVertex->sNormal,
(PVR_VECTOR3*)&psLight->sLightInfo.EyeDirection);
/* Atteni * Lci */
ScalarColorMultiply(&psLight->sLightInfo.Diffuse, NAtten[i], &sTmpCol2);
/* (N.Ldi) * (Atteni * Lci) */
ScalarColorMultiply(&sTmpCol2, NLd[i], &sTmpCol1);
/* Vd * ((N.Ldi) * (Atteni * Lci)) */
ColorMultiply(psVd, &sTmpCol1, &sTmpCol1);
/* Va * Lcai */
ColorMultiply(psVa, &psLight->sLightInfo.Ambient, &sTmpCol2);
/* (Vd * ((N.Ldi) * (Atteni * Lci))) + (Va * Lcai) */
ColorAdd(&sTmpCol1, &sTmpCol2, &sTmpCol2);
/* Drgb = Va * La + Sum[(Vd * ((N.Ldi) * (Atteni * Lci))) + (Va * Lcai)]*/
ColorAddClamp(&sTmpCol2, &sSum, &sSum);
}
else
{
/*
if no normals, dot products go to zero.
0 + (Va * Lcai)
*/
ColorMultiply(psVa, &psLight->sLightInfo.Ambient, &sTmpCol1);
/* Drgb = Va * La + Sum[Va * Lcai] */
ColorAddClamp(&sTmpCol1, &sSum, &sSum);
}
}
}
/* copy diffuse result to vertex diffuse Output color */
psVertex->sDiffuseOut.a = NTV_MAX(D3DM_Zero, NTV_MIN(AlphaChnl, D3DM_One));
psVertex->sDiffuseOut.r = sSum.r;
psVertex->sDiffuseOut.g = sSum.g;
psVertex->sDiffuseOut.b = sSum.b;
/********************************************
SPECULAR LIGHTING CALCULATION
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -