#include "ElementRendererHeaders.hpp" //#define SCALE_BUG "your_loginname_here" //############################################################################ //############################ ScalableShapeElement ################################ //############################################################################ HGOSHEAP ElementRenderer::ScalableShapeElement::s_Heap = NULL; ElementRenderer::ScalableShapeElement::ClassData* ElementRenderer::ScalableShapeElement::DefaultData = NULL; ElementRenderer::Element::SyncMethod ElementRenderer::ScalableShapeElement::SyncMethods[SyncStateCount]= { // // Root mode // SYNC_METHOD(Element, Clean), SYNC_METHOD(Element, Dirty), SYNC_METHOD(Element, Clean), SYNC_METHOD(Element, Dirty), SYNC_METHOD(Element, None), SYNC_METHOD(Element, Defer), SYNC_METHOD(Element, None), SYNC_METHOD(Element, Defer), SYNC_METHOD(Element, Clean), SYNC_METHOD(Element, Dirty), SYNC_METHOD(Element, Clean), SYNC_METHOD(Element, Dirty), SYNC_METHOD(Element, None), SYNC_METHOD(Element, Defer), SYNC_METHOD(Element, None), SYNC_METHOD(Element, Defer), // // Sphere Cull // SYNC_METHOD(ScalableShapeElement, CleanSphere), SYNC_METHOD(ScalableShapeElement, DirtySphere), SYNC_METHOD(ScalableShapeElement, CleanSphere), SYNC_METHOD(ScalableShapeElement, DirtySphere), SYNC_METHOD(Element, None), SYNC_METHOD(Element, Defer), SYNC_METHOD(Element, None), SYNC_METHOD(Element, Defer), // // OBB Cull // SYNC_METHOD(ScalableShapeElement, CleanOBB), SYNC_METHOD(ScalableShapeElement, DirtyOBB), SYNC_METHOD(ScalableShapeElement, CleanOBB), SYNC_METHOD(ScalableShapeElement, DirtyOBB), SYNC_METHOD(Element, None), SYNC_METHOD(Element, Defer), SYNC_METHOD(Element, None), SYNC_METHOD(Element, Defer), // // Never Cull // SYNC_METHOD(Element, Clean), SYNC_METHOD(Element, Dirty), SYNC_METHOD(Element, Clean), SYNC_METHOD(Element, Dirty), SYNC_METHOD(Element, None), SYNC_METHOD(Element, Defer), SYNC_METHOD(Element, None), SYNC_METHOD(Element, Defer), SYNC_METHOD(Element, Clean), SYNC_METHOD(Element, Dirty), SYNC_METHOD(Element, Clean), SYNC_METHOD(Element, 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::ScalableShapeElement::DrawMethods[DrawStateCount]= { // // No billboarding // DRAW_METHOD(ScalableShapeElement, Inherit), DRAW_METHOD(ScalableShapeElement, Override) }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ScalableShapeElement::InitializeClass() { Verify(!s_Heap); s_Heap = gos_CreateMemoryHeap("Scalable Shape", 0, g_LibraryHeap); Check_Pointer(s_Heap); Verify(!DefaultData); DefaultData = new ClassData( ScalableShapeElementClassID, "ElementRenderer::ScalableShapeElement", BaseClass::DefaultData, reinterpret_cast(&Make) ); Register_Object(DefaultData); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ScalableShapeElement::TerminateClass() { Unregister_Object(DefaultData); delete DefaultData; DefaultData = NULL; Check_Pointer(s_Heap); gos_DestroyMemoryHeap(s_Heap); s_Heap = NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ElementRenderer::ScalableShapeElement::ScalableShapeElement( Stuff::MemoryStream *stream, int version, ShapeHolder shapes, bool read_scale_from_stream ): ShapeElement(DefaultData, stream, version, shapes) { 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]; // //------------------------ // Get the scale and color //------------------------ // if (read_scale_from_stream) *stream >> m_scale >> m_color; else { m_scale.x = 1.0f; m_scale.y = 1.0f; m_scale.z = 1.0f; m_color.red = 1.0f; m_color.green = 1.0f; m_color.blue = 1.0f; m_color.alpha = 1.0f; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ElementRenderer::ScalableShapeElement::ScalableShapeElement(): ShapeElement(DefaultData) { 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_scale.x = 1.0f; m_scale.y = 1.0f; m_scale.z = 1.0f; m_color.red = 1.0f; m_color.green = 1.0f; m_color.blue = 1.0f; m_color.alpha = 1.0f; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ElementRenderer::ScalableShapeElement::ScalableShapeElement(ScalableShapeElement *shape): ShapeElement(shape, DefaultData) { 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_scale.x = 1.0f; m_scale.y = 1.0f; m_scale.z = 1.0f; m_color.red = 1.0f; m_color.green = 1.0f; m_color.blue = 1.0f; m_color.alpha = 1.0f; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ElementRenderer::ScalableShapeElement* ElementRenderer::ScalableShapeElement::Make( Stuff::MemoryStream *stream, int version, ShapeHolder shapes ) { Check_Object(stream); gos_PushCurrentHeap(s_Heap); ScalableShapeElement *element = new ScalableShapeElement(stream, version, shapes, true); gos_PopCurrentHeap(); return element; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ElementRenderer::ScalableShapeElement* ElementRenderer::ScalableShapeElement::MakeFromShape( Stuff::MemoryStream *stream, int version, ShapeHolder shapes ) { Check_Object(stream); RegisteredClass::ClassID class_id; *stream >> class_id; Verify(class_id == ShapeElementClassID); gos_PushCurrentHeap(s_Heap); ScalableShapeElement *element = new ScalableShapeElement(stream, version, shapes, false); gos_PopCurrentHeap(); return element; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ScalableShapeElement::Save(Stuff::MemoryStream *stream) { Check_Object(this); Check_Object(stream); BaseClass::Save(stream); // //----------------------------- // Save the shape to the stream //----------------------------- // *stream << m_scale << m_color; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ScalableShapeElement::TestInstance() { Verify(IsDerivedFrom(DefaultData)); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ScalableShapeElement::SetSyncState() { Check_Object(this); Verify( GetCullMode() != VolumeCullMode || AreBoundsWrong() || IsSyncDeferred() || ( m_localOBB.sphereRadius>0.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::ScalableShapeElement::CleanSphereSyncMethod() { Check_Object(this); Verify(m_localOBB.sphereRadius > 0.0f); Verify( !IsMatrixDirty() && GetCullMode()==VolumeCullMode && IsBoundedBySphere() ); SYNC_LOGIC("Sphere::Clean::ScalableShape"); // //------------------------------- // 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(); // //------------------------------ // Transform the bounding sphere //------------------------------ // Stuff::Point3D local_origin(m_localOBB.localToParent); local_origin *= m_scale; m_worldOBB.localToParent(3,0) = local_origin.x*m_localToWorld(0,0) + local_origin.y*m_localToWorld(1,0) + local_origin.z*m_localToWorld(2,0) + m_localToWorld(3,0); m_worldOBB.localToParent(3,1) = local_origin.x*m_localToWorld(0,1) + local_origin.y*m_localToWorld(1,1) + local_origin.z*m_localToWorld(2,1) + m_localToWorld(3,1); m_worldOBB.localToParent(3,2) = local_origin.x*m_localToWorld(0,2) + local_origin.y*m_localToWorld(1,2) + local_origin.z*m_localToWorld(2,2) + m_localToWorld(3,2); m_worldOBB.sphereRadius = m_localOBB.sphereRadius * m_scale.GetLength(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ScalableShapeElement::DirtySphereSyncMethod() { Check_Object(this); Verify(m_localOBB.sphereRadius > 0.0f); Verify( IsMatrixDirty() && GetCullMode()==VolumeCullMode && IsBoundedBySphere() ); SYNC_LOGIC("Sphere::Dirty::ScalableShape"); // //-------------------- // 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(); // //------------------------------ // Transform the bounding sphere //------------------------------ // Stuff::Point3D local_origin(m_localOBB.localToParent); local_origin *= m_scale; m_worldOBB.localToParent(3,0) = local_origin.x*m_localToWorld(0,0) + local_origin.y*m_localToWorld(1,0) + local_origin.z*m_localToWorld(2,0) + m_localToWorld(3,0); m_worldOBB.localToParent(3,1) = local_origin.x*m_localToWorld(0,1) + local_origin.y*m_localToWorld(1,1) + local_origin.z*m_localToWorld(2,1) + m_localToWorld(3,1); m_worldOBB.localToParent(3,2) = local_origin.x*m_localToWorld(0,2) + local_origin.y*m_localToWorld(1,2) + local_origin.z*m_localToWorld(2,2) + m_localToWorld(3,2); m_worldOBB.sphereRadius = m_localOBB.sphereRadius * m_scale.GetLength(); MatrixIsClean(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ScalableShapeElement::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)); Verify( Stuff::Close_Enough(m_localOBB.localToParent(0,0), 1.0f) && Stuff::Close_Enough(m_localOBB.localToParent(1,1), 1.0f) && Stuff::Close_Enough(m_localOBB.localToParent(2,2), 1.0f) ); SYNC_LOGIC("OBB::Clean::ScalableShape"); // //------------------------------- // 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(); // //------------------------------ // Transform the bounding sphere //------------------------------ // Stuff::LinearMatrix4D scaled_transform = m_localOBB.localToParent; scaled_transform(3,0) *= m_scale.x; scaled_transform(3,1) *= m_scale.y; scaled_transform(3,2) *= m_scale.z; m_worldOBB.localToParent.Multiply(scaled_transform, m_localToWorld); m_worldOBB.axisExtents.Multiply(m_localOBB.axisExtents, m_scale); m_worldOBB.sphereRadius = m_worldOBB.axisExtents.GetLength(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ScalableShapeElement::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)); Verify( Stuff::Close_Enough(m_localOBB.localToParent(0,0), 1.0f) && Stuff::Close_Enough(m_localOBB.localToParent(1,1), 1.0f) && Stuff::Close_Enough(m_localOBB.localToParent(2,2), 1.0f) ); SYNC_LOGIC("OBB::Dirty::ScalableShape"); // //-------------------- // 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(); // //------------------------------ // Transform the bounding sphere //------------------------------ // Stuff::LinearMatrix4D scaled_transform = m_localOBB.localToParent; scaled_transform(3,0) *= m_scale.x; scaled_transform(3,1) *= m_scale.y; scaled_transform(3,2) *= m_scale.z; m_worldOBB.localToParent.Multiply(scaled_transform, m_localToWorld); m_worldOBB.axisExtents.Multiply(m_localOBB.axisExtents, m_scale); m_worldOBB.sphereRadius = m_worldOBB.axisExtents.GetLength(); #if defined(SCALE_BUG) SPEW((SCALE_BUG, "m_worldOBB = ")); Spew(SCALE_BUG, m_worldOBB); SPEW((SCALE_BUG, "")); #endif MatrixIsClean(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool ElementRenderer::ScalableShapeElement::CastCulledRay(CollisionQuery *query) { Check_Object(this); Check_Object(query); STOP(("ScalableShape is not collidable!")); return false; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ElementRenderer::Element* ElementRenderer::ScalableShapeElement::FindSmallestElementContainingCulled(SphereTest *test) { Check_Object(this); Check_Object(test); STOP(("ScalableShape is not collidable!")); return NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ScalableShapeElement::SetDrawState() { Check_Object(this); unsigned index = (m_state>>DrawStateBit) & DrawStateMask; Verify(index < DrawStateCount); m_draw = DrawMethods[index]; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ScalableShapeElement::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::DrawScalableShapeInformation info; Check_Object(m_MLRShape); info.shape = m_MLRShape; info.clippingFlags.SetClippingState(culling_state); Check_Object(&m_localToWorld); info.shapeToWorld = &m_localToWorld; info.worldToShape = NULL; info.state = inherited_state->GetMLRState(); LightList culled_lights; info.nrOfActiveLights = CullLights(culled_lights, inherited_state->m_lights); info.activeLights = (info.nrOfActiveLights>0) ? &culled_lights[0] : NULL; info.scaling = &m_scale; info.paintMeColor = &m_color; // //--------------- // Draw the shape //--------------- // MidLevelRenderer::MLRClipper *clipper = camera->GetClipper(); Check_Object(clipper); Stop_Timer(Graph_Traversal); ELEMENT_RENDER("Culling::ScalableShape::Inherited"); Start_Timer(Draw_Scalable); clipper->DrawScalableShape(&info); Stop_Timer(Draw_Scalable); Start_Timer(Graph_Traversal); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::ScalableShapeElement::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::DrawScalableShapeInformation info; Check_Object(m_MLRShape); info.shape = m_MLRShape; info.clippingFlags.SetClippingState(culling_state); Check_Object(&m_localToWorld); info.shapeToWorld = &m_localToWorld; info.worldToShape = NULL; info.state = mixed.GetMLRState(); LightList culled_lights; info.nrOfActiveLights = CullLights(culled_lights, mixed.m_lights); info.activeLights = (info.nrOfActiveLights>0) ? &culled_lights[0] : NULL; info.scaling = &m_scale; info.paintMeColor = &m_color; // //--------------- // Draw the shape //--------------- // MidLevelRenderer::MLRClipper *clipper = camera->GetClipper(); Check_Object(clipper); Stop_Timer(Graph_Traversal); ELEMENT_RENDER("Culling::ScalableShape::Overridden"); Start_Timer(Draw_Scalable); clipper->DrawScalableShape(&info); Stop_Timer(Draw_Scalable); Start_Timer(Graph_Traversal); }