#include "ElementRendererHeaders.hpp" #include //#define HUNT_FOR_THE_MISSING_SHADOW "micgaert" #if defined (LAB_ONLY) && defined (HUNT_FOR_THE_MISSING_SHADOW) #include #endif int ElementRenderer::ShapeElement::s_MaxLightsPerShape=MidLevelRenderer::Limits::Max_Number_Of_Lights_Per_Primitive; static bool __stdcall Check2() {return ElementRenderer::ShapeElement::s_MaxLightsPerShape == 2;} static bool __stdcall Check4() {return ElementRenderer::ShapeElement::s_MaxLightsPerShape == 4;} static void __stdcall Enable2() { ElementRenderer::ShapeElement::s_MaxLightsPerShape = (ElementRenderer::ShapeElement::s_MaxLightsPerShape == 2) ? MidLevelRenderer::Limits::Max_Number_Of_Lights_Per_Primitive : 2; } static void __stdcall Enable4() { ElementRenderer::ShapeElement::s_MaxLightsPerShape = (ElementRenderer::ShapeElement::s_MaxLightsPerShape == 4) ? MidLevelRenderer::Limits::Max_Number_Of_Lights_Per_Primitive : 4; } bool ElementRenderer::ShapeElement::s_ShowClippedBounds = false; static bool __stdcall Greyed() {return ElementRenderer::Element::GetCallbackSet() != NULL;} static bool __stdcall Check_ShowShapeBounds() {return ElementRenderer::ShapeElement::s_ShowClippedBounds;} static void __stdcall Activate_ShowShapeBounds() {ElementRenderer::ShapeElement::s_ShowClippedBounds = !ElementRenderer::ShapeElement::s_ShowClippedBounds;} bool ElementRenderer::ShapeElement::s_CheckBounds = false; bool ElementRenderer::ShapeElement::s_BoundsWereBad = false; static bool __stdcall Check_CheckBounds() {return ElementRenderer::ShapeElement::s_CheckBounds;} static void __stdcall Activate_CheckBounds() {ElementRenderer::ShapeElement::s_CheckBounds = !ElementRenderer::ShapeElement::s_CheckBounds;} //############################################################################ //############################ ShapeElement ################################ //############################################################################ HGOSHEAP ElementRenderer::ShapeElement::s_Heap = NULL; ElementRenderer::ShapeElement::ClassData* ElementRenderer::ShapeElement::DefaultData = NULL; ElementRenderer::Element::SyncMethod ElementRenderer::ShapeElement::SyncMethods[SyncStateCount]= { // // Root mode // SYNC_METHOD(ShapeElement, Clean), SYNC_METHOD(ShapeElement, DirtyRoot), SYNC_METHOD(ShapeElement, Clean), SYNC_METHOD(ShapeElement, DirtyRoot), SYNC_METHOD(Element, None), SYNC_METHOD(Element, Defer), SYNC_METHOD(Element, None), SYNC_METHOD(Element, Defer), SYNC_METHOD(ShapeElement, Clean), SYNC_METHOD(ShapeElement, DirtyRoot), SYNC_METHOD(ShapeElement, Clean), SYNC_METHOD(ShapeElement, DirtyRoot), SYNC_METHOD(Element, None), SYNC_METHOD(Element, Defer), SYNC_METHOD(Element, None), SYNC_METHOD(Element, Defer), // // Sphere Cull // SYNC_METHOD(ShapeElement, CleanSphere), SYNC_METHOD(ShapeElement, DirtySphere), SYNC_METHOD(ShapeElement, CleanSphere), SYNC_METHOD(ShapeElement, DirtySphere), SYNC_METHOD(Element, None), SYNC_METHOD(Element, Defer), SYNC_METHOD(Element, None), SYNC_METHOD(Element, Defer), // // OBB Cull // SYNC_METHOD(ShapeElement, CleanOBB), SYNC_METHOD(ShapeElement, DirtyOBB), SYNC_METHOD(ShapeElement, CleanOBB), SYNC_METHOD(ShapeElement, DirtyOBB), SYNC_METHOD(Element, None), SYNC_METHOD(Element, Defer), SYNC_METHOD(Element, None), SYNC_METHOD(Element, Defer), // // Never Cull // SYNC_METHOD(ShapeElement, Clean), SYNC_METHOD(ShapeElement, Dirty), SYNC_METHOD(ShapeElement, Clean), SYNC_METHOD(ShapeElement, Dirty), SYNC_METHOD(Element, None), SYNC_METHOD(Element, Defer), SYNC_METHOD(Element, None), SYNC_METHOD(Element, Defer), SYNC_METHOD(ShapeElement, Clean), SYNC_METHOD(ShapeElement, Dirty), SYNC_METHOD(ShapeElement, Clean), SYNC_METHOD(ShapeElement, Dirty), SYNC_METHOD(Element, None), SYNC_METHOD(Element, Defer), SYNC_METHOD(Element, None), SYNC_METHOD(Element, Defer), // // Always Cull // SYNC_METHOD(Element, None), SYNC_METHOD(Element, None), SYNC_METHOD(Element, None), SYNC_METHOD(Element, None), SYNC_METHOD(Element, None), SYNC_METHOD(Element, None), SYNC_METHOD(Element, None), SYNC_METHOD(Element, None), SYNC_METHOD(Element, None), SYNC_METHOD(Element, None), SYNC_METHOD(Element, None), SYNC_METHOD(Element, None), SYNC_METHOD(Element, None), SYNC_METHOD(Element, None), SYNC_METHOD(Element, None), SYNC_METHOD(Element, None) }; ElementRenderer::Element::DrawMethod ElementRenderer::ShapeElement::DrawMethods[DrawStateCount]= { // // No billboarding // DRAW_METHOD(ShapeElement, Inherit), DRAW_METHOD(ShapeElement, Override) }; DECLARE_TIMER(static, Light_Culling_Time); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ShapeElement::InitializeClass(Stuff::NotationFile *startup_ini) { Verify(!s_Heap); s_Heap = gos_CreateMemoryHeap("Shape", 0, g_LibraryHeap); Check_Pointer(s_Heap); Verify(!DefaultData); DefaultData = new ClassData( ShapeElementClassID, "ElementRenderer::ShapeElement", BaseClass::DefaultData, reinterpret_cast(&Make) ); Check_Object(DefaultData); s_MaxLightsPerShape = MidLevelRenderer::Limits::Max_Number_Of_Lights_Per_Primitive; s_ShowClippedBounds = false; s_CheckBounds = false; s_BoundsWereBad = false; Initialize_Timer(Light_Culling_Time, "Light Culling"); AddDebuggerMenuItem("Libraries\\Graphics Options\\2 Lights/Shape", Check2, Enable2, 0 ); AddDebuggerMenuItem("Libraries\\Graphics Options\\4 Lights/Shape", Check4, Enable4, 0 ); AddDebuggerMenuItem("Libraries\\ElementRenderer\\Show Clipped Shape Bounds", Check_ShowShapeBounds, Activate_ShowShapeBounds, Greyed ); AddDebuggerMenuItem("Libraries\\ElementRenderer\\Check Bounds", Check_CheckBounds, Activate_CheckBounds, NULL ); if (startup_ini) { Check_Object(startup_ini); Stuff::Page *page = startup_ini->FindPage("Graphics Options"); if (page) { Check_Object(page); page->GetEntry("MaxLights", &s_MaxLightsPerShape); Min_Clamp(s_MaxLightsPerShape, 2); } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ShapeElement::TerminateClass(Stuff::NotationFile *startup_ini) { if (startup_ini) { Check_Object(startup_ini); Stuff::Page *page = startup_ini->SetPage("Graphics Options"); Check_Object(page); page->SetEntry("MaxLights", s_MaxLightsPerShape); } Check_Object(DefaultData); delete DefaultData; DefaultData = NULL; Check_Pointer(s_Heap); gos_DestroyMemoryHeap(s_Heap); s_Heap = NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ElementRenderer::ShapeElement::ShapeElement( ClassData *class_data, Stuff::MemoryStream *stream, int version, ShapeHolder shapes ): Element(class_data, stream, version) { Check_Pointer(this); Check_Object(stream); unsigned index = (m_state>>SyncStateBit) & SyncStateMask; Verify(index < SyncStateCount); m_sync = SyncMethods[index]; index = (m_state>>CullStateBit) & CullStateMask; Verify(index < CullStateCount); m_cameraCull = CullMethods[index].m_cameraCull; m_rayCull = CullMethods[index].m_rayCull; m_sphereTest = CullMethods[index].m_sphereTest; index = (m_state>>DrawStateBit) & DrawStateMask; Verify(index < DrawStateCount); m_draw = DrawMethods[index]; // //--------------------------------- // Create the shape from the stream //--------------------------------- // m_worldToLocal = Stuff::LinearMatrix4D::Identity; int mlr_version = MidLevelRenderer::ReadMLRVersion(stream); if (mlr_version == -1) mlr_version = version; if (version<13) { if(mlr_version<14) m_MLRShape = MidLevelRenderer::MLRShape::Make(stream, mlr_version); else { RegisteredClass::ClassID class_id; *stream >> class_id; switch(class_id) { case MidLevelRenderer::MLRShapeClassID: m_MLRShape = MidLevelRenderer::MLRShape::Make(stream, mlr_version); break; case MidLevelRenderer::MLRCulturShapeClassID: m_MLRShape = MidLevelRenderer::MLRCulturShape::Make(stream, mlr_version); break; default: STOP(("Don't know what this is")); } } } else { int length; *stream >> length; if (shapes) m_MLRShape = (*shapes)(stream, mlr_version, length); else { RegisteredClass::ClassID class_id; *stream >> class_id; switch(class_id) { case MidLevelRenderer::MLRShapeClassID: m_MLRShape = MidLevelRenderer::MLRShape::Make(stream, mlr_version); break; case MidLevelRenderer::MLRCulturShapeClassID: m_MLRShape = MidLevelRenderer::MLRCulturShape::Make(stream, mlr_version); break; default: STOP(("Don't know what this is")); } } } // //------------------------------------------------ // Bump the OBB a tad to help with clipping errors //------------------------------------------------ // if (IsBoundedBySphere()) m_localOBB.sphereRadius *= 1.01f; else { m_localOBB.axisExtents *= 1.01f; m_localOBB.sphereRadius = m_localOBB.axisExtents.GetLength(); } if (s_CheckBounds && !CheckBounds()) s_BoundsWereBad = true; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ElementRenderer::ShapeElement::ShapeElement( ShapeElement *shape, ClassData *class_data ): Element(class_data, shape) { Check_Pointer(this); unsigned index = (m_state>>SyncStateBit) & SyncStateMask; Verify(index < SyncStateCount); m_sync = SyncMethods[index]; index = (m_state>>CullStateBit) & CullStateMask; Verify(index < CullStateCount); m_cameraCull = CullMethods[index].m_cameraCull; m_rayCull = CullMethods[index].m_rayCull; m_sphereTest = CullMethods[index].m_sphereTest; index = (m_state>>DrawStateBit) & DrawStateMask; Verify(index < DrawStateCount); m_draw = DrawMethods[index]; m_worldToLocal = Stuff::LinearMatrix4D::Identity; Check_Object(shape->m_MLRShape); m_MLRShape = shape->m_MLRShape; m_MLRShape->AttachReference(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ElementRenderer::ShapeElement::ShapeElement(ClassData *class_data): Element(class_data) { Check_Pointer(this); unsigned index = (m_state>>SyncStateBit) & SyncStateMask; Verify(index < SyncStateCount); m_sync = SyncMethods[index]; index = (m_state>>CullStateBit) & CullStateMask; Verify(index < CullStateCount); m_cameraCull = CullMethods[index].m_cameraCull; m_rayCull = CullMethods[index].m_rayCull; m_sphereTest = CullMethods[index].m_sphereTest; index = (m_state>>DrawStateBit) & DrawStateMask; Verify(index < DrawStateCount); m_draw = DrawMethods[index]; m_worldToLocal = Stuff::LinearMatrix4D::Identity; gos_PushCurrentHeap(MidLevelRenderer::ShapeHeap); m_MLRShape = new MidLevelRenderer::MLRShape(0); Check_Object(m_MLRShape); gos_PopCurrentHeap(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ElementRenderer::ShapeElement::~ShapeElement() { Check_Object(this); m_MLRShape->DetachReference(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ElementRenderer::ShapeElement* ElementRenderer::ShapeElement::Make( Stuff::MemoryStream *stream, int version, ShapeHolder shapes ) { Check_Object(stream); gos_PushCurrentHeap(s_Heap); ShapeElement *element = new ShapeElement(DefaultData, stream, version, shapes); gos_PopCurrentHeap(); return element; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ShapeElement::Save(Stuff::MemoryStream *stream) { Check_Object(this); Check_Object(stream); BaseClass::Save(stream); // //----------------------------- // Save the shape to the stream //----------------------------- // Check_Object(m_MLRShape); MidLevelRenderer::WriteMLRVersion(stream); *stream << (int)0; unsigned index = stream->GetIndex(); m_MLRShape->Save(stream); unsigned length = stream->GetIndex() - index; stream->RewindPointer(length + sizeof(int)); *stream << length; stream->AdvancePointer(length); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ShapeElement::TestInstance() { Verify(IsDerivedFrom(DefaultData)); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool ElementRenderer::ShapeElement::CheckBounds() { Check_Object(this); return (IsBoundedBySphere()) ? CheckSphereBounds(m_MLRShape, m_localOBB) : CheckOBBBounds(m_MLRShape, m_localOBB); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool ElementRenderer::ShapeElement::CheckSphereBounds( MidLevelRenderer::MLRShape *shape, const Stuff::OBB &sphere ) { Stuff::Point3D center(sphere.localToParent); Stuff::Scalar radius_squared = sphere.sphereRadius*sphere.sphereRadius; int meshes = shape->GetNum(); for (int m=0; mFind(m); Check_Object(mesh); const Stuff::Point3D *verts; int count; mesh->GetCoordData(&verts, &count); for (int v=0; v radius_squared) return false; } } return true; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool ElementRenderer::ShapeElement::CheckOBBBounds( MidLevelRenderer::MLRShape *shape, const Stuff::OBB &obb ) { int meshes = shape->GetNum(); for (int m=0; mFind(m); Check_Object(mesh); const Stuff::Point3D *verts; int count; mesh->GetCoordData(&verts, &count); for (int v=0; v0.0f && (IsMatrixDirty() || m_worldOBB.sphereRadius>0.0f ) ) ); Verify( GetCullMode() == RootMode || m_parent != NULL || AreBoundsWrong() ); unsigned index = (m_state>>SyncStateBit) & SyncStateMask; Verify(index < SyncStateCount); m_sync = SyncMethods[index]; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ShapeElement::SetDrawState() { Check_Object(this); unsigned index = (m_state>>DrawStateBit) & DrawStateMask; Verify(index < DrawStateCount); m_draw = DrawMethods[index]; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ShapeElement::DirtyRootSyncMethod() { Check_Object(this); Verify(IsMatrixDirty() && GetCullMode()==RootMode); SYNC_LOGIC("Root::Dirty::Shape"); // //-------------------- // Update our matrices //-------------------- // m_localToParent = m_localToWorld = m_newLocalToParent; m_worldToLocal.Invert(m_localToWorld); MatrixIsClean(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ShapeElement::DirtySyncMethod() { Check_Object(this); Verify(IsMatrixDirty() && GetCullMode()==NeverCullMode); SYNC_LOGIC("Dirty::Shape"); // //-------------------- // Update our matrices //-------------------- // m_localToParent = m_newLocalToParent; Check_Object(m_parent); if (!IsLocalToParentIdentity()) m_localToWorld.Multiply(m_localToParent, m_parent->GetLocalToWorld()); else m_localToWorld = m_parent->GetLocalToWorld(); m_worldToLocal.Invert(m_localToWorld); MatrixIsClean(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ShapeElement::CleanSphereSyncMethod() { Check_Object(this); Verify(m_localOBB.sphereRadius > 0.0f); Verify( !IsMatrixDirty() && GetCullMode()==VolumeCullMode && IsBoundedBySphere() ); SYNC_LOGIC("Sphere::Clean::Shape"); // //------------------------------- // Update our m_localToWorld matrix //------------------------------- // Check_Object(m_parent); if (!IsLocalToParentIdentity()) m_localToWorld.Multiply(m_localToParent, m_parent->GetLocalToWorld()); else m_localToWorld = m_parent->GetLocalToWorld(); m_worldToLocal.Invert(m_localToWorld); // //------------------------------ // Transform the bounding sphere //------------------------------ // m_worldOBB.MultiplySphereOnly(m_localOBB, m_localToWorld); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ShapeElement::DirtySphereSyncMethod() { Check_Object(this); Verify(m_localOBB.sphereRadius > 0.0f); Verify( IsMatrixDirty() && GetCullMode()==VolumeCullMode && IsBoundedBySphere() ); SYNC_LOGIC("Sphere::Dirty::Shape"); // //-------------------- // Update our matrices //-------------------- // m_localToParent = m_newLocalToParent; Check_Object(m_parent); if (!IsLocalToParentIdentity()) m_localToWorld.Multiply(m_localToParent, m_parent->GetLocalToWorld()); else m_localToWorld = m_parent->GetLocalToWorld(); m_worldToLocal.Invert(m_localToWorld); // //------------------------------ // Transform the bounding sphere //------------------------------ // m_worldOBB.MultiplySphereOnly(m_localOBB, m_localToWorld); MatrixIsClean(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ShapeElement::CleanOBBSyncMethod() { Check_Object(this); Verify( !IsMatrixDirty() && GetCullMode()==VolumeCullMode && IsBoundedByOBB() ); Verify(Stuff::Close_Enough(m_localOBB.sphereRadius, m_localOBB.axisExtents.GetLength(), m_localOBB.sphereRadius*0.02f)); SYNC_LOGIC("OBB::Clean::Shape"); // //------------------------------- // Update our m_localToWorld matrix //------------------------------- // Check_Object(m_parent); if (!IsLocalToParentIdentity()) m_localToWorld.Multiply(m_localToParent, m_parent->GetLocalToWorld()); else m_localToWorld = m_parent->GetLocalToWorld(); m_worldToLocal.Invert(m_localToWorld); // //------------------------------ // Transform the bounding sphere //------------------------------ // m_worldOBB.Multiply(m_localOBB, m_localToWorld); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ShapeElement::DirtyOBBSyncMethod() { Check_Object(this); Verify( IsMatrixDirty() && GetCullMode()==VolumeCullMode && IsBoundedByOBB() ); Verify(Stuff::Close_Enough(m_localOBB.sphereRadius, m_localOBB.axisExtents.GetLength(), m_localOBB.sphereRadius*0.02f)); SYNC_LOGIC("OBB::Dirty::Shape"); // //-------------------- // Update our matrices //-------------------- // m_localToParent = m_newLocalToParent; Check_Object(m_parent); if (!IsLocalToParentIdentity()) m_localToWorld.Multiply(m_localToParent, m_parent->GetLocalToWorld()); else m_localToWorld = m_parent->GetLocalToWorld(); m_worldToLocal.Invert(m_localToWorld); // //------------------------------ // Transform the bounding sphere //------------------------------ // m_worldOBB.Multiply(m_localOBB, m_localToWorld); MatrixIsClean(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool ElementRenderer::ShapeElement::CastCulledRay(CollisionQuery *query) { Check_Object(this); Check_Object(query); Verify(!query->m_data); // //----------------------------------- // Figure out the local m_line equation //----------------------------------- // const Stuff::LinearMatrix4D &world_to_local = GetWorldToLocal(); Check_Object(&world_to_local); Stuff::Line3D local_line; Check_Object(query->m_line); local_line.m_origin.Multiply(query->m_line->m_origin, world_to_local); local_line.m_direction.Multiply(query->m_line->m_direction, world_to_local); local_line.m_length = query->m_line->m_length; // //----------------------------- // Test it against the MidLevelRenderer::MLRShape //----------------------------- // Stuff::Normal3D local_normal; if (m_MLRShape) { Check_Object(m_MLRShape); if (m_MLRShape->CastRay(&local_line, &local_normal)) { query->m_line->m_length = local_line.m_length; const Stuff::LinearMatrix4D &local_to_world = GetLocalToWorld(); Check_Object(&local_to_world); Check_Pointer(query->m_normal); query->m_normal->Multiply(local_normal, local_to_world); Verify(*query->m_normal * query->m_line->m_direction <= -Stuff::SMALL); query->m_data = m_data; return true; } } return false; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ElementRenderer::Element* ElementRenderer::ShapeElement::FindSmallestElementContainingCulled(SphereTest *test) { Check_Object(this); Check_Object(test); return this; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ShapeElement::InheritDrawMethod( CameraElement *camera, const StateChange *inherited_state, int culling_state ) { Check_Object(this); Check_Object(inherited_state); Check_Object(camera); Verify(culling_state != -1); #if defined(_ARMOR) if (!culling_state) Verify(!Cull(camera)); #endif // //-------------------------------------- // Draw our bounds if we are supposed to //-------------------------------------- // #if defined(LAB_ONLY) Callback *callback = GetCallbackSet(); unsigned index = GetCallbackIndex(); if (callback && callback[index]) { Check_Pointer(callback[index]); (*callback[index])(camera, inherited_state, culling_state, this); } else if (s_ShowClippedBounds && GetCullMode() == VolumeCullMode && culling_state) { Stuff::RGBAColor color(1.0f, 0.5f, 0.5f, 0.3f); if (IsBoundedBySphere()) DrawSphere(m_worldOBB, color, camera, inherited_state, culling_state); else DrawOBB(m_worldOBB, color, camera, inherited_state, culling_state); } #endif // //---------------------------- // Set up the draw information //---------------------------- // MidLevelRenderer::DrawShapeInformation info; Check_Object(m_MLRShape); info.shape = m_MLRShape; info.clippingFlags.SetClippingState(culling_state); Check_Object(&m_localToWorld); info.shapeToWorld = &m_localToWorld; Check_Object(&m_worldToLocal); info.worldToShape = &m_worldToLocal; info.state = inherited_state->GetMLRState(); info.paintMeColor = &FadeColor; #if defined (LAB_ONLY) && defined (HUNT_FOR_THE_MISSING_SHADOW) if(m_MLRShape->GetNum()>0) { MidLevelRenderer::MLRTexture *tex = (*MidLevelRenderer::MLRTexturePool::Instance)[&m_MLRShape->Find(0)->GetReferenceState()]; MidLevelRenderer::GOSImage *image = tex->GetImage(); const char *tex_name = gos_GetTextureName(image->GetHandle()); SPEW((HUNT_FOR_THE_MISSING_SHADOW, "D: %s", tex_name)); } #endif LightList culled_lights; info.nrOfActiveLights = CullLights(culled_lights, inherited_state->m_lights); info.activeLights = (info.nrOfActiveLights>0) ? &culled_lights[0] : NULL; // //--------------- // Draw the shape //--------------- // MidLevelRenderer::MLRClipper *clipper = camera->GetClipper(); Check_Object(clipper); Stop_Timer(Graph_Traversal); ELEMENT_RENDER("Culling::Shape::Inherited"); Start_Timer(Draw_Shapes); clipper->DrawShape(&info); Stop_Timer(Draw_Shapes); Start_Timer(Graph_Traversal); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ShapeElement::OverrideDrawMethod( CameraElement *camera, const StateChange *inherited_state, int culling_state ) { Check_Object(this); Check_Object(inherited_state); Check_Object(camera); Verify(culling_state != -1); #if defined(_ARMOR) if (!culling_state) Verify(!Cull(camera)); #endif // //------------------- // Mix the properties //------------------- // Check_Object(m_stateChange); StateChange mixed; mixed.Mix(*inherited_state, *m_stateChange); MixLights( mixed.m_lights, inherited_state->m_lights, m_stateChange->m_lights ); // //-------------------------------------- // Draw our bounds if we are supposed to //-------------------------------------- // #if defined(LAB_ONLY) Callback *callback = GetCallbackSet(); unsigned index = GetCallbackIndex(); if (callback && callback[index]) { Check_Pointer(callback[index]); (*callback[index])(camera, &mixed, culling_state, this); } else if (s_ShowClippedBounds && GetCullMode() == VolumeCullMode && culling_state) { Stuff::RGBAColor color(1.0f, 0.5f, 0.5f, 0.3f); if (IsBoundedBySphere()) DrawSphere(m_worldOBB, color, camera, &mixed, culling_state); else DrawOBB(m_worldOBB, color, camera, &mixed, culling_state); } #endif // //---------------------------- // Set up the draw information //---------------------------- // MidLevelRenderer::DrawShapeInformation info; Check_Object(m_MLRShape); info.shape = m_MLRShape; info.clippingFlags.SetClippingState(culling_state); Check_Object(&m_localToWorld); info.shapeToWorld = &m_localToWorld; Check_Object(&m_worldToLocal); info.worldToShape = &m_worldToLocal; info.state = mixed.GetMLRState(); info.paintMeColor = &FadeColor; LightList culled_lights; #if defined (LAB_ONLY) && defined (HUNT_FOR_THE_MISSING_SHADOW) MidLevelRenderer::MLRTexture *tex = (*MidLevelRenderer::MLRTexturePool::Instance)[&m_MLRShape->Find(0)->GetReferenceState()]; MidLevelRenderer::GOSImage *image = tex->GetImage(); const char *tex_name = gos_GetTextureName(image->GetHandle()); SPEW((HUNT_FOR_THE_MISSING_SHADOW, "D: %s", tex_name)); #endif info.nrOfActiveLights = CullLights(culled_lights, mixed.m_lights); info.activeLights = (info.nrOfActiveLights>0) ? &culled_lights[0] : NULL; // //--------------- // Draw the shape //--------------- // MidLevelRenderer::MLRClipper *clipper = camera->GetClipper(); Check_Object(clipper); Stop_Timer(Graph_Traversal); ELEMENT_RENDER("Culling::Shape::Overridden"); Start_Timer(Draw_Shapes); clipper->DrawShape(&info); Stop_Timer(Draw_Shapes); Start_Timer(Graph_Traversal); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ShapeElement::SetMLRShape(MidLevelRenderer::MLRShape *shape) { Check_Object(this); Check_Object(shape); if (m_MLRShape) { Check_Object(m_MLRShape); m_MLRShape->DetachReference(); } m_MLRShape = shape; m_MLRShape->AttachReference(); } extern DWORD Disable_Lights; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int ElementRenderer::ShapeElement::CullLights( LightList culled_lights, const LightList lights ) { Check_Object(this); // //---------------------------------------------------------------- // Set up the destination light array and start copying the lights //---------------------------------------------------------------- // if (Disable_Lights) return 0; ELEMENT_RENDER("Culling::ShapeLOD::Lights"); Start_Timer(Light_Culling_Time); int new_count = 0; Stuff::Point3D center(m_worldOBB.localToParent); for (int i=0; iGetIntensity() < Stuff::SMALL) continue; // //-------------------------------------------------------------------- // If we are copying a light with a range, check it against the bounds // of this node and only copy if it would hit the bounds //-------------------------------------------------------------------- // if (light->IsDerivedFrom(MidLevelRenderer::MLRInfiniteLightWithFalloff::DefaultData)) { MidLevelRenderer::MLRInfiniteLightWithFalloff *bounded_light = Cast_Object(MidLevelRenderer::MLRInfiniteLightWithFalloff*, light); Stuff::Point3D lc(bounded_light->GetLightToWorldMatrix()); Stuff::Vector3D diff; diff.Subtract(center, lc); Stuff::Scalar range = m_worldOBB.sphereRadius + bounded_light->GetFalloffFar(); if (diff.GetLengthSquared() < range*range) culled_lights[new_count++] = light; } // //--------------------------------- // Otherwise it is automatically in //--------------------------------- // else culled_lights[new_count++] = light; if (new_count >= s_MaxLightsPerShape) { #if defined (LAB_ONLY) && defined (HUNT_FOR_THE_MISSING_SHADOW) SPEW((HUNT_FOR_THE_MISSING_SHADOW, "L: %d+", new_count)); #endif break; } } #if defined (LAB_ONLY) && defined (HUNT_FOR_THE_MISSING_SHADOW) SPEW((HUNT_FOR_THE_MISSING_SHADOW, "L: %d", new_count)); #endif Verify(new_count <= MidLevelRenderer::Limits::Max_Number_Of_Lights_Per_Primitive); Stop_Timer(Light_Culling_Time); return new_count; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int ElementRenderer::ShapeElement::CountTriangles() { Check_Object(this); if (m_MLRShape) { Check_Object(m_MLRShape); return m_MLRShape->GetNumPrimitives(); } return 0; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ShapeElement::CleanDamage() { Check_Object(this); Check_Object(m_MLRShape); Verify(m_MLRShape->GetReferenceCount() == 1); m_MLRShape->CleanMe(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ShapeElement::ApplyDamage( const Stuff::LinearMatrix4D &damage_spot, Stuff::Scalar radius ) { Check_Object(this); Check_Object(&damage_spot); Check_Object(m_MLRShape); Verify(m_MLRShape->GetReferenceCount() == 1); m_MLRShape->HurtMe(damage_spot, radius); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ShapeElement::ApplyDamageDecal( const Stuff::LinearMatrix4D &damage_spot, Stuff::Scalar radius, MidLevelRenderer::MLRTexture *texture ) { Check_Object(this); Check_Object(&damage_spot); Check_Object(m_MLRShape); Verify(m_MLRShape->GetReferenceCount() == 1); m_MLRShape->HurtMe(damage_spot, radius, texture); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ShapeElement::CastShadow( const Stuff::LinearMatrix4D &shadow_to_world, const Stuff::UnitVector3D &sun_in_world, Stuff::Scalar radius ) { if (!IsShadowed()) return; MidLevelRenderer::MLRShape *mlr_shape = GetMLRShape(); Stuff::LinearMatrix4D world_to_object; world_to_object.Invert(GetLocalToWorld()); Stuff::UnitVector3D sun_in_object; sun_in_object.Multiply(sun_in_world, world_to_object); Stuff::LinearMatrix4D shadow_to_object; shadow_to_object.Multiply(shadow_to_world, world_to_object); mlr_shape->DrawMyShadow(shadow_to_object, sun_in_object, radius); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ShapeElement::MakeFootStep( MidLevelRenderer::MLRShape *shape, const Stuff::LinearMatrix4D &foot, Stuff::Scalar radius, MidLevelRenderer::MLRTexture *tex ) { MidLevelRenderer::MLRShape *mlr_shape = GetMLRShape(); Stuff::LinearMatrix4D world_to_object; world_to_object.Invert(GetLocalToWorld()); Stuff::LinearMatrix4D foot_to_object; foot_to_object.Multiply(foot, world_to_object); mlr_shape->StepOnMe(shape, foot_to_object, radius, tex); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Returns array of vertex coordinates and number of vertices void ElementRenderer::ShapeElement::GetCoordData(Stuff::DynamicArrayOf *array) { Check_Object(this); array->SetLength(0); int meshes = m_MLRShape->GetNum(); for(int m=0; mFind(m); Check_Object(mesh); const Stuff::Point3D *verts; int count; mesh->GetCoordData(&verts, &count); int point_count = array->GetLength(); array->SetLength(point_count+count); for (int v=0; v