mirror of
https://github.com/GTAmodding/re3.git
synced 2024-12-29 11:55:41 +00:00
794 lines
25 KiB
C
794 lines
25 KiB
C
|
|
||
|
/* If this file is used outside of the core RW SDK,
|
||
|
* the following things need to be defined
|
||
|
*/
|
||
|
#if (!defined(RWASSERT))
|
||
|
#define RWASSERT(_assertval) /* No op */
|
||
|
#endif
|
||
|
#if (!defined(RWFUNCTION))
|
||
|
#define RWFUNCTION(_rwfunctionstring) /* No op */
|
||
|
#endif
|
||
|
#if (!defined(RWRETURN))
|
||
|
#define RWRETURN(_rwreturnval) return(_rwreturnval)
|
||
|
#endif
|
||
|
#if (!defined(RWRETURNVOID))
|
||
|
#define RWRETURNVOID() return
|
||
|
#endif
|
||
|
|
||
|
/* These are used by specular lighting,
|
||
|
* sorry I have to leave them in here... IDBS
|
||
|
* I'll make it neater when I have time.
|
||
|
*/
|
||
|
#if (!defined(FALLOFFAMBIENT))
|
||
|
#define FALLOFFAMBIENT() /* No op */
|
||
|
#endif
|
||
|
#if (!defined(FALLOFFDIRECTIONAL))
|
||
|
#define FALLOFFDIRECTIONAL() /* No op */
|
||
|
#endif
|
||
|
#if (!defined(FALLOFFPOINT))
|
||
|
#define FALLOFFPOINT() /* No op */
|
||
|
#endif
|
||
|
#if (!defined(FALLOFFSPOT))
|
||
|
#define FALLOFFSPOT() /* No op */
|
||
|
#endif
|
||
|
#if (!defined(FALLOFFSOFTSPOT))
|
||
|
#define FALLOFFSOFTSPOT() /* No op */
|
||
|
#endif
|
||
|
|
||
|
/***************************************************************************
|
||
|
_rwApplyAmbientLight
|
||
|
|
||
|
On entry : Instanced data
|
||
|
: Light
|
||
|
: Optional inverse object matrix
|
||
|
: (to transform light to object space)
|
||
|
: Inverse scale of object
|
||
|
: Surface properties of the light
|
||
|
On exit :
|
||
|
*/
|
||
|
|
||
|
static void
|
||
|
_rwApplyAmbientLight(VERTSARG,
|
||
|
const void *voidLight,
|
||
|
const RwMatrix * __RWUNUSED__ inverseMat,
|
||
|
RwReal __RWUNUSED__ invScale,
|
||
|
const RwSurfaceProperties * surfaceProps)
|
||
|
{
|
||
|
CAMVERTDECL;
|
||
|
NUMVERTDECL;
|
||
|
const RpLight *light = (const RpLight *) voidLight;
|
||
|
RwReal scale;
|
||
|
RwV3d vertToLight;
|
||
|
|
||
|
RWFUNCTION(RWSTRING("_rwApplyAmbientLight"));
|
||
|
RWASSERT(light);
|
||
|
RWASSERT(surfaceProps);
|
||
|
|
||
|
CAMVERTINIT();
|
||
|
NUMVERTINIT();
|
||
|
|
||
|
/* No directional component:
|
||
|
* (this is used in CAMVERTADDRGBA in a specular lighting node) */
|
||
|
vertToLight.x = 0;
|
||
|
vertToLight.y = 0;
|
||
|
vertToLight.z = 0;
|
||
|
|
||
|
/* rpLIGHTAMBIENT - Constant illumination on all vertices
|
||
|
*/
|
||
|
if (rwObjectTestPrivateFlags(light, rpLIGHTPRIVATENOCHROMA))
|
||
|
{
|
||
|
scale = 255.0f * light->color.red * surfaceProps->ambient;
|
||
|
|
||
|
/* Ambient light affects all vertices the same */
|
||
|
while (numVert--)
|
||
|
{
|
||
|
RwReal lum = scale;
|
||
|
|
||
|
#undef FALLOFFCALC
|
||
|
#define FALLOFFCALC FALLOFFAMBIENT
|
||
|
CAMVERTADDRGBA(1, 1, 1, 0);
|
||
|
CAMVERTINC();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
/* perform for coloured lights */
|
||
|
{
|
||
|
scale = 255.0f * surfaceProps->ambient;
|
||
|
|
||
|
/* Ambient light affects all vertices the same */
|
||
|
while (numVert--)
|
||
|
{
|
||
|
RwReal lum = scale;
|
||
|
|
||
|
#undef FALLOFFCALC
|
||
|
#define FALLOFFCALC FALLOFFAMBIENT
|
||
|
CAMVERTADDRGBA(light->color.red, light->color.green,
|
||
|
light->color.blue, 0);
|
||
|
CAMVERTINC();
|
||
|
}
|
||
|
}
|
||
|
RWRETURNVOID();
|
||
|
}
|
||
|
|
||
|
/***************************************************************************
|
||
|
_rwApplyDirectionalLight
|
||
|
|
||
|
On entry : Instanced data
|
||
|
: Light
|
||
|
: Optional inverse object matrix
|
||
|
: (to transform light to object space)
|
||
|
: Inverse scale of object
|
||
|
: Surface properties of the light
|
||
|
On exit :
|
||
|
*/
|
||
|
|
||
|
static void
|
||
|
_rwApplyDirectionalLight(VERTSARG,
|
||
|
const void *voidLight,
|
||
|
const RwMatrix * inverseMat,
|
||
|
RwReal __RWUNUSED__ invScale,
|
||
|
const RwSurfaceProperties * surfaceProps)
|
||
|
{
|
||
|
OBJCAMVERTDECL;
|
||
|
NUMVERTDECL;
|
||
|
const RpLight *light = (const RpLight *) voidLight;
|
||
|
RwV3d vertToLight;
|
||
|
RwReal scale;
|
||
|
RwReal dot;
|
||
|
RwFrame *lightFrame;
|
||
|
|
||
|
RWFUNCTION(RWSTRING("_rwApplyDirectionalLight"));
|
||
|
RWASSERT(light);
|
||
|
RWASSERT(surfaceProps);
|
||
|
|
||
|
OBJCAMVERTINIT();
|
||
|
NUMVERTINIT();
|
||
|
|
||
|
/* rpLIGHTDIRECTIONAL - Lighting scaled by dot product
|
||
|
* of vertex normal and light lookAt vector.
|
||
|
*/
|
||
|
/* This may not have a frame - we need to check */
|
||
|
lightFrame = RpLightGetFrame(light);
|
||
|
if (lightFrame)
|
||
|
{
|
||
|
vertToLight = RwFrameGetLTM(lightFrame)->at;
|
||
|
|
||
|
/* Transform the light into object space if necessary */
|
||
|
if (inverseMat)
|
||
|
{
|
||
|
RwV3dTransformVectors(&vertToLight, &vertToLight, 1, inverseMat);
|
||
|
_rwV3dNormalize(&vertToLight, &vertToLight);
|
||
|
}
|
||
|
|
||
|
/* Vert TO light */
|
||
|
RwV3dScale(&vertToLight, &vertToLight, -1);
|
||
|
|
||
|
/* Optimise for grey lights? */
|
||
|
if (rwObjectTestPrivateFlags(light, rpLIGHTPRIVATENOCHROMA))
|
||
|
{
|
||
|
/* Use one of the light colour intensities as general intensity */
|
||
|
/* light vector tests are to be identical to others */
|
||
|
scale = 255.0f * light->color.red * surfaceProps->diffuse;
|
||
|
|
||
|
/* Loop through each of the vertices */
|
||
|
while (numVert--)
|
||
|
{
|
||
|
RwV3d objNormal;
|
||
|
|
||
|
OBJVERTGETNORMAL(&objNormal);
|
||
|
/* Calculate angle between vertex normal and light vector */
|
||
|
dot = RwV3dDotProduct(&vertToLight, &objNormal);
|
||
|
|
||
|
/* Ensure vector is facing light,
|
||
|
* don't light areas not facing */
|
||
|
|
||
|
if (dot > 0.0f)
|
||
|
{
|
||
|
RwReal lum = dot * scale;
|
||
|
|
||
|
#undef FALLOFFCALC
|
||
|
#define FALLOFFCALC FALLOFFDIRECTIONAL
|
||
|
CAMVERTADDRGBA(1, 1, 1, 0);
|
||
|
}
|
||
|
|
||
|
/* Next vertex */
|
||
|
OBJCAMVERTINC();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
/* perform for coloured lights */
|
||
|
{
|
||
|
scale = 255.0f * surfaceProps->diffuse;
|
||
|
|
||
|
/* Loop through each of the vertices */
|
||
|
while (numVert--)
|
||
|
{
|
||
|
RwV3d objNormal;
|
||
|
|
||
|
OBJVERTGETNORMAL(&objNormal);
|
||
|
/* Calculate angle between vertex normal and light vector */
|
||
|
dot = RwV3dDotProduct(&vertToLight, &objNormal);
|
||
|
|
||
|
/* Ensure vector is facing light,
|
||
|
* don't light areas not facing */
|
||
|
|
||
|
if (dot > 0.0f)
|
||
|
{
|
||
|
RwReal lum = dot * scale;
|
||
|
|
||
|
#define FALLOFFCALC FALLOFFDIRECTIONAL
|
||
|
CAMVERTADDRGBA(light->color.red, light->color.green,
|
||
|
light->color.blue, 0);
|
||
|
}
|
||
|
|
||
|
/* Next vertex */
|
||
|
OBJCAMVERTINC();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
RWRETURNVOID();
|
||
|
}
|
||
|
|
||
|
/***************************************************************************
|
||
|
_rwApplyPointLight
|
||
|
|
||
|
On entry : Instanced data
|
||
|
: Light
|
||
|
: Optional inverse object matrix
|
||
|
: (to transform light to object space)
|
||
|
: Inverse scale of object
|
||
|
: Surface properties of the light
|
||
|
On exit :
|
||
|
*/
|
||
|
|
||
|
static void
|
||
|
_rwApplyPointLight(VERTSARG, const void *voidLight,
|
||
|
const RwMatrix * inverseMat,
|
||
|
RwReal invScale, const RwSurfaceProperties * surfaceProps)
|
||
|
{
|
||
|
OBJCAMVERTDECL;
|
||
|
NUMVERTDECL;
|
||
|
const RpLight *light = (const RpLight *) voidLight;
|
||
|
RwReal scale, recipRad;
|
||
|
RwV3d lightPos, vertToLight;
|
||
|
RwReal radSquared;
|
||
|
|
||
|
RWFUNCTION(RWSTRING("_rwApplyPointLight"));
|
||
|
RWASSERT(light);
|
||
|
RWASSERT(surfaceProps);
|
||
|
|
||
|
OBJCAMVERTINIT();
|
||
|
NUMVERTINIT();
|
||
|
|
||
|
/* rpLIGHTPOINT - Linear falloff with distance, scaled by
|
||
|
* dot product of vertex normal and light to vertex vector.
|
||
|
*/
|
||
|
lightPos = RwFrameGetLTM(RpLightGetFrame(light))->pos;
|
||
|
|
||
|
if (inverseMat)
|
||
|
{
|
||
|
RwReal scaledRad;
|
||
|
|
||
|
scaledRad = ((light->radius) * (invScale));
|
||
|
radSquared = ((scaledRad) * (scaledRad));
|
||
|
recipRad = (((RwReal) (1)) / (scaledRad));
|
||
|
|
||
|
/* Transform light into object space */
|
||
|
RwV3dTransformPoints(&lightPos, &lightPos, 1, inverseMat);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
radSquared = ((light->radius) * (light->radius));
|
||
|
recipRad = (((RwReal) (1)) / (light->radius));
|
||
|
}
|
||
|
|
||
|
if (rwObjectTestPrivateFlags(light, rpLIGHTPRIVATENOCHROMA))
|
||
|
{
|
||
|
/* The scale encapsulates the common elements to do
|
||
|
* with light intensity and surface lighting properties
|
||
|
*/
|
||
|
scale =
|
||
|
((((RwReal) (255)) * (light->color.red))) *
|
||
|
(surfaceProps->diffuse);
|
||
|
|
||
|
while (numVert--)
|
||
|
{
|
||
|
RwV3d objVertex, objNormal;
|
||
|
RwReal dot, dist2;
|
||
|
|
||
|
OBJVERTGETPOS(&objVertex);
|
||
|
OBJVERTGETNORMAL(&objNormal);
|
||
|
|
||
|
/* Discover the vector between vertex and light and it's length */
|
||
|
RwV3dSub(&vertToLight, &lightPos, &objVertex);
|
||
|
|
||
|
/* Ensure that this vertex is facing the light source */
|
||
|
dot = RwV3dDotProduct(&vertToLight, &objNormal);
|
||
|
if (dot > 0.0f)
|
||
|
{
|
||
|
/* Ensure vertex lies within the light's radius */
|
||
|
dist2 = RwV3dDotProduct(&vertToLight, &vertToLight);
|
||
|
if (dist2 < radSquared)
|
||
|
{
|
||
|
RwReal lum;
|
||
|
RwReal recipDist;
|
||
|
RwReal dist;
|
||
|
|
||
|
rwSqrt(&dist, dist2);
|
||
|
recipDist =
|
||
|
(dist > 0.0f) ? (((RwReal) 1) / dist) : 0.0f;
|
||
|
|
||
|
/*
|
||
|
* The following simplifies down to:
|
||
|
*
|
||
|
* -scale *
|
||
|
* (dot/dist) *
|
||
|
* (1 - dist/lightRadius)
|
||
|
*
|
||
|
* Where
|
||
|
* scale
|
||
|
* takes care of the light intensity and
|
||
|
* diffuse lighting coefficient
|
||
|
* (dot/dist)
|
||
|
* is a normalised dot product of
|
||
|
* light->vertex vector and vertex normal
|
||
|
* (1 - dist/lightRadius)
|
||
|
* is a linear falloff factor
|
||
|
*/
|
||
|
lum = scale * dot * (recipDist - recipRad);
|
||
|
|
||
|
/* Calculate the luminance at vertex */
|
||
|
#undef FALLOFFCALC
|
||
|
#define FALLOFFCALC FALLOFFPOINT
|
||
|
CAMVERTADDRGBA(1, 1, 1, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
OBJCAMVERTINC();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
scale = (((RwReal) (255)) * (surfaceProps->diffuse));
|
||
|
|
||
|
while (numVert--)
|
||
|
{
|
||
|
RwV3d objVertex, objNormal;
|
||
|
RwReal dot, dist2;
|
||
|
|
||
|
OBJVERTGETPOS(&objVertex);
|
||
|
OBJVERTGETNORMAL(&objNormal);
|
||
|
|
||
|
/* Discover the vector between vertex and light and it's length */
|
||
|
RwV3dSub(&vertToLight, &lightPos, &objVertex);
|
||
|
|
||
|
/* Ensure that this vertex is facing the light source */
|
||
|
dot = RwV3dDotProduct(&vertToLight, &objNormal);
|
||
|
if (dot > 0.0f)
|
||
|
{
|
||
|
dist2 = RwV3dDotProduct(&vertToLight, &vertToLight);
|
||
|
|
||
|
/* Ensure vertex lies within the light's radius */
|
||
|
if (dist2 < radSquared)
|
||
|
{
|
||
|
RwReal lum;
|
||
|
RwReal recipDist;
|
||
|
RwReal dist;
|
||
|
|
||
|
/* Only now calculate the actual length of vector */
|
||
|
rwSqrt(&dist, dist2);
|
||
|
recipDist =
|
||
|
(dist > 0.0f) ? (((RwReal) 1) / dist) : 0.0f;
|
||
|
|
||
|
lum = scale * dot * (recipDist - recipRad);
|
||
|
/* Alter the luminance according to light colour */
|
||
|
#define FALLOFFCALC FALLOFFPOINT
|
||
|
CAMVERTADDRGBA(light->color.red, light->color.green,
|
||
|
light->color.blue, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Next point */
|
||
|
OBJCAMVERTINC();
|
||
|
}
|
||
|
}
|
||
|
RWRETURNVOID();
|
||
|
}
|
||
|
|
||
|
/***************************************************************************
|
||
|
_rwApplySpotLight
|
||
|
|
||
|
On entry : Instanced data
|
||
|
: Light
|
||
|
: Optional inverse object matrix
|
||
|
: (to transform light to object space)
|
||
|
: Inverse scale of object
|
||
|
: Surface properties of the light
|
||
|
On exit :
|
||
|
*/
|
||
|
|
||
|
static void
|
||
|
_rwApplySpotLight(VERTSARG,
|
||
|
const void *voidLight,
|
||
|
const RwMatrix * inverseMat,
|
||
|
RwReal invScale, const RwSurfaceProperties * surfaceProps)
|
||
|
{
|
||
|
OBJCAMVERTDECL;
|
||
|
NUMVERTDECL;
|
||
|
const RpLight *light = (const RpLight *) voidLight;
|
||
|
RwReal recipRad;
|
||
|
RwReal radSquared;
|
||
|
RwV3d lightPos, at;
|
||
|
|
||
|
RWFUNCTION(RWSTRING("_rwApplySpotLight"));
|
||
|
RWASSERT(light);
|
||
|
RWASSERT(surfaceProps);
|
||
|
|
||
|
OBJCAMVERTINIT();
|
||
|
NUMVERTINIT();
|
||
|
|
||
|
/* rpLIGHTSPOT - Linear falloff with distance, cone to restrict
|
||
|
* angle that light has effect, constant intensity across cone,
|
||
|
* scaled by dot product of vertex normal and light to vertex vector.
|
||
|
*/
|
||
|
|
||
|
lightPos = RwFrameGetLTM(RpLightGetFrame(light))->pos;
|
||
|
at = RwFrameGetLTM(RpLightGetFrame(light))->at;
|
||
|
|
||
|
if (inverseMat)
|
||
|
{
|
||
|
RwReal scaledRad;
|
||
|
|
||
|
scaledRad = ((light->radius) * (invScale));
|
||
|
recipRad = (((RwReal) (1)) / (scaledRad));
|
||
|
radSquared = ((scaledRad) * (scaledRad));
|
||
|
|
||
|
/* Transform light into object space */
|
||
|
/* The at is required to ensure within cone */
|
||
|
RwV3dTransformPoints(&lightPos, &lightPos, 1, inverseMat);
|
||
|
RwV3dTransformVectors(&at, &at, 1, inverseMat);
|
||
|
_rwV3dNormalize(&at, &at);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
recipRad = (((RwReal) (1)) / (light->radius));
|
||
|
radSquared = ((light->radius) * (light->radius));
|
||
|
}
|
||
|
|
||
|
if (rwObjectTestPrivateFlags(light, rpLIGHTPRIVATENOCHROMA))
|
||
|
{
|
||
|
RwReal scale =
|
||
|
|
||
|
((RwReal) 255) * (light->color.red) * (surfaceProps->diffuse);
|
||
|
|
||
|
while (numVert--)
|
||
|
{
|
||
|
RwV3d vertToLight, objVertex, objNormal;
|
||
|
RwReal dot;
|
||
|
|
||
|
OBJVERTGETPOS(&objVertex);
|
||
|
OBJVERTGETNORMAL(&objNormal);
|
||
|
|
||
|
/* Find the squared distance from light point to vertex */
|
||
|
RwV3dSub(&vertToLight, &lightPos, &objVertex);
|
||
|
|
||
|
/* Ensure that this vertex is facing the light source */
|
||
|
dot = RwV3dDotProduct(&vertToLight, &objNormal);
|
||
|
if (dot > 0.0f)
|
||
|
{
|
||
|
RwReal dist2;
|
||
|
|
||
|
/* Ensure vertex lies within the light's radius */
|
||
|
dist2 = RwV3dDotProduct(&vertToLight, &vertToLight);
|
||
|
if (dist2 < radSquared)
|
||
|
{
|
||
|
RwReal dist;
|
||
|
RwReal compare;
|
||
|
RwReal proj;
|
||
|
|
||
|
rwSqrt(&dist, dist2);
|
||
|
compare = dist * light->minusCosAngle;
|
||
|
proj = RwV3dDotProduct(&vertToLight, &at);
|
||
|
|
||
|
if (proj < compare)
|
||
|
{
|
||
|
RwReal lum;
|
||
|
RwReal recipDist;
|
||
|
|
||
|
/* Get the real distance from the light
|
||
|
* to the vertex (not squared) */
|
||
|
recipDist =
|
||
|
(dist > 0.0f) ? (((RwReal) 1) / dist) : 0.0f;
|
||
|
|
||
|
/* This model is the same as the point source
|
||
|
* inside the cone, zero outside the cone */
|
||
|
lum = scale * dot * (recipDist - recipRad);
|
||
|
#undef FALLOFFCALC
|
||
|
#define FALLOFFCALC FALLOFFSPOT
|
||
|
CAMVERTADDRGBA(1, 1, 1, 0);
|
||
|
}
|
||
|
}
|
||
|
/* Next vertex */
|
||
|
OBJCAMVERTINC();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
RwReal scale =
|
||
|
|
||
|
(((RwReal) (255)) * (surfaceProps->diffuse));
|
||
|
|
||
|
while (numVert--)
|
||
|
{
|
||
|
RwV3d vertToLight, objVertex, objNormal;
|
||
|
RwReal dot;
|
||
|
|
||
|
OBJVERTGETPOS(&objVertex);
|
||
|
OBJVERTGETNORMAL(&objNormal);
|
||
|
|
||
|
/* Find the squared distance from light point to vertex */
|
||
|
RwV3dSub(&vertToLight, &lightPos, &objVertex);
|
||
|
|
||
|
/* Ensure that this vertex is facing the light source */
|
||
|
dot = RwV3dDotProduct(&vertToLight, &objNormal);
|
||
|
if (dot > 0.0f)
|
||
|
{
|
||
|
RwReal dist2;
|
||
|
|
||
|
/* Ensure vertex lies within the light's radius */
|
||
|
dist2 = RwV3dDotProduct(&vertToLight, &vertToLight);
|
||
|
if (dist2 < radSquared)
|
||
|
{
|
||
|
RwReal dist;
|
||
|
RwReal compare;
|
||
|
RwReal proj;
|
||
|
|
||
|
rwSqrt(&dist, dist2);
|
||
|
compare = dist * light->minusCosAngle;
|
||
|
proj = RwV3dDotProduct(&vertToLight, &at);
|
||
|
|
||
|
if (proj < compare)
|
||
|
{
|
||
|
RwReal lum;
|
||
|
RwReal recipDist;
|
||
|
|
||
|
recipDist =
|
||
|
(dist > 0.0f) ? (((RwReal) 1) / dist) : 0.0f;
|
||
|
|
||
|
/* This model is the same as the point source
|
||
|
* inside the cone, zero outside the cone */
|
||
|
lum = scale * dot * (recipDist - recipRad);
|
||
|
|
||
|
/* Introduce the light colours as a
|
||
|
* scaling factor for luminance */
|
||
|
#define FALLOFFCALC FALLOFFSPOT
|
||
|
CAMVERTADDRGBA(light->color.red,
|
||
|
light->color.green, light->color.blue,
|
||
|
0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Next */
|
||
|
OBJCAMVERTINC();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
RWRETURNVOID();
|
||
|
}
|
||
|
|
||
|
/***************************************************************************
|
||
|
_rwApplySpotSoftLight
|
||
|
|
||
|
On entry : Instanced data
|
||
|
: Light
|
||
|
: Optional inverse object matrix
|
||
|
: (to transform light to object space)
|
||
|
: Inverse scale of object
|
||
|
: Surface properties of the light
|
||
|
On exit :
|
||
|
*/
|
||
|
|
||
|
static void
|
||
|
_rwApplySpotSoftLight(VERTSARG, const void *voidLight,
|
||
|
const RwMatrix * inverseMat, RwReal invScale,
|
||
|
const RwSurfaceProperties * surfaceProps)
|
||
|
{
|
||
|
OBJCAMVERTDECL;
|
||
|
NUMVERTDECL;
|
||
|
const RpLight *light = (const RpLight *) voidLight;
|
||
|
RwReal recipRad;
|
||
|
RwReal radSquared;
|
||
|
RwV3d lightPos, at;
|
||
|
|
||
|
RWFUNCTION(RWSTRING("_rwApplySpotSoftLight"));
|
||
|
RWASSERT(light);
|
||
|
RWASSERT(surfaceProps);
|
||
|
|
||
|
OBJCAMVERTINIT();
|
||
|
NUMVERTINIT();
|
||
|
|
||
|
/* rpLIGHTSPOTSOFT - Linear falloff with distance, cone to restrict
|
||
|
* angle that light has effect, falloff to edge of cone, scaled by
|
||
|
* dot product of vertex normal and light to vertex vector.
|
||
|
*/
|
||
|
|
||
|
lightPos = RwFrameGetLTM(RpLightGetFrame(light))->pos;
|
||
|
at = RwFrameGetLTM(RpLightGetFrame(light))->at;
|
||
|
|
||
|
if (inverseMat)
|
||
|
{
|
||
|
RwReal scaledRad;
|
||
|
|
||
|
scaledRad = ((light->radius) * (invScale));
|
||
|
recipRad = (((RwReal) (1)) / (scaledRad));
|
||
|
radSquared = ((scaledRad) * (scaledRad));
|
||
|
|
||
|
/* Transform light into object space */
|
||
|
/* The at is required to ensure within cone */
|
||
|
RwV3dTransformPoints(&lightPos, &lightPos, 1, inverseMat);
|
||
|
RwV3dTransformVectors(&at, &at, 1, inverseMat);
|
||
|
_rwV3dNormalize(&at, &at);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
recipRad = 1.0f / light->radius;
|
||
|
radSquared = light->radius * light->radius;
|
||
|
}
|
||
|
|
||
|
if (rwObjectTestPrivateFlags(light, rpLIGHTPRIVATENOCHROMA))
|
||
|
{
|
||
|
RwReal scale =
|
||
|
|
||
|
((RwReal) 255) * (light->color.red) * (surfaceProps->diffuse);
|
||
|
|
||
|
while (numVert--)
|
||
|
{
|
||
|
RwV3d vertToLight, objVertex, objNormal;
|
||
|
RwReal dot;
|
||
|
|
||
|
OBJVERTGETPOS(&objVertex);
|
||
|
OBJVERTGETNORMAL(&objNormal);
|
||
|
|
||
|
/* Find the squared distance from light point to vertex */
|
||
|
RwV3dSub(&vertToLight, &lightPos, &objVertex);
|
||
|
|
||
|
/* Ensure that this vertex is facing the light source */
|
||
|
dot = RwV3dDotProduct(&vertToLight, &objNormal);
|
||
|
if (dot > 0.0f)
|
||
|
{
|
||
|
RwReal dist2;
|
||
|
|
||
|
/* Ensure vertex lies within the light's radius */
|
||
|
dist2 = RwV3dDotProduct(&vertToLight, &vertToLight);
|
||
|
if (dist2 < radSquared)
|
||
|
{
|
||
|
RwReal dist;
|
||
|
RwReal compare;
|
||
|
RwReal proj;
|
||
|
|
||
|
rwSqrt(&dist, dist2);
|
||
|
compare = dist * light->minusCosAngle;
|
||
|
proj = RwV3dDotProduct(&vertToLight, &at);
|
||
|
|
||
|
if (proj < compare)
|
||
|
{
|
||
|
RwReal lum;
|
||
|
RwReal recipDist;
|
||
|
RwReal normalise;
|
||
|
|
||
|
recipDist =
|
||
|
(dist > 0.0f) ? (((RwReal) 1) / dist) : 0.0f;
|
||
|
|
||
|
/* This model is the same as the point source
|
||
|
* inside the cone, zero outside the cone */
|
||
|
lum = scale * dot * (recipDist - recipRad);
|
||
|
|
||
|
/* It has an extra term for quadratic falloff
|
||
|
* across the cone though */
|
||
|
normalise = (dist + compare);
|
||
|
RWASSERT(normalise >= 0.0f);
|
||
|
if (normalise > 0.0f)
|
||
|
{
|
||
|
normalise = (dist + proj) / normalise;
|
||
|
|
||
|
normalise *= normalise;
|
||
|
lum *= (((RwReal) 1) - normalise);
|
||
|
}
|
||
|
|
||
|
#undef FALLOFFCALC
|
||
|
#define FALLOFFCALC FALLOFFSOFTSPOT
|
||
|
CAMVERTADDRGBA(1, 1, 1, 0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Next */
|
||
|
OBJCAMVERTINC();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
else
|
||
|
{
|
||
|
RwReal scale = 255.0f * surfaceProps->diffuse;
|
||
|
|
||
|
while (numVert--)
|
||
|
{
|
||
|
RwV3d vertToLight, objVertex, objNormal;
|
||
|
RwReal dot;
|
||
|
|
||
|
OBJVERTGETPOS(&objVertex);
|
||
|
OBJVERTGETNORMAL(&objNormal);
|
||
|
|
||
|
/* Find the squared distance from light point to vertex */
|
||
|
RwV3dSub(&vertToLight, &lightPos, &objVertex);
|
||
|
|
||
|
/* Ensure that this vertex is facing the light source */
|
||
|
dot = RwV3dDotProduct(&vertToLight, &objNormal);
|
||
|
if (dot > 0.0f)
|
||
|
{
|
||
|
RwReal dist2;
|
||
|
|
||
|
/* Ensure vertex lies within the light's radius */
|
||
|
dist2 = RwV3dDotProduct(&vertToLight, &vertToLight);
|
||
|
if (dist2 < radSquared)
|
||
|
{
|
||
|
RwReal dist;
|
||
|
RwReal compare;
|
||
|
RwReal proj;
|
||
|
|
||
|
rwSqrt(&dist, dist2);
|
||
|
compare = dist * light->minusCosAngle;
|
||
|
proj = RwV3dDotProduct(&vertToLight, &at);
|
||
|
|
||
|
if (proj < compare)
|
||
|
{
|
||
|
|
||
|
RwReal lum;
|
||
|
RwReal normalise;
|
||
|
RwReal recipDist;
|
||
|
|
||
|
/* Get the real distance from the light
|
||
|
* to the vertex (not squared) */
|
||
|
recipDist =
|
||
|
(dist > 0.0f) ? (((RwReal) 1) / dist) : 0.0f;
|
||
|
|
||
|
/* This model is the same as the point source
|
||
|
* inside the cone, zero outside the cone */
|
||
|
lum = scale * dot * (recipDist - recipRad);
|
||
|
|
||
|
/* It has an extra term for quadratic falloff
|
||
|
* across the cone though */
|
||
|
/* It has an extra term for quadratic falloff
|
||
|
* across the cone though */
|
||
|
normalise = (dist + compare);
|
||
|
RWASSERT(normalise >= 0.0f);
|
||
|
if (normalise > 0.0f)
|
||
|
{
|
||
|
normalise = (dist + proj) / normalise;
|
||
|
|
||
|
normalise *= normalise;
|
||
|
lum *= (((RwReal) 1) - normalise);
|
||
|
|
||
|
}
|
||
|
/* Introduce the light colours as a
|
||
|
* scaling factor for luminance */
|
||
|
#undef FALLOFFCALC
|
||
|
#define FALLOFFCALC FALLOFFSOFTSPOT
|
||
|
CAMVERTADDRGBA(light->color.red,
|
||
|
light->color.green,
|
||
|
light->color.blue, 0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Next */
|
||
|
OBJCAMVERTINC();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
RWRETURNVOID();
|
||
|
}
|