//===========================================================================// // File: Map.cpp // // Project: MUNGA Brick: Interest Manager // // Contents: Interface specifications for interest manager // //---------------------------------------------------------------------------// // Date Who Modification // // -------- --- -----------------------------------------------------------// // 11/04/94 ECH Initial coding. // // 11/29/94 JMA Changed Identities to IDs // // 02/10/95 CPB Added GaugeInterestType // // 08/25/97 ECH Infrastructure changes. // //---------------------------------------------------------------------------// // Copyright (C) 1994-1995, Virtual World Entertainment, Inc. // // All Rights reserved worldwide // // This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL // //===========================================================================// #include "AdeptHeaders.hpp" #include "Zone.hpp" #include "Map.hpp" #include "RendererManager.hpp" #include "ExecutionState.hpp" #include "Application.hpp" #include #include #include #include "Tile.hpp" #include "CollisionVolume.hpp" #include "CollisionGrid.hpp" #include "LightManager.hpp" #include #include #include #include #include "dropzone.hpp" #ifdef LAB_ONLY #include bool saveMapBspDifference = false; #endif //############################################################################# //########################### Zone ################################# //############################################################################# Zone::ClassData *Zone::DefaultData = NULL; DWORD Executed_Zone_Entity_Count; DWORD Zone_Entity_Count; DWORD Tile_Entity_Count; static bool Show_Lights=false; static bool Hide_ZoneEntities=false; static bool __stdcall CheckHideZoneEntities() {return Hide_ZoneEntities;} static void __stdcall EnableHideZoneEntities() {Hide_ZoneEntities = !Hide_ZoneEntities;} static bool __stdcall CheckShowLights() {return Show_Lights!=0;} static void __stdcall EnableShowLights() {Show_Lights = !Show_Lights;} //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Zone::InitializeClass() { Verify(!DefaultData); DefaultData = new ClassData( ZoneClassID, "Adept::Zone", ElementRenderer::GroupElement::DefaultData, reinterpret_cast(&Make) ); Register_Object(DefaultData); Zone_Entity_Count = 0; Tile_Entity_Count = 0; #if !defined(NO_STATS) AddStatistic("Zone Entities", "entities", gos_DWORD, &Zone_Entity_Count, 0); AddStatistic("Tile Entities", "entities", gos_DWORD, &Tile_Entity_Count, 0); AddStatistic("Executed Zone Entities", "entities", gos_DWORD, &Executed_Zone_Entity_Count, Stat_AutoReset); #endif AddDebuggerMenuItem("Libraries\\Adept\\Hide Zone Entities", CheckHideZoneEntities, EnableHideZoneEntities, 0 ); AddDebuggerMenuItem("Libraries\\Adept\\Show lights", CheckShowLights, EnableShowLights, 0 ); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Zone::TerminateClass() { Unregister_Object(DefaultData); delete DefaultData; DefaultData = NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Zone::TestInstance() { Verify(IsDerivedFrom(DefaultData)); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Zone::Zone(): GroupElement(DefaultData), m_dormant(NULL), m_simulated(NULL), m_rendered(NULL), m_executors(NULL), m_tiledEntities(NULL), m_flags(0) { m_draw = static_cast(&Zone::Draw); AdoptStateChange(new ElementRenderer::StateChange); Check_Pointer(this); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Zone::~Zone() { Check_Object(this); // //------------------------------------ // Detach any children that were tiled //------------------------------------ // ChainIteratorOf tiled_children(&m_tiledEntities); ElementRenderer::Element *child; while ((child = tiled_children.ReadAndNext()) != NULL) { if (child->GetParentElement()) // jcem... why? child->DetachFromParent(); } // //------------------------------------------------------------------------- // Delete the ground element, then detach anything else hooked to this zone //------------------------------------------------------------------------- // ChainIteratorOf children(&m_group); while ((child = children.ReadAndNext()) != NULL) { if (child->GetParentElement()) // jcem... why? child->DetachFromParent(); } Check_Object(m_tileGrid); delete m_tileGrid; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Zone::Save(MemoryStream *stream) { Check_Object(this); Check_Object(stream); // //-------------------------- // Write stuff to the stream //-------------------------- // *stream << static_cast(ElementRenderer::GroupElementClassID) << m_state; if (m_stateChange) { Check_Object(m_stateChange); Verify(m_state & PropertyChangeFlag); m_stateChange->Save(stream); } if (!IsLocalToParentIdentity()) *stream << m_localToParent; // //-------------------------- // Write the bounding volume //-------------------------- // if (IsBoundedByOBB()) { *stream << m_localOBB.localToParent << m_localOBB.axisExtents << m_localOBB.sphereRadius; } else { Point3D center(m_localOBB.localToParent); *stream << center; *stream << m_localOBB.sphereRadius; } // //----------------------------------------------------------- // Write out the child count and then the children themselves //----------------------------------------------------------- // ChainIteratorOf elements(&m_group); ElementRenderer::Element *element; *stream << elements.GetSize(); while ((element = elements.ReadAndNext()) != NULL) { Check_Object(element); element->Save(stream); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Zone::CreateTileGrid( Stuff::Scalar row, Stuff::Scalar column ) { Check_Object(this); // //------------------------------------------------ // Create the tile grid and attach it to ourselves //------------------------------------------------ // m_tileGrid = new ElementRenderer::GridElement( e_TilesPerZone, e_TilesPerZone, row, column, c_ZoneSize, c_ZoneSize ); Check_Object(m_tileGrid); AttachChild(m_tileGrid); m_tileGrid->LockBounds(); Check_Object(CollisionGrid::Instance); // //----------------------------------------------------------------- // Now create a group node under each tile. Also hook it up to the // collision grid //----------------------------------------------------------------- // Verify((m_row+1)*e_TilesPerZone <= 256); Verify((m_column+1)*e_TilesPerZone <= 256); for (BYTE r=0; r(m_row*e_TilesPerZone+r), static_cast(m_column*e_TilesPerZone+c) ); Check_Object(tile); CollisionGrid::Instance->AttachIndexedChild( tile->m_row, tile->m_column, tile ); m_tileGrid->AttachIndexedChild(r, c, tile); tile->LockBounds(); } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Zone::SetInterestLevel( Entity* entity, Entity::InterestLevel type ) { Check_Object(this); Check_Object(entity); Verify(!entity->m_pendingInterestMessage.GetCurrent()); // //-------------------------------------- // Make sure this isn't a trivial change //-------------------------------------- // Entity::InterestLevel zone_interest = GetInterestLevel(), entity_interest = entity->GetInterestLevel(); if (type == entity_interest) return; // //----------------------------------------------------------------- // Look for the interaction between the zone and new interest state //----------------------------------------------------------------- // switch ((zone_interest<<2) | type) { case (Entity::DormantInterestLevel<<2)|Entity::DormantInterestLevel: Verify(m_dormant.IsPlugMember(entity)); Verify(!m_simulated.IsPlugMember(entity)); Verify(!m_rendered.IsPlugMember(entity)); entity->BecomeUninteresting(); Verify(!m_executors.IsPlugMember(entity)); break; case (Entity::DormantInterestLevel<<2)|Entity::RenderingInterestLevel: Verify(m_dormant.IsPlugMember(entity)); Verify(!m_simulated.IsPlugMember(entity)); Verify(!m_rendered.IsPlugMember(entity)); Verify(!m_executors.IsPlugMember(entity)); break; case (Entity::DormantInterestLevel<<2)|Entity::SimulationInterestLevel: Verify(m_dormant.IsPlugMember(entity)); Verify(!m_simulated.IsPlugMember(entity)); Verify(!m_rendered.IsPlugMember(entity)); Verify(!m_executors.IsPlugMember(entity)); break; case (Entity::SimulationInterestLevel<<2)|Entity::DormantInterestLevel: Verify(!m_dormant.IsPlugMember(entity)); Verify(m_simulated.IsPlugMember(entity)); Verify(!m_rendered.IsPlugMember(entity)); m_simulated.RemovePlug(entity); m_dormant.Add(entity); entity->BecomeUninteresting(); Verify(!m_executors.IsPlugMember(entity)); break; case (Entity::SimulationInterestLevel<<2)|Entity::SimulationInterestLevel: if (entity_interest == Entity::DormantInterestLevel) { Verify(m_dormant.IsPlugMember(entity)); Verify(!m_simulated.IsPlugMember(entity)); Verify(!m_rendered.IsPlugMember(entity)); m_dormant.RemovePlug(entity); m_simulated.Add(entity); entity->BecomeInteresting(false); } break; case (Entity::SimulationInterestLevel<<2)|Entity::RenderingInterestLevel: if (entity_interest == Entity::DormantInterestLevel) { Verify(m_dormant.IsPlugMember(entity)); Verify(!m_simulated.IsPlugMember(entity)); Verify(!m_rendered.IsPlugMember(entity)); m_dormant.RemovePlug(entity); m_simulated.Add(entity); entity->BecomeInteresting(false); } break; case (Entity::RenderingInterestLevel<<2)|Entity::DormantInterestLevel: if (entity_interest == Entity::SimulationInterestLevel) { Verify(!m_rendered.IsPlugMember(entity)); Verify(m_simulated.IsPlugMember(entity)); m_simulated.RemovePlug(entity); } else { Verify(!m_simulated.IsPlugMember(entity)); Verify(m_rendered.IsPlugMember(entity)); m_rendered.RemovePlug(entity); } Verify(!m_dormant.IsPlugMember(entity)); m_dormant.Add(entity); entity->BecomeUninteresting(); Verify(!m_executors.IsPlugMember(entity)); break; case (Entity::RenderingInterestLevel<<2)|Entity::SimulationInterestLevel: Verify(!m_simulated.IsPlugMember(entity)); if (entity_interest == Entity::DormantInterestLevel) { Verify(m_dormant.IsPlugMember(entity)); m_dormant.RemovePlug(entity); } else { Verify(m_rendered.IsPlugMember(entity)); m_rendered.RemovePlug(entity); } Verify(!m_simulated.IsPlugMember(entity)); m_simulated.Add(entity); entity->BecomeInteresting(false); break; case (Entity::RenderingInterestLevel<<2)|Entity::RenderingInterestLevel: Verify(!m_rendered.IsPlugMember(entity)); if (entity_interest == Entity::DormantInterestLevel) { Verify(m_dormant.IsPlugMember(entity)); m_dormant.RemovePlug(entity); } else { Verify(m_simulated.IsPlugMember(entity)); m_simulated.RemovePlug(entity); } Verify(!m_rendered.IsPlugMember(entity)); m_rendered.Add(entity); entity->BecomeInteresting(true); break; default: STOP(("Illegal interest level setting")); break; } // //-------------------- // Set the entity mask //-------------------- // entity->SetInterestMask(type); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Zone::AttachChild(ElementRenderer::Element *child) { Check_Object(this); Check_Object(child); Verify( Close_Enough( GetLocalToWorld(), LinearMatrix4D::Identity ) ); Verify( Close_Enough( GetNewLocalToParent(), LinearMatrix4D::Identity ) ); Verify(!m_rendered.IsPlugMember(child)); Verify(!m_simulated.IsPlugMember(child)); Verify(!m_dormant.IsPlugMember(child)); #ifdef _DEBUG // jcem Entity* pEnt = static_cast(child->GetClientData()); if (pEnt && pEnt->IsDerivedFrom(DropZone::DefaultData)) { pEnt++; pEnt--; } #endif // _DEBUG // //------------------------------------------------------------------- // If this is the ground, attach it directly to ourselves and be done //------------------------------------------------------------------- // if (child == m_tileGrid) { GroupElement::AttachChild(child); return; } // //------------------------------------------------------------------- // Attach the entity to the appropriate parent in the video hierarchy //------------------------------------------------------------------- // Entity *entity = Cast_Object(Entity*, child->GetClientData()); Verify(!entity->m_pendingInterestMessage.GetCurrent()); Verify(!m_executors.IsPlugMember(child)); Tile *tile = NULL; if (!entity->IsTileBound()) { GroupElement::AttachChild(child); Set_Statistic(Zone_Entity_Count, Zone_Entity_Count+1); gosASSERT(!m_tiledEntities.IsPlugMember(child)); } else { Set_Statistic(Tile_Entity_Count, Tile_Entity_Count+1); Point3D location(child->GetNewLocalToParent()); ElementRenderer::GridElement *tile_grid = Cast_Object(ElementRenderer::GridElement*, m_tileGrid); Verify( Close_Enough( tile_grid->GetLocalToWorld(), LinearMatrix4D::Identity ) ); Verify( Close_Enough( tile_grid->GetNewLocalToParent(), LinearMatrix4D::Identity ) ); WORD index = tile_grid->FindElementIndex(location.z, location.x); tile = Cast_Object( Tile*, tile_grid->ListElement::GetIndexedElement(index) ); tile->AttachChild(child); Verify(!m_tiledEntities.IsPlugMember(child)); m_tiledEntities.Add(child); } // //----------------------------------------------------------------- // Look at the combination of the zone/entity interest level to see // what chains to hook up //----------------------------------------------------------------- // Entity::InterestLevel zone_interest = GetInterestLevel(), entity_interest = entity->GetInterestLevel(); switch ((zone_interest<<2) | entity_interest) { case (Entity::DormantInterestLevel<<2)|Entity::DormantInterestLevel: case (Entity::DormantInterestLevel<<2)|Entity::RenderingInterestLevel: case (Entity::DormantInterestLevel<<2)|Entity::SimulationInterestLevel: { if (!entity->IsNeverExecuteState()) { EnableExecution(); Verify(entity != Map::GetInstance()); m_executors.Add(entity); } } break; case (Entity::SimulationInterestLevel<<2)|Entity::DormantInterestLevel: { m_simulated.Add(entity); entity->BecomeInteresting(false); Non_Dormant_Zone_Gets_Dormant_Entity: if (!entity->IsNeverExecuteState()) { Verify(entity != Map::GetInstance()); m_executors.Add(entity); } HookUpCollision(entity); } break; case (Entity::SimulationInterestLevel<<2)|Entity::SimulationInterestLevel: { m_simulated.Add(entity); if (!entity->IsNeverExecuteState()) { Verify(entity != Map::GetInstance()); m_executors.Add(entity); } HookUpCollision(entity); } break; case (Entity::SimulationInterestLevel<<2)|Entity::RenderingInterestLevel: { m_simulated.Add(entity); if (!entity->IsNeverExecuteState()) { Verify(entity != Map::GetInstance()); m_executors.Add(entity); } HookUpCollision(entity); } break; case (Entity::RenderingInterestLevel<<2)|Entity::DormantInterestLevel: m_rendered.Add(entity); entity->BecomeInteresting(true); goto Non_Dormant_Zone_Gets_Dormant_Entity; case (Entity::RenderingInterestLevel<<2)|Entity::SimulationInterestLevel: { m_rendered.Add(entity); entity->BecomeInteresting(true); if (!entity->IsNeverExecuteState()) { Verify(entity != Map::GetInstance()); m_executors.Add(entity); } HookUpCollision(entity); } break; case (Entity::RenderingInterestLevel<<2)|Entity::RenderingInterestLevel: { m_rendered.Add(entity); if (!entity->IsNeverExecuteState()) { Verify(entity != Map::GetInstance()); m_executors.Add(entity); } HookUpCollision(entity); } break; default: STOP(("Illegal interest level setting")); break; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Zone::DetachChild(ElementRenderer::Element *child) { Check_Object(this); Check_Object(child); #ifdef _DEBUG // jcem Entity* pEnt = static_cast(child->GetClientData()); if (pEnt && pEnt->IsDerivedFrom(DropZone::DefaultData)) { pEnt++; pEnt--; } #endif // _DEBUG // //----------------------------------------------------- // If this is the tile grid, let GroupElement handle it //----------------------------------------------------- // if (child == m_tileGrid) { GroupElement::DetachChild(child); return; } // //------------------------------------------------------- // Remove the entity from execution if it is on the chain //------------------------------------------------------- // Entity *entity = Cast_Object(Entity*, child->GetClientData()); if (!entity->IsNeverExecuteState()) { Verify(m_executors.IsPlugMember(entity)); RemoveExecutor(entity); } else Verify(!m_executors.IsPlugMember(entity)); // //------------------- // Deal with the zone //------------------- // Entity::InterestLevel zone_interest = GetInterestLevel(), entity_interest = entity->GetInterestLevel(); switch ((zone_interest<<2) | entity_interest) { case (Entity::DormantInterestLevel<<2)|Entity::DormantInterestLevel: case (Entity::DormantInterestLevel<<2)|Entity::SimulationInterestLevel: case (Entity::DormantInterestLevel<<2)|Entity::RenderingInterestLevel: case (Entity::SimulationInterestLevel<<2)|Entity::DormantInterestLevel: case (Entity::RenderingInterestLevel<<2)|Entity::DormantInterestLevel: Verify(m_dormant.IsPlugMember(entity)); Verify(!m_simulated.IsPlugMember(entity)); Verify(!m_rendered.IsPlugMember(entity)); m_dormant.RemovePlug(entity); break; case (Entity::SimulationInterestLevel<<2)|Entity::RenderingInterestLevel: case (Entity::SimulationInterestLevel<<2)|Entity::SimulationInterestLevel: case (Entity::RenderingInterestLevel<<2)|Entity::SimulationInterestLevel: UnhookCollision(entity); Not_Quite_Done: Verify(!m_dormant.IsPlugMember(entity)); Verify(m_simulated.IsPlugMember(entity)); Verify(!m_rendered.IsPlugMember(entity)); m_simulated.RemovePlug(entity); break; case (Entity::RenderingInterestLevel<<2)|Entity::RenderingInterestLevel: UnhookCollision(entity); if (entity->m_pendingInterestMessage.GetCurrent()) goto Not_Quite_Done; Verify(!m_dormant.IsPlugMember(entity)); Verify(!m_simulated.IsPlugMember(entity)); Verify(m_rendered.IsPlugMember(entity)); m_rendered.RemovePlug(entity); break; default: STOP(("Illegal interest level setting")); break; } // //--------------------------------------------------------------------- // Detach the entity from the appropriate parent in the video hierarchy //--------------------------------------------------------------------- // Tile *tile = NULL; if (!entity->IsTileBound()) { GroupElement::DetachChild(child); Set_Statistic(Zone_Entity_Count, Zone_Entity_Count-1); gosASSERT(!m_tiledEntities.IsPlugMember(child)); } else { Set_Statistic(Tile_Entity_Count, Tile_Entity_Count-1); Point3D location(child->GetNewLocalToParent()); ElementRenderer::GridElement *tile_grid = Cast_Object(ElementRenderer::GridElement*, m_tileGrid); Verify( Close_Enough( tile_grid->GetLocalToWorld(), LinearMatrix4D::Identity ) ); Verify( Close_Enough( tile_grid->GetNewLocalToParent(), LinearMatrix4D::Identity ) ); WORD index = tile_grid->FindElementIndex(location.z, location.x); tile = Cast_Object( Tile*, tile_grid->ListElement::GetIndexedElement(index) ); Verify(tile == child->GetParentElement()); tile->DetachChild(child); m_tiledEntities.RemovePlug(child); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Zone::SetDrawState() { Check_Object(this); m_draw = static_cast(&Zone::Draw); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Zone::Draw( ElementRenderer::CameraElement *camera, const ElementRenderer::StateChange *inherited_state, int culling_state ) { Check_Object(this); Check_Object(inherited_state); Check_Object(camera); Verify(culling_state != -1); // //------------------- // Mix the properties //------------------- // ElementRenderer::StateChange mixed; mixed.Mix(*inherited_state, *m_stateChange); int zone_lights = MixLights( mixed.m_lights, inherited_state->m_lights, m_stateChange->m_lights ); Verify(zone_lights <= MidLevelRenderer::Limits::Max_Number_Of_Lights_Per_Primitive); // //-------------------------------------- // 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); } #endif // //------------------- // Draw the tile grid //------------------- // ChainIteratorOf children(&m_group); ElementRenderer::Element *child = children.ReadAndNext(); Check_Object(child); Verify(Cast_Object(ElementRenderer::GridElement*, child) != NULL); camera->DrawElement(child, inherited_state); // //------------------------------------------------------------------- // We will only process a child for lights if it is not culled, so do // that part of the function ourself //------------------------------------------------------------------- // Check_Object(CollisionGrid::Instance); Scalar row_scale = 1.0f/CollisionGrid::Instance->m_rowCellSize; Scalar column_scale = 1.0f/CollisionGrid::Instance->m_columnCellSize; #if defined(LAB_ONLY) if (Hide_ZoneEntities) goto Do_Lights; #endif while ((child = children.ReadAndNext()) != NULL) { Check_Object(child); Verify(child->GetClassID() == ElementRenderer::GroupElementClassID); int culling_state = child->Cull(camera); if (culling_state == -1) continue; // //-------------------------------------------------------------------- // The child was not culled, so check it for lights. To get lighting, // it needs a bounding volume and needs to enable the light flags //-------------------------------------------------------------------- // const OBB &obb = child->GetWorldOBB(); Scalar radius = obb.sphereRadius; ElementRenderer::StateChange *state = child->GetStateChange(); if (radius>0.0f && state && state->GetLightingMode() != 0) { Check_Object(state); // //------------------------------- // Figure out the grid boundaries //------------------------------- // Point3D center(obb.localToParent); Scalar min_z = (center.z - radius - CollisionGrid::Instance->m_rowOffset) * row_scale; BYTE min_row = (min_z < 0.0f) ? (BYTE)0 : Truncate_Float_To_Byte(min_z); Scalar max_z = (center.z + radius - CollisionGrid::Instance->m_rowOffset) * row_scale; BYTE max_row = Truncate_Float_To_Byte(max_z); if (max_row >= CollisionGrid::Instance->m_rowCellCount) max_row = static_cast(CollisionGrid::Instance->m_rowCellCount - 1); Scalar min_x = (center.x - radius - CollisionGrid::Instance->m_columnOffset) * column_scale; BYTE min_col = (min_x < 0.0f) ? (BYTE)0 : Truncate_Float_To_Byte(min_x); Scalar max_x = (center.x + radius - CollisionGrid::Instance->m_columnOffset) * column_scale; BYTE max_col = Truncate_Float_To_Byte(max_x); if (max_col >= CollisionGrid::Instance->m_columnCellCount) max_col = static_cast(CollisionGrid::Instance->m_columnCellCount - 1); Verify( min_col <= max_col && max_col < CollisionGrid::Instance->m_columnCellCount ); Verify( min_row <= max_row && max_row < CollisionGrid::Instance->m_rowCellCount ); // //---------------------------------------------------- // Copy the lights we have so far into the final array //---------------------------------------------------- // int base_light = zone_lights; int max_light = zone_lights; ElementRenderer::StateChange object_state(mixed); int k; for (k=0; kGetTile(z, x); Check_Object(tile); // //---------------------------------------- // Make sure the light array is up to date //---------------------------------------- // if (tile->m_lightsChanged) tile->UpdateLights(); ElementRenderer::StateChange *tile_state = tile->GetStateChange(); Check_Object(tile_state); if (max_light==base_light) { for ( k=0; km_lights[k]; ++k ) { Verify(max_light < MidLevelRenderer::Limits::Max_Number_Of_Lights_Per_Primitive); MidLevelRenderer::MLRLight *light = tile_state->m_lights[k]; Check_Object(light); if (light->GetIntensity() < SMALL) continue; 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) continue; object_state.m_lights[max_light++] = light; if (max_light == MidLevelRenderer::Limits::Max_Number_Of_Lights_Per_Primitive) goto Draw_Now; } } // //------------------------------------------------------------------- // Check each tile light to see if it should be put into the new list //------------------------------------------------------------------- // else { for ( int j=0; jm_lights[j]; ++j ) { Verify(max_light < MidLevelRenderer::Limits::Max_Number_Of_Lights_Per_Primitive); MidLevelRenderer::MLRLight *light = tile_state->m_lights[j]; Check_Object(light); if (light->GetIntensity() < SMALL) continue; 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) continue; for (int kk=base_light; kkDrawTo(camera, &object_state, culling_state); } else child->DrawTo(camera, &mixed, culling_state); camera->m_acceptingElement = NULL; } // //-------------------------------------- // Draw our bounds if we are supposed to //-------------------------------------- // #if defined(LAB_ONLY) Do_Lights: if (Show_Lights) { Stuff::OBB obb; obb.axisExtents = Vector3D::Identity; for (BYTE z=static_cast(m_row<<3); z<=static_cast((m_row<<3)+7); ++z) { for (BYTE x=static_cast(m_column<<3); x<=static_cast((m_column<<3)+7); ++x) { Tile *tile = CollisionGrid::Instance->GetTile(z, x); Check_Object(tile); // //---------------------------------------- // Make sure the light array is up to date //---------------------------------------- // if (tile->m_lightsChanged) tile->UpdateLights(); // //-------------------------------------------------------------- // Step through each tile and draw all its lights if they are on //-------------------------------------------------------------- // ElementRenderer::StateChange *tile_state = tile->GetStateChange(); Check_Object(tile_state); for ( int k=0; km_lights[k]; ++k ) { MidLevelRenderer::MLRLight *light = tile_state->m_lights[k]; Check_Object(light); Scalar intensity = light->GetIntensity(); if (intensity>0.0f) { MidLevelRenderer::MLRInfiniteLightWithFalloff* finite = Cast_Object(MidLevelRenderer::MLRInfiniteLightWithFalloff*,light); obb.localToParent = LinearMatrix4D::Identity; Point3D position; finite->GetInWorldPosition(position); obb.localToParent.BuildTranslation(position); obb.sphereRadius = finite->GetFalloffFar(); Stuff::RGBAColor color; finite->GetColor(color); color.alpha = intensity*0.3f; DrawSphere(obb, color, camera, inherited_state, 0x2f); } } } } } #endif } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Zone::EnableExecution() { Check_Object(this); Check_Object(Map::GetInstance()); Verify(GetInterestLevel() == Entity::DormantInterestLevel); // //---------------------------------------------------------- // Set the zone status and add it to the Map::Instance chain //---------------------------------------------------------- // ActivateZone(); Map::GetInstance()->m_executingZones.Add(this); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Zone::ActivateZone() { Check_Object(this); Check_Object(Map::GetInstance()); Verify(GetInterestLevel() == Entity::DormantInterestLevel); // //---------------------- // Load up the materials //---------------------- // unsigned index = m_row*Map::GetInstance()->m_columnZoneCount + m_column; Zone::ResourceData *zone_res = Map::GetInstance()->GetZoneResourceData(index); Check_Object(zone_res); if (zone_res->m_materialResourceID != ResourceID::Null) { m_materialResource.FindID(zone_res->m_materialResourceID); Verify(m_materialResource.DoesResourceExist()); m_materialArray = Cast_Pointer(BYTE*, m_materialResource.GetPointer()); Verify(m_materialResource.GetSize() == 0x10000); } else m_materialArray = NULL; // //---------------- // Load up the bsp //---------------- // m_bspResource.FindID(zone_res->m_bspResourceID); Verify(m_bspResource.DoesResourceExist()); m_bspResource >> m_planeCount; m_planes = Cast_Pointer(const Plane*, m_bspResource.GetPointer()); m_bspResource.AdvancePointer(m_planeCount * sizeof(Plane)); for (WORD i=0; i<64; ++i) { int bsp_size; m_bspResource >> bsp_size; Tile *tile = Cast_Object(Tile*, m_tileGrid->GetIndexedElement(i)); tile->m_BSPCount = *Cast_Pointer(WORD*, m_bspResource.GetPointer()); m_bspResource.AdvancePointer(sizeof(WORD)); Verify(!tile->m_BSP); tile->m_BSP = Cast_Pointer(TerrainBSP*, m_bspResource.GetPointer()); m_bspResource.AdvancePointer(tile->m_BSPCount*sizeof(TerrainBSP)); } // //----------------------------------------- // Hook up each of the children to the zone //----------------------------------------- // SetInterestLevel(Entity::SimulationInterestLevel); Verify(!Map::GetInstance()->m_executingZones.IsPlugMember(this)); Map::GetInstance()->m_executingZones.Add(this); ChainIteratorOf invalids(&m_dormant); Entity *entity; while ((entity = invalids.GetCurrent()) != NULL) { Check_Object(entity); Verify(!entity->m_pendingInterestMessage.GetCurrent()); entity->SyncMatrices(true); Verify(!m_rendered.IsPlugMember(entity)); Verify(!m_simulated.IsPlugMember(entity)); m_simulated.Add(entity); entity->BecomeInteresting(false); Verify(entity->GetInterestLevel() != Entity::DormantInterestLevel); // //------------------------------------------------------------- // If we are executing, place the entity on its execution chain //------------------------------------------------------------- // if (!entity->IsNeverExecuteState()) { if (GetInterestLevel() == Entity::DormantInterestLevel) EnableExecution(); Verify(entity != Map::GetInstance()); Verify(!m_executors.IsPlugMember(entity)); m_executors.Add(entity); } // //------------------------------------------------------------------ // Deal with the collision needs and remove it from the invalid list //------------------------------------------------------------------ // HookUpCollision(entity); invalids.Remove(); Verify(!m_dormant.IsPlugMember(entity)); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Zone::EnableRendering() { Check_Object(this); Verify(GetInterestLevel() != Entity::RenderingInterestLevel); Verify(!Application::GetInstance()->m_localMissionParameters->m_runDedicated); // //----------------------------------------- // Make sure that the zone can be simulated //----------------------------------------- // Check_Object(Map::GetInstance()); Map::GetInstance()->m_renderedZones.Add(this); if (GetInterestLevel() == Entity::DormantInterestLevel) ActivateZone(); Verify(GetInterestLevel() == Entity::SimulationInterestLevel); SetInterestLevel(Entity::RenderingInterestLevel); // //---------------------------------- // Load up the ground into the tiles //---------------------------------- // unsigned index = m_row*Map::GetInstance()->m_columnZoneCount + m_column; Zone::ResourceData *zone_res = Map::GetInstance()->GetZoneResourceData(index); Check_Object(zone_res); Resource shape_stream(zone_res->m_geometryResourceID); Check_Object(m_tileGrid); int version = ElementRenderer::ReadERFVersion(&shape_stream); #ifdef LAB_ONLY BYTE *raw_power = NULL; HGOSFILE fd = NULL; if(saveMapBspDifference==true) { char file_name[16]; sprintf(file_name, "HDiff_%c%c.raw", 'A'+m_row, 'A'+m_column); raw_power = new BYTE [256*256*3]; memset(raw_power, 0, 256*256*3); gos_OpenFile( &fd, file_name, READWRITE ); } #endif for (WORD i=0; i<64; ++i) { Tile* tile = Cast_Object( Tile*, m_tileGrid->GetIndexedElement(i) ); Verify(!tile->m_ground); tile->m_ground = ElementRenderer::Element::Create(&shape_stream, version); Check_Object(tile->m_ground); #ifdef LAB_ONLY if(saveMapBspDifference==true) { DynamicArrayOf lotsOfPoints; tile->m_ground->GetCoordData(&lotsOfPoints); Scalar row_offset, column_offset, row_cell_size, column_cell_size; m_tileGrid->GetDimensions(&row_offset, &column_offset, &row_cell_size, &column_cell_size); int x_z_miss = 0; for(int j=0;jm_BSP->TestLine(&bsp_query, 0.0f, line.m_length); if(hit) { Scalar diff = lotsOfPoints[j].y - (point.y-line.m_length); if(diff>Stuff::SMALL) { int x = (int)(fmod(lotsOfPoints[j].x - column_offset, 1280.0)/5.f); int z = (int)(fmod(lotsOfPoints[j].z - row_offset, 1280.0)/5.f); if(x>=0&&x<256&&z>=0&&z<256) { raw_power[3*(z*256 + x)] = Truncate_Float_To_Byte(diff*100.f > 255.f ? 0xff : diff*100.f); } else { x_z_miss++; } } else if(diff<-Stuff::SMALL) { int x = (int)(fmod(lotsOfPoints[j].x - column_offset, 1280.0)/5.f); int z = (int)(fmod(lotsOfPoints[j].z - row_offset, 1280.0)/5.f); if(x>=0&&x<256&&z>=0&&z<256) { raw_power[3*(z*256 + x)+2] = Truncate_Float_To_Byte(diff*100.f < -255.f ? 0xff : -diff*100.f); } else { x_z_miss++; } } } else { int x = (int)(fmod(lotsOfPoints[j].x - column_offset, 1280.0)/5.f); int z = (int)(fmod(lotsOfPoints[j].z - row_offset, 1280.0)/5.f); if(x>=0&&x<256&&z>=0&&z<256) { raw_power[3*(z*256 + x)+1] = 0xff; } } } } #endif tile->AttachChild(tile->m_ground); } #ifdef LAB_ONLY if(saveMapBspDifference==true) { gos_WriteFile(fd, raw_power, 256*256*3); gos_CloseFile(fd); delete [] raw_power; } #endif m_tileGrid->Sync(); if (Compost::TerrainTextureLogistic::Instance) { Compost::TerrainTextureLogistic::Instance->AttachZone( m_tileGrid, static_cast(m_row*e_TilesPerZone), static_cast(m_column*e_TilesPerZone) ); } // //------------------------------------------------ // Now, make the non-rendered entities interesting //------------------------------------------------ // Check_Object(RendererManager::Instance); ChainIteratorOf nonrenders(&m_simulated); Entity *entity; Entity::BecomeInterestingMessage message(ReplicatorID::Null, true); while ((entity = nonrenders.ReadAndNext()) != NULL) { Check_Object(entity); AbstractEvent *event = entity->m_pendingInterestMessage.GetCurrent(); if (event) { Check_Object(event); delete event; } Verify(!m_dormant.IsPlugMember(entity)); Verify(!m_rendered.IsPlugMember(entity)); Verify(m_simulated.IsPlugMember(entity)); message.replicatorID = entity->GetReplicatorID(); entity->m_pendingInterestMessage.Add(GeneralEventQueue::Instance->Post(entity, &message)); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Zone::DisableExecution() { Check_Object(this); Check_Object(Map::GetInstance()); Verify(GetInterestLevel() != Entity::DormantInterestLevel); // //------------------------------------------------ // Set the zone status and add it to the Map::Instance chain //------------------------------------------------ // SetInterestLevel(Entity::DormantInterestLevel); Map::GetInstance()->m_executingZones.RemovePlug(this); STOP(("Not implemented")); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Zone::DeactivateZone() { Check_Object(this); Check_Object(Map::GetInstance()); Verify(GetInterestLevel() != Entity::DormantInterestLevel); // //----------------------------------------- // Hook up each of the children to the zone //----------------------------------------- // SetInterestLevel(Entity::DormantInterestLevel); STOP(("Not implemented")); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Zone::DisableRendering() { Check_Object(this); Check_Object(Map::GetInstance()); Verify(GetInterestLevel() == Entity::RenderingInterestLevel); // //------------------------------------------------ // Set the zone status and add it to the Map::Instance chain //------------------------------------------------ // SetInterestLevel(Entity::SimulationInterestLevel); Map::GetInstance()->m_renderedZones.RemovePlug(this); // //------------------------------------------------ // Now, make the non-rendered entities interesting //------------------------------------------------ // Check_Object(RendererManager::Instance); ChainIteratorOf renders(&m_rendered); Entity *entity; while ((entity = renders.GetCurrent()) != NULL) { Check_Object(entity); Verify(!entity->m_pendingInterestMessage.GetCurrent()); renders.Remove(); Verify(!m_simulated.IsPlugMember(entity)); Verify(!m_dormant.IsPlugMember(entity)); Verify(!m_rendered.IsPlugMember(entity)); m_simulated.Add(entity); entity->BecomeInteresting(false); } // //------------------ // Delete the ground //------------------ // for (WORD i=0; i<64; ++i) { Tile* tile = Cast_Object( Tile*, m_tileGrid->GetIndexedElement(i) ); Check_Object(tile->m_ground); delete tile->m_ground; tile->m_ground = NULL; } if (Compost::TerrainTextureLogistic::Instance) { Compost::TerrainTextureLogistic::Instance->DetachMeshes( m_row*e_TilesPerZone, m_column*e_TilesPerZone, e_TilesPerZone, e_TilesPerZone ); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Zone::AddExecutor(Entity *entity) { Check_Object(this); Check_Object(entity); Verify(!m_executors.IsPlugMember(entity)); Entity::InterestLevel zone_interest = GetInterestLevel(), entity_interest = entity->GetInterestLevel(); switch ((zone_interest<<2) | entity_interest) { case (Entity::DormantInterestLevel<<2)|Entity::SimulationInterestLevel: case (Entity::DormantInterestLevel<<2)|Entity::DormantInterestLevel: case (Entity::DormantInterestLevel<<2)|Entity::RenderingInterestLevel: case (Entity::SimulationInterestLevel<<2)|Entity::DormantInterestLevel: case (Entity::RenderingInterestLevel<<2)|Entity::DormantInterestLevel: Verify(m_dormant.IsPlugMember(entity)); Verify(!m_simulated.IsPlugMember(entity)); Verify(!m_rendered.IsPlugMember(entity)); break; case (Entity::SimulationInterestLevel<<2)|Entity::SimulationInterestLevel: case (Entity::SimulationInterestLevel<<2)|Entity::RenderingInterestLevel: case (Entity::RenderingInterestLevel<<2)|Entity::SimulationInterestLevel: Verify(!m_dormant.IsPlugMember(entity)); Verify(m_simulated.IsPlugMember(entity)); Verify(!m_rendered.IsPlugMember(entity)); m_executors.Add(entity); break; case (Entity::RenderingInterestLevel<<2)|Entity::RenderingInterestLevel: Verify(!m_dormant.IsPlugMember(entity)); Verify(!m_simulated.IsPlugMember(entity)); Verify(m_rendered.IsPlugMember(entity)); m_executors.Add(entity); break; default: STOP(("Illegal interest level setting")); break; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Zone::RemoveExecutor(Entity *entity) { Check_Object(this); Check_Object(entity); Entity::InterestLevel zone_interest = GetInterestLevel(), entity_interest = entity->GetInterestLevel(); switch ((zone_interest<<2) | entity_interest) { case (Entity::DormantInterestLevel<<2)|Entity::DormantInterestLevel: case (Entity::DormantInterestLevel<<2)|Entity::SimulationInterestLevel: case (Entity::DormantInterestLevel<<2)|Entity::RenderingInterestLevel: case (Entity::SimulationInterestLevel<<2)|Entity::DormantInterestLevel: case (Entity::RenderingInterestLevel<<2)|Entity::DormantInterestLevel: Verify(m_dormant.IsPlugMember(entity)); Verify(!m_rendered.IsPlugMember(entity)); Verify(!m_simulated.IsPlugMember(entity)); Verify(!m_executors.IsPlugMember(entity)); break; case (Entity::SimulationInterestLevel<<2)|Entity::SimulationInterestLevel: case (Entity::SimulationInterestLevel<<2)|Entity::RenderingInterestLevel: case (Entity::RenderingInterestLevel<<2)|Entity::SimulationInterestLevel: Not_Quite_Done: Verify(m_simulated.IsPlugMember(entity)); Verify(!m_dormant.IsPlugMember(entity)); Verify(!m_rendered.IsPlugMember(entity)); Verify(m_executors.IsPlugMember(entity)); m_executors.RemovePlug(entity); break; case (Entity::RenderingInterestLevel<<2)|Entity::RenderingInterestLevel: if (entity->m_pendingInterestMessage.GetCurrent()) goto Not_Quite_Done; Verify(!m_simulated.IsPlugMember(entity)); Verify(!m_dormant.IsPlugMember(entity)); Verify(m_rendered.IsPlugMember(entity)); Verify(m_executors.IsPlugMember(entity)); m_executors.RemovePlug(entity); break; default: STOP(("Illegal interest level setting")); break; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Zone::HookUpCollision(Entity *entity) { Check_Object(this); Check_Object(entity); // //------------------------------------------ // If this entity won't collide, we are done //------------------------------------------ // if (entity->GetCollisionMask() == Entity::NeverCollidesMask) return; // //----------------------------------------------------------------------- // If the entity is a collider, look to see if it is also a collidee. If // not, put it on the line collider list //----------------------------------------------------------------------- // if (entity->IsACollider()) { Verify(!entity->IsTileBound()); Check_Object(CollisionGrid::Instance); CollisionVolume *bounds = entity->GetSolidVolume(); if (!bounds) CollisionGrid::Instance->m_lineColliders.Add(entity); else { CollisionGrid::Instance->m_solidColliders.Add(entity); bounds->m_worldSpaceBounds.Multiply( bounds->m_localSpaceBounds, entity->GetLocalToWorld() ); ExtentBox aabb(bounds->m_worldSpaceBounds); Check_Object(CollisionGrid::Instance); Scalar row_scale = 1.0f/CollisionGrid::Instance->m_rowCellSize; Scalar column_scale = 1.0f/CollisionGrid::Instance->m_columnCellSize; // //------------------------------- // Figure out the grid boundaries //------------------------------- // Scalar min_z = (aabb.minZ - CollisionGrid::Instance->m_rowOffset) * row_scale; entity->minTileRow = (min_z < 0.0f) ? (BYTE)0 : Truncate_Float_To_Byte(min_z); Scalar max_z = (aabb.maxZ - CollisionGrid::Instance->m_rowOffset) * row_scale; entity->maxTileRow = Truncate_Float_To_Byte(max_z); if (entity->maxTileRow >= CollisionGrid::Instance->m_rowCellCount) entity->maxTileRow = static_cast(CollisionGrid::Instance->m_rowCellCount - 1); Scalar min_x = (aabb.minX - CollisionGrid::Instance->m_columnOffset) * column_scale; entity->minTileColumn = (min_x < 0.0f) ? (BYTE)0 : Truncate_Float_To_Byte(min_x); Scalar max_x = (aabb.maxX - CollisionGrid::Instance->m_columnOffset) * column_scale; entity->maxTileColumn = Truncate_Float_To_Byte(max_x); if (entity->maxTileColumn >= CollisionGrid::Instance->m_columnCellCount) entity->maxTileColumn = static_cast(CollisionGrid::Instance->m_columnCellCount - 1); // //--------------------------------------------------------------------- // Attach the entity to each tile that overlaps its extents. If this // is the first time that tile is being used this frame, attach it to // the colliding tile list //--------------------------------------------------------------------- // Verify( entity->minTileColumn <= entity->maxTileColumn && entity->maxTileColumn < CollisionGrid::Instance->m_columnCellCount ); Verify( entity->minTileRow <= entity->maxTileRow && entity->maxTileRow < CollisionGrid::Instance->m_rowCellCount ); for (BYTE z=entity->minTileRow; z<=entity->maxTileRow; ++z) { for (BYTE x=entity->minTileColumn; x<=entity->maxTileColumn; ++x) { Tile *tile = CollisionGrid::Instance->GetTile(z, x); Check_Object(tile); Verify(tile->m_row == z && tile->m_column == x); ChainIteratorOf temp(&tile->m_colliders); if (!temp.GetCurrent()) CollisionGrid::Instance->m_collidingTiles.Add(tile); Verify(!tile->m_colliders.IsPlugMember(entity)); Verify(!tile->m_collidees.IsPlugMember(entity)); tile->m_colliders.Add(entity); } } } return; } // //---------------------------------------------------------------- // If it is not a collider, but is a collidee, it then must have a // collision volume //---------------------------------------------------------------- // CollisionVolume *bounds = entity->GetHierarchicalVolume(); if (!bounds) bounds = entity->GetSolidVolume(); Check_Object(bounds); // //--------------------------------------------------------------------- // If the collidee is tile bound, it will only collide in the specified // tile //--------------------------------------------------------------------- // if (entity->IsTileBound()) { ElementRenderer::Element *element = entity->GetElement(); Check_Object(element); Tile *tile = Cast_Object(Tile*, element->GetParentElement()); Verify(!tile->m_collidees.IsPlugMember(entity)); Verify(!tile->m_colliders.IsPlugMember(entity)); tile->m_collidees.Add(entity); tile->AddEntityToDamagableList(entity); Verify(tile->m_row < 256 && tile->m_column < 256); entity->minTileRow = static_cast(tile->m_row); entity->maxTileRow = static_cast(tile->m_row); entity->minTileColumn = static_cast(tile->m_column); entity->maxTileColumn = static_cast(tile->m_column); } // //--------------------------------------------- // Otherwise, attach it to any tile it overlaps //--------------------------------------------- // else { bounds->m_worldSpaceBounds.Multiply(bounds->m_localSpaceBounds, entity->GetLocalToWorld()); ExtentBox aabb(bounds->m_worldSpaceBounds); Check_Object(CollisionGrid::Instance); Scalar row_scale = 1.0f/CollisionGrid::Instance->m_rowCellSize; Scalar column_scale = 1.0f/CollisionGrid::Instance->m_columnCellSize; // //------------------------------- // Figure out the grid boundaries //------------------------------- // Scalar min_z = (aabb.minZ - CollisionGrid::Instance->m_rowOffset) * row_scale; entity->minTileRow = (min_z < 0.0f) ? (BYTE)0 : Truncate_Float_To_Byte(min_z); Scalar max_z = (aabb.maxZ - CollisionGrid::Instance->m_rowOffset) * row_scale; entity->maxTileRow = Truncate_Float_To_Byte(max_z); if (entity->maxTileRow >= CollisionGrid::Instance->m_rowCellCount) entity->maxTileRow = static_cast(CollisionGrid::Instance->m_rowCellCount - 1); Scalar min_x = (aabb.minX - CollisionGrid::Instance->m_columnOffset) * column_scale; entity->minTileColumn = (min_x < 0.0f) ? (BYTE)0 : Truncate_Float_To_Byte(min_x); Scalar max_x = (aabb.maxX - CollisionGrid::Instance->m_columnOffset) * column_scale; entity->maxTileColumn = Truncate_Float_To_Byte(max_x); if (entity->maxTileColumn >= CollisionGrid::Instance->m_columnCellCount) entity->maxTileColumn = static_cast(CollisionGrid::Instance->m_columnCellCount - 1); // //--------------------------------------------------------------------- // Attach the entity to each tile that overlaps its extents. If this // is the first time that tile is being used this frame, attach it to // the colliding tile list //--------------------------------------------------------------------- // Verify( entity->minTileColumn <= entity->maxTileColumn && entity->maxTileColumn < CollisionGrid::Instance->m_columnCellCount ); Verify( entity->minTileRow <= entity->maxTileRow && entity->maxTileRow < CollisionGrid::Instance->m_rowCellCount ); for (BYTE z=entity->minTileRow; z<=entity->maxTileRow; ++z) { for (BYTE x=entity->minTileColumn; x<=entity->maxTileColumn; ++x) { Tile *tile = CollisionGrid::Instance->GetTile(z, x); Check_Object(tile); Verify(!tile->m_colliders.IsPlugMember(entity)); Verify(!tile->m_collidees.IsPlugMember(entity)); tile->m_collidees.Add(entity); tile->AddEntityToDamagableList(entity); } } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Zone::UnhookCollision(Entity *entity) { Check_Object(this); Check_Object(entity); // //----------------------------------------------------------------------- // If the entity is a collider, look to see if it is also a collidee. If // not, put it on the line collider list //----------------------------------------------------------------------- // if (entity->IsACollider()) { Verify(!entity->IsTileBound()); CollisionVolume *bounds = entity->GetSolidVolume(); if (!bounds) { Check_Object(CollisionGrid::Instance); CollisionGrid::Instance->m_lineColliders.RemovePlug(entity); } else { Verify(!CollisionGrid::Instance->m_lineColliders.IsPlugMember(entity)); Check_Object(bounds); CollisionGrid::Instance->m_solidColliders.RemovePlug(entity); for (BYTE z=entity->minTileRow; z<=entity->maxTileRow; ++z) { for (BYTE x=entity->minTileColumn; x<=entity->maxTileColumn; ++x) { Tile *tile = CollisionGrid::Instance->GetTile(z, x); if (tile) { Check_Object(tile); Verify(!tile->m_collidees.IsPlugMember(entity)); // Verify(tile->m_colliders.IsPlugMember(entity)); tile->m_colliders.RemovePlug(entity); } } } } } // //---------------------------------------------------------------- // If it is not a collider, but is a collidee, it then must have a // collision volume //---------------------------------------------------------------- // else if (entity->GetCollisionMask() != Entity::NeverCollidesMask) { Verify(!CollisionGrid::Instance->m_lineColliders.IsPlugMember(entity)); // //--------------------------------------------------------------------- // If the collidee is tile bound, it will only collide in the specified // tile //--------------------------------------------------------------------- // if (entity->IsTileBound()) { ElementRenderer::Element *element = entity->GetElement(); Check_Object(element); Tile *tile = Cast_Object(Tile*, element->GetParentElement()); Verify(tile->m_collidees.IsPlugMember(entity)); Verify(!tile->m_colliders.IsPlugMember(entity)); tile->m_collidees.RemovePlug(entity); } // //--------------------------------------------- // Otherwise, attach it to any tile it overlaps //--------------------------------------------- // else { // //--------------------------------------------------------------------- // Attach the entity to each tile that overlaps its extents. If this // is the first time that tile is being used this frame, attach it to // the colliding tile list //--------------------------------------------------------------------- // Verify( entity->minTileColumn <= entity->maxTileColumn && entity->maxTileColumn < CollisionGrid::Instance->m_columnCellCount ); Verify( entity->minTileRow <= entity->maxTileRow && entity->maxTileRow < CollisionGrid::Instance->m_rowCellCount ); for (BYTE z=entity->minTileRow; z<=entity->maxTileRow; ++z) { for (BYTE x=entity->minTileColumn; x<=entity->maxTileColumn; ++x) { Tile *tile = CollisionGrid::Instance->GetTile(z, x); if (tile) { Check_Object(tile); Verify(tile->m_collidees.IsPlugMember(entity)); Verify(!tile->m_colliders.IsPlugMember(entity)); tile->m_collidees.RemovePlug(entity); } #if defined(LAB_ONLY) && 0 // doesn't really work yet.... ( else PAUSE(("%s was placed across zone boundaries!", (const char*)entity->instanceName)); #endif } } } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Zone::PreCollisionExecute(Time till) { Check_Object(this); Verify(GetInterestLevel() != Entity::DormantInterestLevel); PRECOLLISION_LOGIC("Zone"); // //----------------- // Execute entities //----------------- // Check_Object(Map::GetInstance()); ChainIteratorOf entities(&m_executors); Entity *entity; while ((entity = entities.ReadAndNext()) != NULL) { Check_Object(entity); Verify(entity->GetInterestLevel() != Entity::DormantInterestLevel); if (entity->GetTimeSlice(till) > 0.0f) { Set_Statistic(Executed_Zone_Entity_Count, Executed_Zone_Entity_Count+1); int hash = entity->GetExecutionSlot(); entity->nextPreExecution = Map::GetInstance()->m_executionSlots[hash]; Map::GetInstance()->m_executionSlots[hash] = entity; } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Zone::SyncMatrices(bool update_matrix) { Check_Object(this); Verify(GetInterestLevel() != Entity::DormantInterestLevel); SYNC_LOGIC("Zone"); // //---------------------------- // Sync the executing entities //---------------------------- // ChainIteratorOf entities(&m_executors); Entity *entity; while ((entity = entities.ReadAndNext()) != NULL) { Check_Object(entity); entity->SyncMatrices(update_matrix); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // BYTE Zone::GetMaterial(Point3D &point) { Check_Object(this); // //------------------------------------------------------- // If there is no material array, return the default case //------------------------------------------------------- // if (!m_materialArray) return 0; // //------------------------------------------------------ // Adjust the point for zero,zero being in the SE corner //------------------------------------------------------ // Scalar scale = 1.0f / c_ZoneSize; Scalar local_x = point.x - CollisionGrid::Instance->m_columnOffset; Scalar local_z = point.z - CollisionGrid::Instance->m_rowOffset; local_x *= scale; local_z *= scale; local_x -= m_column; local_z -= m_row; // //------------------------------------ // Figure out what cell we would be in //------------------------------------ // int x = 256 - static_cast(floor(256.0*local_x)); Clamp(x, 0, 255); int z = 256 - static_cast(floor(256.0*local_z)); Clamp(z, 0, 255); int index = (z<<8) + x; Verify(index >= 0 && index < 0x10000); return m_materialArray[index]; }