/* 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(); }