#include "MLRHeaders.hpp" //############################################################################# //######################### MLRProjectLight ################################ //############################################################################# MLRProjectLight::ClassData* MLRProjectLight::DefaultData = NULL; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MLRProjectLight::InitializeClass() { Verify(!DefaultData); Verify(gos_GetCurrentHeap() == StaticHeap); DefaultData = new ClassData( MLRProjectLightClassID, "MidLevelRenderer::MLRProjectLight", MLRInfiniteLightWithFalloff::DefaultData ); Register_Object(DefaultData); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MLRProjectLight::TerminateClass() { Unregister_Object(DefaultData); delete DefaultData; DefaultData = NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MLRProjectLight::MLRProjectLight() : MLRInfiniteLightWithFalloff(DefaultData) { Verify(gos_GetCurrentHeap() == LightsHeap); lightMap = NULL; inverseLightToShape = Matrix4D::Identity; xMin = -0.005f; xMax = 0.005f; yMin = -0.005f; yMax = 0.005f; nnear = 0.1f; ffar = 1.9f; distance = -1.0f; CreateProjectMatrix(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MLRProjectLight::MLRProjectLight( Stuff::MemoryStream *stream, int version ) : MLRInfiniteLightWithFalloff(DefaultData, stream, version) { Check_Object(stream); Verify(gos_GetCurrentHeap() == LightsHeap); lightMap = NULL; if (version > 7) { MString name; *stream >> name; if (name.GetLength() > 0) { Check_Object(MLRTexturePool::Instance); MLRTexture *texture = (*MLRTexturePool::Instance)(name, 0); if (!texture) texture = MLRTexturePool::Instance->Add(name, 0); Check_Object(texture); lightMap = new MLRLightMap(texture); Register_Object(lightMap); lightMap->AttachReference(); lightMask |= MLRState::LightMapLightingMode; } } Radian angle; *stream >> angle; SetSpreadAngle(angle); inverseLightToShape = Matrix4D::Identity; xMin = -0.05f; xMax = 0.05f; yMin = -0.05f; yMax = 0.05f; nnear = 0.1f; ffar = 1.9f; distance = -1.0f; CreateProjectMatrix(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MLRProjectLight::MLRProjectLight(Stuff::Page *page): MLRInfiniteLightWithFalloff(DefaultData, page) { Check_Object(page); Verify(gos_GetCurrentHeap() == LightsHeap); lightMap = NULL; const char* lightmap; if (page->GetEntry("LightMap", &lightmap)) { Check_Pointer(lightmap); Check_Object(MLRTexturePool::Instance); MLRTexture *texture = (*MLRTexturePool::Instance)(lightmap, 0); if (!texture) texture = MLRTexturePool::Instance->Add(lightmap, 0); Check_Object(texture); lightMap = new MLRLightMap(texture); Register_Object(lightMap); lightMap->AttachReference(); lightMask |= MLRState::LightMapLightingMode; } Degree angle=45.0; page->GetEntry("Spread", &angle.angle); SetSpreadAngle(angle); inverseLightToShape = Matrix4D::Identity; xMin = -0.05f; xMax = 0.05f; yMin = -0.05f; yMax = 0.05f; nnear = 0.1f; ffar = 1.9f; distance = -1.0f; CreateProjectMatrix(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MLRProjectLight::~MLRProjectLight() { if(lightMap!=NULL) { lightMap->DetachReference(); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MLRProjectLight::Save(Stuff::MemoryStream *stream) { Check_Object(this); Check_Object(stream); MLRInfiniteLightWithFalloff::Save(stream); if (lightMap) { Check_Object(lightMap); unsigned handle = lightMap->GetState().GetTextureHandle(); MLRTexture *texture = (*MLRTexturePool::Instance)[handle]; Check_Object(texture); MString name = texture->GetTextureName(); *stream << name; } else *stream << *MString::s_Empty; *stream << spreadAngle; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MLRProjectLight::Write(Stuff::Page *page) { Check_Object(this); Check_Object(page); MLRInfiniteLightWithFalloff::Write(page); if (lightMap) { Check_Object(lightMap); unsigned handle = lightMap->GetState().GetTextureHandle(); MLRTexture *texture = (*MLRTexturePool::Instance)[handle]; Check_Object(texture); page->SetEntry("LightMap", texture->GetTextureName()); } page->SetEntry("Spread", spreadAngle * Degrees_Per_Radian); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MLRProjectLight::TestInstance() { Verify(IsDerivedFrom(DefaultData)); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MLRProjectLight::CreateProjectMatrix() { Matrix4D m4_1, m4_2; m4_1 = Matrix4D::Identity; // m4_1.BuildTranslation(Point3D(0.5f, 0.5f, 0.0f)); // m4_1(0,0) = 0.5f; // m4_1(1,1) = 0.5f; // m4_1(2,2) = 1.0f; m4_2 = Matrix4D::Identity; m4_2.SetPerspective(nnear, ffar, xMax, xMin, yMax, yMin); projMatrix.Multiply(m4_2, m4_1); LinearMatrix4D moveBack; moveBack = LinearMatrix4D::Identity; moveBack.BuildTranslation(Point3D(0.0f, 0.0f, distance)); m4_1.Multiply(moveBack, projMatrix); projMatrix = m4_1; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MLRProjectLight::InitLineTextureProjection( Stuff::Point3D *lineTestPoints, Stuff::RGBAColor *lineTestColors ) { Point3D p[8]; p[0] = Point3D(xMin, yMin, (nnear + distance)); p[1] = Point3D(xMax, yMin, (nnear + distance)); p[2] = Point3D(xMax, yMax, (nnear + distance)); p[3] = Point3D(xMin, yMax, (nnear + distance)); float t = ffar / nnear; p[4] = Point3D(xMin * t, yMin * t, (ffar + distance)); p[5] = Point3D(xMax * t, yMin * t, (ffar + distance)); p[6] = Point3D(xMax * t, yMax * t, (ffar + distance)); p[7] = Point3D(xMin * t, yMax * t, (ffar + distance)); lineTestPoints[0] = p[0]; lineTestPoints[1] = p[1]; lineTestPoints[2] = p[1]; lineTestPoints[3] = p[2]; lineTestPoints[4] = p[2]; lineTestPoints[5] = p[3]; lineTestPoints[6] = p[3]; lineTestPoints[7] = p[0]; lineTestPoints[8] = p[0]; lineTestPoints[9] = p[4]; lineTestPoints[10] = p[1]; lineTestPoints[11] = p[5]; lineTestPoints[12] = p[2]; lineTestPoints[13] = p[6]; lineTestPoints[14] = p[3]; lineTestPoints[15] = p[7]; lineTestPoints[16] = p[4]; lineTestPoints[17] = p[5]; lineTestPoints[18] = p[5]; lineTestPoints[19] = p[6]; lineTestPoints[20] = p[6]; lineTestPoints[21] = p[7]; lineTestPoints[22] = p[7]; lineTestPoints[23] = p[4]; for(int i=0;i<24;i++) { lineTestColors[i] = RGBAColor ( Random::GetFraction(), Random::GetFraction(), Random::GetFraction(), 1.0f ); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MLRProjectLight::SetLightToShapeMatrix(const LinearMatrix4D& worldToShape) { Check_Object(this); lightToShape.Multiply(lightToWorld, worldToShape); inverseLightToShape.Invert(lightToShape); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MLRProjectLight::SetSpreadAngle(const Radian &radian) { Check_Object(this); spreadAngle = radian; tanSpreadAngle = (Scalar)tan(spreadAngle); cosSpreadAngle = (Scalar)cos(spreadAngle); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MLRProjectLight::SetSpreadAngle(const Degree °ree) { Check_Object(this); spreadAngle = degree; tanSpreadAngle = (Scalar)tan(spreadAngle); cosSpreadAngle = (Scalar)cos(spreadAngle); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool MLRProjectLight::GetSpreadAngle(Radian *angle) { Check_Object(this); *angle = spreadAngle; return true; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MLRProjectLight::LightVertex(const MLRVertexData& vertexData) { UnitVector3D light_z; RGBColor light_color(color); Point3D vertex_to_light; Verify(GetFalloffDistance(vertex_to_light.x, vertex_to_light.y)); GetInShapePosition(vertex_to_light); vertex_to_light -= *vertexData.point; // //-------------------------------------------------------------- // If the distance to the vertex is zero, the light will not // contribute to the vertex coloration. Otherwise, decrease the // light level as appropriate to the distance //-------------------------------------------------------------- // Scalar length = vertex_to_light.GetApproximateLength(); Scalar falloff = 1.0f; if(GetFalloff(length, falloff)) { light_color.red *= falloff; light_color.green *= falloff; light_color.blue *= falloff; } else { return; } Scalar cos_spread_angle = GetCosSpreadAngle(); GetInShapeDirection(light_z); length = -1.0f / length; vertex_to_light *= length; Scalar t = vertex_to_light * light_z; if (t <= cos_spread_angle) { return; } /* Verify(!Close_Enough(cos_spread_angle, 1.0f)); spread = 1.0f - ((1.0f - t) / (1.0f - cos_spread_angle)); light_color.red *= cos_spread_angle; light_color.green *= cos_spread_angle; light_color.blue *= cos_spread_angle; */ light_z.x = vertex_to_light.x; light_z.y = vertex_to_light.y; light_z.z = vertex_to_light.z; // //------------------------------------------------------------------- // Now we reduce the light level falling on the vertex based upon the // cosine of the angle between light and normal //------------------------------------------------------------------- // Scalar cosine = 0.7071f; if(vertexData.normal!=NULL) { cosine = -(light_z * (*vertexData.normal)); // * intensity; } if (cosine > SMALL) { light_color.red *= cosine; light_color.green *= cosine; light_color.blue *= cosine; Stuff::RGBAColor *t = const_cast(vertexData.color); Check_Pointer(t); t->red += light_color.red; t->green += light_color.green; t->blue += light_color.blue; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MLRProjectLight::LightCenter(RGBAColor& rcol) { UnitVector3D light_z; RGBColor light_color(color); Point3D vertex_to_light; Verify(GetFalloffDistance(vertex_to_light.x, vertex_to_light.y)); GetInShapePosition(vertex_to_light); // //-------------------------------------------------------------- // If the distance to the vertex is zero, the light will not // contribute to the vertex coloration. Otherwise, decrease the // light level as appropriate to the distance //-------------------------------------------------------------- // Scalar length = vertex_to_light.GetApproximateLength(); Scalar falloff = 1.0f; if(GetFalloff(length, falloff)) { light_color.red *= falloff; light_color.green *= falloff; light_color.blue *= falloff; } else { return; } Scalar cos_spread_angle = GetCosSpreadAngle(); GetInShapeDirection(light_z); length = -1.0f / length; vertex_to_light *= length; Scalar t = vertex_to_light * light_z; if (t <= cos_spread_angle) { return; } /* Verify(!Close_Enough(cos_spread_angle, 1.0f)); spread = 1.0f - ((1.0f - t) / (1.0f - cos_spread_angle)); light_color.red *= cos_spread_angle; light_color.green *= cos_spread_angle; light_color.blue *= cos_spread_angle; */ light_z.x = vertex_to_light.x; light_z.y = vertex_to_light.y; light_z.z = vertex_to_light.z; // //------------------------------------------------------------------- // Now we reduce the light level falling on the vertex based upon the // cosine of the angle between light and normal //------------------------------------------------------------------- // Scalar cosine = 0.7071f; if (cosine > SMALL) { light_color.red *= cosine; light_color.green *= cosine; light_color.blue *= cosine; rcol.red += light_color.red; rcol.green += light_color.green; rcol.blue += light_color.blue; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MLRProjectLight::SetLightMap(MLRLightMap *light_map) { Check_Object(this); if (lightMap) { lightMap->DetachReference(); } lightMap = light_map; if (lightMap == NULL) { lightMask &= ~MLRState::LightMapLightingMode; } else { lightMap->AttachReference(); lightMask |= MLRState::LightMapLightingMode; } }