#include "AdeptHeaders.hpp" #include "CollisionVolume.hpp" #include "Entity.hpp" #include #include #include "Application.hpp" //#define OBB_BUG "jmalbert" static ElementRenderer::Element::Callback *Old_Callbacks = NULL; static ElementRenderer::Element::Callback Callbacks[1<> m_localSpaceBounds; Verify(m_localSpaceBounds.axisExtents.x >= 0.0f); Verify(m_localSpaceBounds.axisExtents.y >= 0.0f); Verify(m_localSpaceBounds.axisExtents.z >= 0.0f); *stream >> m_material; m_worldSpaceBounds.localToParent = LinearMatrix4D::Identity; m_worldSpaceBounds.sphereRadius = -1.0f; // //------------------------------ // Read the name if one is there //------------------------------ // if (version > 1) { MString joint_name; *stream >> joint_name; } m_entity = entity; // //------------------------------------------------------------------- // If we are reading version 2 or less, remap the material to the new // settings //------------------------------------------------------------------- // if (version < 3) { switch (m_material&0x1f) { case 0: //DirtMaterial, m_material |= BrownDirtMaterial; break; case 2: //RockMaterial, m_material &= ~0x1f; m_material |= RockMaterial; break; case 3: //SteelMaterial, m_material &= ~0x1f; m_material |= SteelMaterial; break; case 4: //BlacktopMaterial, m_material &= ~0x1f; m_material |= BlacktopMaterial; break; case 5: //UsMaterial, m_material &= ~0x1f; m_material |= UsMaterial; break; case 6: //ThemMaterial, m_material &= ~0x1f; m_material |= ThemMaterial; break; case 7: //VehicleMaterial, m_material &= ~0x1f; m_material |= SteelMaterial; break; case 8: //GlassMaterial, m_material &= ~0x1f; m_material |= GlassMaterial; break; case 9: //BrickMaterial, m_material &= ~0x1f; m_material |= ConcreteMaterial; break; case 10: //GrassMaterial, m_material &= ~0x1f; m_material |= GrassMaterial; break; case 11: //WoodMaterial, m_material &= ~0x1f; m_material |= WoodMaterial; break; case 12: //TreeMaterial, m_material &= ~0x1f; m_material |= WoodMaterial; break; case 13: //SwampMaterial, m_material &= ~0x1f; m_material |= GrassMaterial; break; case 14: //ConcreteMaterial, m_material &= ~0x1f; m_material |= ConcreteMaterial; break; case 15: //RoughMaterial, m_material &= ~0x1f; m_material |= GrassMaterial; break; case 16: //SnowMaterial, m_material &= ~0x1f; m_material |= SnowMaterial; break; case 17: //UnderbrushMaterial, m_material &= ~0x1f; m_material |= GrassMaterial; break; case 18: //ShallowWaterMaterial, m_material &= ~0x1f; m_material |= WaterMaterial; break; case 19: //MidWaterMaterial, m_material &= ~0x1f; m_material |= WaterMaterial; break; case 20: //DesertMaterial, m_material &= ~0x1f; m_material |= BrownDirtMaterial; break; case 21: //FlatSwampMaterial, m_material &= ~0x1f; m_material |= GrassMaterial; break; case 22: //ThickSwampMaterial, m_material &= ~0x1f; m_material |= GrassMaterial; break; case 23: //RedRockMaterial, m_material &= ~0x1f; m_material |= RockMaterial; break; case 24: //GreyDirtMaterial, m_material &= ~0x1f; m_material |= GreyDirtMaterial; break; case 25: //DarkDirtMaterial, m_material &= ~0x1f; m_material |= DarkBrownDirtMaterial; break; case 26: //DarkDesertMaterial, m_material &= ~0x1f; m_material |= DarkBrownDirtMaterial; break; case 27: //DarkRedRockMaterial, m_material &= ~0x1f; m_material |= DarkRockMaterial; break; case 28: //DarkRockMaterial, m_material &= ~0x1f; m_material |= DarkRockMaterial; break; case 29: //DarkConcreteMaterial, m_material &= ~0x1f; m_material |= DarkConcreteMaterial; break; case 30: //DarkGreyDirtMaterial, m_material &= ~0x1f; m_material |= DarkGreyDirtMaterial; break; } } // //----------------------------------------------------------------------- // Non-armatured objects can read in an arbitrary tree, all of which will // be attached to the same entity //----------------------------------------------------------------------- // BYTE count; *stream >> count; #if defined(_ARMOR) if (!count) Verify(m_localSpaceBounds.sphereRadius > 0.0f); #endif while (count-- > 0) { CollisionVolume *obb = new CollisionVolume(entity, stream, version); Check_Object(obb); m_children.Add(obb); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CollisionVolume::CollisionVolume( Entity *main_entity, ChildFinder find_function, Entity *joint_entity, MemoryStream *stream, int version ): Plug(DefaultData), m_children(NULL) { Check_Pointer(this); Check_Object(main_entity); Check_Pointer(find_function); Check_Object(joint_entity); Check_Object(stream); // //-------------------------------- // Read in the bounds and material //-------------------------------- // *stream >> m_localSpaceBounds; Verify(m_localSpaceBounds.axisExtents.x >= 0.0f); Verify(m_localSpaceBounds.axisExtents.y >= 0.0f); Verify(m_localSpaceBounds.axisExtents.z >= 0.0f); *stream >> m_material; m_worldSpaceBounds.localToParent = LinearMatrix4D::Identity; m_worldSpaceBounds.sphereRadius = -1.0f; // //--------------------------------------------------------------- // All named OBBs represent parental OBBs and must have no radius //--------------------------------------------------------------- // Verify(version > 1); MString joint_name; *stream >> joint_name; if (joint_name) { Verify(m_localSpaceBounds.sphereRadius == 0.0f); joint_entity = (*find_function)(main_entity, joint_name); #if defined(OBB_BUG) SPEW((OBB_BUG, "Building null node %s", (char*)joint_name)); #endif #if defined(LAB_ONLY) if (!joint_entity) STOP(("Error - couldn't find joint %s", (char*)joint_name)); #endif if (joint_entity != main_entity) { Check_Object(joint_entity); Verify(!joint_entity->hierarchicalVolume); joint_entity->hierarchicalVolume = this; } } // //---------------------------------- // All unnamed OBBs must have bounds //---------------------------------- // else { Verify(m_localSpaceBounds.sphereRadius > 0.0f); #if defined(OBB_BUG) SPEW((OBB_BUG, "Building %f radius obb node", m_localSpaceBounds.sphereRadius)); #endif } m_entity = joint_entity; Check_Object(m_entity); // //------------------------------ // Read in the hierarchy of OBBs //------------------------------ // BYTE count; *stream >> count; #if defined(_ARMOR) if (!count) Verify(m_localSpaceBounds.sphereRadius > 0.0f); #endif while (count-- > 0) { CollisionVolume *obb = new CollisionVolume(main_entity, find_function, joint_entity, stream, version); Check_Object(obb); m_children.Add(obb); // //------------------------------------------------------------------------ // If we don't have a joint name, and the child is attached to our entity, // go ahead and multiply his bounds into our space //------------------------------------------------------------------------ // if (!joint_name && m_entity==obb->m_entity) { OBB new_obb; new_obb.Multiply(obb->m_localSpaceBounds, m_localSpaceBounds.localToParent); obb->m_localSpaceBounds = new_obb; } } #if defined(OBB_BUG) if (joint_name.GetLength() > 0) SPEW((OBB_BUG, "Done building null node %s", (char*)joint_name)); else SPEW((OBB_BUG, "Done building %f radius obb node", m_localSpaceBounds.sphereRadius)); #endif } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CollisionVolume::~CollisionVolume() { Check_Object(this); // //---------------------- // Delete the child OBBs //---------------------- // if (m_entity) { if (!m_entity->solidVolume && m_entity->hierarchicalVolume == this) m_entity->hierarchicalVolume = NULL; } m_children.DeletePlugs(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void CollisionVolume::Save(MemoryStream *stream) { Check_Object(this); Check_Object(stream); // //--------------------------------- // Save out the bounds and material //--------------------------------- // *stream << m_localSpaceBounds; *stream << m_material; *stream << MString(GetName()); // //-------------------------------- // Save out the number of children //-------------------------------- // BYTE count = 0; ChainIteratorOf children(&m_children); CollisionVolume *volume; while ((volume = children.ReadAndNext()) != NULL) { Check_Object(volume); ++count; Verify(count < 255); } *stream << count; // //---------------------- // Save out the children //---------------------- // children.First(); while ((volume = children.ReadAndNext()) != NULL) { Check_Object(volume); volume->Save(stream); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // const char* CollisionVolume::GetName() { Check_Object(this); return NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void CollisionVolume::FindEntityToWorld( Stuff::LinearMatrix4D *entity_to_world, Entity *base, const Stuff::LinearMatrix4D &base_to_world ) { Check_Object(this); Check_Object(base); // //-------------------------------------------------------------------------- // If the base is our entity, just copy the base to world into the entity to // world variable //-------------------------------------------------------------------------- // if (base == m_entity) { *entity_to_world = base_to_world; return; } // //-------------------------------------------------------------------------- // Otherwise, we have to concatenate up the entity chain until we get to the // base entity //-------------------------------------------------------------------------- // LinearMatrix4D entity_to_base = m_entity->GetLocalToParent(); Entity *entity = m_entity->GetParentEntity(); while (entity != base) { Check_Object(entity); *entity_to_world = entity_to_base; entity_to_base.Multiply(*entity_to_world, entity->GetLocalToParent()); entity = entity->GetParentEntity(); } entity_to_world->Multiply(entity_to_base, base_to_world); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CollisionVolume* CollisionVolume::CastRay( Entity::CollisionQuery *query, Entity *base, const Stuff::LinearMatrix4D &base_to_world ) { Check_Object(this); Check_Object(query); // //-------------------------------- // See if the entity can be struck //-------------------------------- // if (IsDestroyed()) return NULL; #if defined(LAB_ONLY) ElementRenderer::Element *element = m_entity->GetElement(); Check_Object(element); #endif // //------------------------------- // Figure out where our entity is //------------------------------- // LinearMatrix4D entity_to_world; FindEntityToWorld(&entity_to_world, base, base_to_world); m_worldSpaceBounds.Multiply(m_localSpaceBounds, entity_to_world); // //------------------- // See if we this box //------------------- // Line3D *line = query->m_line; Check_Object(line); int axis=0; Scalar len=-1.0f; if (m_worldSpaceBounds.sphereRadius > 0.0f) { len = line->GetDistanceTo(m_worldSpaceBounds, &axis); if (len == -1.0 || len > line->m_length) { #if defined(LAB_ONLY) if (Show_Line_vs_OBBs) { Verify(element->GetCallbackSet() == Callbacks); unsigned callback = element->GetCallbackIndex(); if (callback < DrawOBBRejected) element->SetCallbackIndex(DrawOBBRejected); } #endif return NULL; } else { #if defined(LAB_ONLY) if (Show_Line_vs_OBBs) { Verify(element->GetCallbackSet() == Callbacks); unsigned callback = element->GetCallbackIndex(); if (callback < DrawOBBTraversed) element->SetCallbackIndex(DrawOBBTraversed); } #endif } } // //---------------------------------------------------------- // If we did hit the box, and there are no children, we done //---------------------------------------------------------- // ChainIteratorOf children(&m_children); if (!children.GetCurrent()) { Verify(m_worldSpaceBounds.sphereRadius > 0.0f); query->m_material = static_cast(m_material & e_MaterialMask); bool exit_now; if (!(m_material&e_GoodEnough) && m_entity->GetInterestLevel() == Entity::RenderingInterestLevel) { RAYCAST_LOGIC("vs. Polygons"); Start_Timer(Poly_Ray_Cast); exit_now = m_entity->GetElement()->CastRay(query); Stop_Timer(Poly_Ray_Cast); Verify(!exit_now || *query->m_normal * query->m_line->m_direction < -SMALL); } else { Verify(len >= 0.0f); query->m_line->m_length = len; // //------------------------------------------------------------------------------- // Since we hit the OBB, we have to figure out the new normal. All the collision // told us was which local-space axis was struck, so lets just go get it from the // matrix of the world obb //------------------------------------------------------------------------------- // query->m_normal->x = m_worldSpaceBounds.localToParent(axis, 0); query->m_normal->y = m_worldSpaceBounds.localToParent(axis, 1); query->m_normal->z = m_worldSpaceBounds.localToParent(axis, 2); query->m_normal->Normalize(*query->m_normal); if (*query->m_normal*line->m_direction >= -SMALL) query->m_normal->Negate(*query->m_normal); exit_now = true; Verify(*query->m_normal * query->m_line->m_direction < -SMALL); } query->m_data = NULL; #if defined(LAB_ONLY) if (Show_Line_vs_OBBs) { Verify(element->GetCallbackSet() == Callbacks); if (!(m_material&e_GoodEnough) && m_entity->GetInterestLevel() == Entity::RenderingInterestLevel) element->SetCallbackIndex(DrawOBBPolygonsTested); else element->SetCallbackIndex(DrawOBBStruck); } #endif if (exit_now) return this; } // //------------------------------------------------------------- // Check all our children, and keep the hit that is the closest //------------------------------------------------------------- // CollisionVolume* result = NULL; CollisionVolume *volume; while ((volume = children.ReadAndNext()) != NULL) { Check_Object(volume); CollisionVolume *temp = volume->CastRay(query, m_entity, entity_to_world); if (temp) result = temp; } return result; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CollisionVolume* CollisionVolume::CollideOBB( CollisionVolume *solid, Entity *base, const Stuff::LinearMatrix4D &base_to_world ) { Check_Object(this); Check_Object(solid); // //-------------------------------- // See if this is a trivial reject //-------------------------------- // if (IsDestroyed()) return NULL; // //------------------------------- // Figure out where our entity is //------------------------------- // LinearMatrix4D entity_to_world; FindEntityToWorld(&entity_to_world, base, base_to_world); m_worldSpaceBounds.Multiply(m_localSpaceBounds, entity_to_world); // //------------------- // See if we this box //------------------- // Check_Object(m_entity); Check_Object(solid->m_entity); #if defined(LAB_ONLY) ElementRenderer::Element *our_element = m_entity->GetElement(); Check_Object(our_element); ElementRenderer::Element *their_element = solid->m_entity->GetElement(); Check_Object(their_element); #endif if (m_worldSpaceBounds.sphereRadius > 0.0f) { int axis = solid->m_worldSpaceBounds.FindSeparatingAxis(m_worldSpaceBounds); if (axis != OBB::NoSeparation) { #if defined(LAB_ONLY) if (Show_OBB_vs_OBBs) { Verify(our_element->GetCallbackSet() == Callbacks); unsigned callback = our_element->GetCallbackIndex(); if (callback < DrawOBBRejected) our_element->SetCallbackIndex(DrawOBBRejected); callback = their_element->GetCallbackIndex(); if (callback < DrawOBBRejected) their_element->SetCallbackIndex(DrawOBBRejected); } #endif return NULL; } } // //---------------------------------------------------------- // If we did hit the box, and there are no children, we done //---------------------------------------------------------- // ChainIteratorOf children(&m_children); if (!children.GetCurrent()) { Verify(m_worldSpaceBounds.sphereRadius > 0.0f); #if defined(LAB_ONLY) if (Show_OBB_vs_OBBs) { Verify(our_element->GetCallbackSet() == Callbacks); our_element->SetCallbackIndex(DrawOBBStruck); their_element->SetCallbackIndex(DrawOBBStruck); } #endif return this; } // //------------------------------------------------------------- // Check all our children, and keep the hit that is the closest //------------------------------------------------------------- // #if defined(LAB_ONLY) if (Show_OBB_vs_OBBs) { Verify(our_element->GetCallbackSet() == Callbacks); unsigned callback = our_element->GetCallbackIndex(); if (callback < DrawOBBTraversed) our_element->SetCallbackIndex(DrawOBBTraversed); } #endif CollisionVolume* result = NULL; CollisionVolume *volume; while ((volume = children.ReadAndNext()) != NULL) { Check_Object(volume); CollisionVolume *temp = volume->CollideOBB(solid, m_entity, entity_to_world); if (temp) result = temp; } return result; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void CollisionVolume::FindSolidsWithin( const Stuff::Sphere &sphere, WithinCallback callback, Entity *original_caller, Entity *base, const Stuff::LinearMatrix4D &base_to_world ) { Check_Object(this); Check_Object(&sphere); Check_Pointer(callback); // //-------------------------------- // See if this is a trivial reject //-------------------------------- // if (IsDestroyed()) return; // //------------------------------- // Figure out where our entity is //------------------------------- // LinearMatrix4D entity_to_world; FindEntityToWorld(&entity_to_world, base, base_to_world); m_worldSpaceBounds.Multiply(m_localSpaceBounds, entity_to_world); // //--------------------------------- // See if this box is in the sphere //--------------------------------- // if (m_worldSpaceBounds.sphereRadius > 0.0f) { Sphere us(m_worldSpaceBounds); if (!sphere.Intersects(us)) return; } // //----------------------- // Check all our children //----------------------- // ChainIteratorOf children(&m_children); if (!children.GetCurrent()) { Verify(m_worldSpaceBounds.sphereRadius > 0.0f); (*callback)(this, original_caller); } else { CollisionVolume *volume; while ((volume = children.ReadAndNext()) != NULL) { Check_Object(volume); volume->FindSolidsWithin( sphere, callback, original_caller, m_entity, entity_to_world ); } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int CollisionVolume::ReadOBBVersion(MemoryStream *stream) { Check_Object(stream); // //------------------------------------------------------------------------ // See if this file has an erf signature. If so, the next int will be the // version number. If not, assume it is version 1 and rewind the file //------------------------------------------------------------------------ // int version = CurrentOBBVersion+1; int obb_signature; *stream >> obb_signature; if (obb_signature == 'OBB#') *stream >> version; else stream->RewindPointer(sizeof(obb_signature)); if (version > CurrentOBBVersion) STOP(("Application must be rebuilt to use this version of OBB data")); return version; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void CollisionVolume::WriteOBBVersion(MemoryStream *stream) { Check_Object(stream); *stream << 'OBB#' << static_cast(CurrentOBBVersion); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void CollisionVolume::DrawOBBRejectedCallback( ElementRenderer::CameraElement *camera, const ElementRenderer::StateChange *state, int culling_state, ElementRenderer::Element *element ) { Check_Object(camera); Check_Object(state); Check_Object(element); // //-------------------------------- // Figure out the collision volume //-------------------------------- // Entity *entity = Cast_Object(Entity*, element->GetClientData()); CollisionVolume *solid = entity->GetHierarchicalVolume(); if (!solid || Show_OBB_vs_OBBs) solid = entity->GetSolidVolume(); if (solid) { Check_Object(solid); // //----------------- // Draw blue bounds //----------------- // if (solid->m_localSpaceBounds.sphereRadius>0.0f) { solid->m_worldSpaceBounds.Multiply(solid->m_localSpaceBounds, entity->GetLocalToWorld()); ElementRenderer::Element::DrawOBB( solid->m_worldSpaceBounds, Blue, camera, state, 0x3f ); } else { ChainIteratorOf children(&solid->m_children); CollisionVolume *child; while ((child = children.ReadAndNext()) != NULL) { Check_Object(child); if (child->m_localSpaceBounds.sphereRadius > 0.0f && child->m_entity == solid->m_entity) { child->m_worldSpaceBounds.Multiply(child->m_localSpaceBounds, entity->GetLocalToWorld()); ElementRenderer::Element::DrawOBB( child->m_worldSpaceBounds, Blue, camera, state, 0x3f ); } } } } element->SetCallbackIndex(0); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void CollisionVolume::DrawOBBTraversedCallback( ElementRenderer::CameraElement *camera, const ElementRenderer::StateChange *state, int culling_state, ElementRenderer::Element *element ) { Check_Object(camera); Check_Object(state); Check_Object(element); // //-------------------------------- // Figure out the collision volume //-------------------------------- // Entity *entity = Cast_Object(Entity*, element->GetClientData()); CollisionVolume *solid = entity->GetHierarchicalVolume(); if (!solid || Show_OBB_vs_OBBs) solid = entity->GetSolidVolume(); // //------------------------------------------------------------------------- // This branchs is used by non-articulated objects. If there are children, // draw them first in yellow //------------------------------------------------------------------------- // if (solid) { Check_Object(solid); if (solid->m_localSpaceBounds.sphereRadius > 0.0f) { ChainIteratorOf children(&solid->m_children); if (children.GetCurrent()==NULL) { solid->m_worldSpaceBounds.Multiply(solid->m_localSpaceBounds, entity->GetLocalToWorld()); ElementRenderer::Element::DrawOBB( solid->m_worldSpaceBounds, Blue, camera, state, 0x3f ); } else { CollisionVolume *child; while ((child = children.ReadAndNext()) != NULL) { Check_Object(child); if (child->m_entity != solid->m_entity) continue; Verify(child->m_localSpaceBounds.sphereRadius > 0.0f); child->m_worldSpaceBounds.Multiply(child->m_localSpaceBounds, entity->GetLocalToWorld()); ElementRenderer::Element::DrawOBB( child->m_worldSpaceBounds, Blue, camera, state, 0x3f ); } } } // //----------------------------------------------------------------------- // This branch is used by articulated objects. If this joint was struck, // only draw our children who are also attached to our entity //----------------------------------------------------------------------- // else { ChainIteratorOf children(&solid->m_children); CollisionVolume *child; while ((child = children.ReadAndNext()) != NULL) { Check_Object(child); if (child->m_entity != solid->m_entity) continue; // //--------------------------------------------------------------- // Check each child to see if it has children itself. If not, go // ahead and draw it //--------------------------------------------------------------- // ChainIteratorOf grandchildren(&child->m_children); if (!grandchildren.GetCurrent()) { Verify(child->m_localSpaceBounds.sphereRadius > 0.0f); child->m_worldSpaceBounds.Multiply(child->m_localSpaceBounds, entity->GetLocalToWorld()); ElementRenderer::Element::DrawOBB( child->m_worldSpaceBounds, Blue, camera, state, 0x3f ); } else { CollisionVolume *grandchild; while ((grandchild = grandchildren.ReadAndNext()) != NULL) { Check_Object(grandchild); Verify(grandchild->m_localSpaceBounds.sphereRadius > 0.0f); grandchild->m_worldSpaceBounds.Multiply(grandchild->m_localSpaceBounds, entity->GetLocalToWorld()); ElementRenderer::Element::DrawOBB( grandchild->m_worldSpaceBounds, Blue, camera, state, 0x3f ); } } } } } element->SetCallbackIndex(0); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void CollisionVolume::DrawOBBStruckCallback( ElementRenderer::CameraElement *camera, const ElementRenderer::StateChange *state, int culling_state, ElementRenderer::Element *element ) { Check_Object(camera); Check_Object(state); Check_Object(element); // //-------------------------------- // Figure out the collision volume //-------------------------------- // Entity *entity = Cast_Object(Entity*, element->GetClientData()); CollisionVolume *solid = entity->GetHierarchicalVolume(); if (!solid || Show_OBB_vs_OBBs) solid = entity->GetSolidVolume(); // //------------------------------------------------------------------------- // This branchs is used by non-articulated objects. If there are children, // draw them first in yellow //------------------------------------------------------------------------- // if (solid) { Check_Object(solid); if (solid->m_localSpaceBounds.sphereRadius > 0.0f) { ChainIteratorOf children(&solid->m_children); if (children.GetCurrent()==NULL) { solid->m_worldSpaceBounds.Multiply(solid->m_localSpaceBounds, entity->GetLocalToWorld()); ElementRenderer::Element::DrawOBB( solid->m_worldSpaceBounds, Sparkles[0], camera, state, 0x3f ); } else { CollisionVolume *child; int sparkle=0; while ((child = children.ReadAndNext()) != NULL) { Check_Object(child); if (child->m_entity != solid->m_entity) continue; Verify(child->m_localSpaceBounds.sphereRadius > 0.0f); child->m_worldSpaceBounds.Multiply(child->m_localSpaceBounds, entity->GetLocalToWorld()); ElementRenderer::Element::DrawOBB( child->m_worldSpaceBounds, Sparkles[(sparkle++)&3], camera, state, 0x3f ); } } } // //----------------------------------------------------------------------- // This branch is used by articulated objects. If this joint was struck, // only draw our children who are also attached to our entity //----------------------------------------------------------------------- // else { ChainIteratorOf children(&solid->m_children); CollisionVolume *child; int sparkle = 0; while ((child = children.ReadAndNext()) != NULL) { Check_Object(child); if (child->m_entity != solid->m_entity) continue; // //--------------------------------------------------------------- // Check each child to see if it has children itself. If not, go // ahead and draw it //--------------------------------------------------------------- // ChainIteratorOf grandchildren(&child->m_children); if (!grandchildren.GetCurrent()) { if (child->m_localSpaceBounds.sphereRadius > 0.0f) { child->m_worldSpaceBounds.Multiply(child->m_localSpaceBounds, entity->GetLocalToWorld()); ElementRenderer::Element::DrawOBB( child->m_worldSpaceBounds, Sparkles[(sparkle++)&3], camera, state, 0x3f ); } } else { CollisionVolume *grandchild; while ((grandchild = grandchildren.ReadAndNext()) != NULL) { Check_Object(grandchild); Verify(grandchild->m_localSpaceBounds.sphereRadius > 0.0f); grandchild->m_worldSpaceBounds.Multiply(grandchild->m_localSpaceBounds, entity->GetLocalToWorld()); ElementRenderer::Element::DrawOBB( grandchild->m_worldSpaceBounds, Sparkles[(sparkle++)&3], camera, state, 0x3f ); } } } } } element->SetCallbackIndex(0); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void CollisionVolume::DrawOBBPolygonsTestedCallback( ElementRenderer::CameraElement *camera, const ElementRenderer::StateChange *state, int culling_state, ElementRenderer::Element *element ) { Check_Object(camera); Check_Object(state); Check_Object(element); // //-------------------------------- // Figure out the collision volume //-------------------------------- // Entity *entity = Cast_Object(Entity*, element->GetClientData()); CollisionVolume *solid = entity->GetHierarchicalVolume(); if (!solid || Show_OBB_vs_OBBs) solid = entity->GetSolidVolume(); if (solid) { Check_Object(solid); Verify(solid->m_localSpaceBounds.sphereRadius > 0.0f); solid->m_worldSpaceBounds.Multiply(solid->m_localSpaceBounds, entity->GetLocalToWorld()); ElementRenderer::Element::DrawOBB( solid->m_worldSpaceBounds, Green, camera, state, 0x3f ); } element->SetCallbackIndex(0); }