Files
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
2026-06-24 21:28:16 -05:00

1036 lines
29 KiB
C++

//===========================================================================//
// 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 "Map.hpp"
#include "VideoRenderer.hpp"
#include "VideoComponentWeb.hpp"
#include "Application.hpp"
#include "Zone.hpp"
#include <ElementRenderer\GridElement.hpp>
#include "GUITextManager.hpp"
#include <Compost\TerrainTextureLogistic.hpp>
#include <Compost\TexturePool.hpp>
#include "CollisionGrid.hpp"
#include "Tile.hpp"
#include <MLR\MLRCulturShape.hpp>
#include <MLR\MLRFootstep.hpp>
#include <GameOS\ToolOS.hpp>
#include "EntityManager.hpp"
//#define HIERARCHY "your_loginname_here" // used to display attachment info
#define HUNT_ADD_EFFECT_BUG
//#############################################################################
//################################### Map ###############################
//#############################################################################
Map::ClassData*
Map::DefaultData = NULL;
int Map::LoadRadius = 1;
static bool __stdcall CheckFullZoneLoad() {return Map::LoadRadius==4;}
static void __stdcall EnableFullZoneLoad() {Map::LoadRadius = 5-Map::LoadRadius;}
DECLARE_TIMER(static, Attaching_To_Map);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Map::InitializeClass(Stuff::NotationFile *startup_ini)
{
Verify(!DefaultData);
Check_Object(ExecutionStateEngine::DefaultData);
DefaultData =
new ClassData(
MapClassID,
"Adept::Map",
Entity::DefaultData,
0, NULL,
(Entity::Factory)Make,
(Entity::CreateMessage::Factory)CreateMessage::ConstructCreateMessage,
ExecutionStateEngine::DefaultData,
(Entity::GameModel::Factory)GameModel::ConstructGameModel,
NULL,
(Entity::GameModel::ReadAndVerifier)GameModel::ReadAndVerify,
(Entity::GameModel::ModelWrite)GameModel::WriteToText,
(Entity::GameModel::ModelSave)GameModel::SaveGameModel
);
Check_Object(DefaultData);
DIRECT_GAME_MODEL_ATTRIBUTE(
Map__GameModel,
DamageCraterResource,
m_damageCraterResourceID,
ResourceID
);
Initialize_Timer(Attaching_To_Map, "Attaching To Map");
AddDebuggerMenuItem("Libraries\\Adept\\Load All Zones", CheckFullZoneLoad, EnableFullZoneLoad, 0 );
if (startup_ini)
{
Check_Object(startup_ini);
Stuff::Page *page = startup_ini->FindPage("Graphics Options");
if (page)
{
Check_Object(page);
page->GetEntry("LoadRadius", &LoadRadius);
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Map::TerminateClass(Stuff::NotationFile *startup_ini)
{
if (startup_ini)
{
Check_Object(startup_ini);
Stuff::Page *page = startup_ini->SetPage("Graphics Options");
Check_Object(page);
page->SetEntry("LoadRadius", LoadRadius);
}
Check_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
#if 0
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Map*
Map::Make(
const CreateMessage *message,
ReplicatorID *base_id
)
{
Check_Object(message);
//
//-----------------------------------------------------------------------
// We need to open up the game model specified by the message in order to
// find the ResourceID of our grid element
//-----------------------------------------------------------------------
//
Resource model_resource;
GetGameModelResourceFromDataListID(&model_resource, message->dataListID);
GameModel *model = Cast_Pointer(GameModel*, model_resource.GetPointer());
Check_Object(model);
Resource grid_resource(model->m_gridElementResourceID);
Check_Object(&grid_resource);
Verify(grid_resource.DoesResourceExist());
ElementRenderer::GridElement *grid =
Cast_Object(
ElementRenderer::GridElement*,
ElementRenderer::Element::Create(
&grid_resource,
ElementRenderer::ReadERFVersion(&grid_resource)
)
);
Map *new_entity = new Map(DefaultData, message, base_id, grid);
Check_Object(new_entity);
return new_entity;
}
#endif
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Replicator::CreateMessage*
Map::SaveMakeMessage(MemoryStream *stream, ResourceFile *res_file)
{
Check_Object(this);
Check_Object(stream);
//
//---------------------------------------------------------------------
// Make sure there is enough room for the factory request on the stream
//---------------------------------------------------------------------
//
stream->AllocateBytes(sizeof(CreateMessage));
Entity::SaveMakeMessage(stream, res_file);
CreateMessage *message =
Cast_Pointer(CreateMessage*, stream->GetPointer());
message->messageLength = sizeof(*message);
//
//----------------------------------------
// Create the memory stream for the props
//----------------------------------------
//
DynamicMemoryStream prop_stream(sizeof(WORD));
ReplicatorID span = ReplicatorID::Null;
prop_stream << span.localID;
//
//--------------------------------------------------------------------
// Tell each prop to save itself and bump the stream pointer afterword
//--------------------------------------------------------------------
//
ChainIteratorOf<Entity *> iterator(&childEntityChain);
Entity *entity;
while ((entity = iterator.ReadAndNext()) != NULL)
{
Check_Object(entity);
if (entity->GetPropType() == MapPropType)
{
Replicator::CreateMessage *create_message =
entity->SaveMakeMessage(&prop_stream, NULL);
if (create_message)
{
Check_Object(create_message);
prop_stream.AdvancePointer(create_message->messageLength);
span += create_message->replicatorID.localID;
}
}
}
//
//-----------------------------------------
// Only save out the stream if there is one
//-----------------------------------------
//
if (prop_stream.GetBytesUsed() > sizeof(WORD))
{
prop_stream.Rewind();
Verify(span.localID > 0);
prop_stream << span.localID;
Resource prop_resource(NULL);
prop_resource.Save(&prop_stream, NULL);
STOP(("Not updated"));
Check_Object(&prop_resource);
message->m_propStreamResourceID = prop_resource.GetResourceID();
message->replicatorID += span;
}
else
message->m_propStreamResourceID = ResourceID::Null;
return message;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Map::Map(
ClassData *class_data,
const CreateMessage *message,
ReplicatorID *base_id,
ElementRenderer::GridElement *element,
int execution_slots
):
Entity(class_data, message, base_id, element),
m_executingZones(NULL),
m_renderedZones(NULL),
m_renderOrigin(NULL),
m_executionSlots(execution_slots)
{
Check_Pointer(this);
Check_Object(message);
//
//---------------------------------------------------------------------
// We will get our size directly from the .erf file that has the grid
// element in it. In the mean time, set up the structures for one zone
//---------------------------------------------------------------------
//
ElementRenderer::GridElement *grid =
Cast_Object(ElementRenderer::GridElement*, entityElement);
grid->GetSize(&m_rowZoneCount, &m_columnZoneCount);
m_zoneCount = static_cast<WORD>(m_columnZoneCount * m_rowZoneCount);
grid->SetSize(m_zoneCount);
Scalar row_size, column_size;
grid->GetDimensions(
&m_rowZoneOrigin,
&m_columnZoneOrigin,
&row_size,
&column_size
);
Verify(!Small_Enough(row_size));
m_rowZoneScale = 1.0f / row_size;
Verify(!Small_Enough(column_size));
m_columnZoneScale = 1.0f / column_size;
Verify(Close_Enough(m_columnZoneScale, m_rowZoneScale));
//
//--------------------------------------------------
// Set up the game model and set up the list of erfs
//--------------------------------------------------
//
const GameModel *model = GetGameModel();
Check_Object(model);
m_zonesResource.FindID(model->m_zoneArrayResourceID);
Verify(m_zonesResource.DoesResourceExist());
Verify(m_zoneCount*sizeof(Zone::ResourceData) == m_zonesResource.GetSize());
//
//---------------------
// Create the supergrid
//---------------------
//
Verify(!CollisionGrid::Instance);
gos_PushCurrentHeap(s_CollisionHeap);
CollisionGrid::Instance =
new CollisionGrid(
static_cast<BYTE>(m_rowZoneCount*e_TilesPerZone),
static_cast<BYTE>(m_columnZoneCount*e_TilesPerZone),
m_rowZoneOrigin,
m_columnZoneOrigin,
row_size * m_rowZoneCount,
column_size * m_columnZoneCount,
model->m_waterLevel
);
Check_Object(CollisionGrid::Instance);
gos_PopCurrentHeap();
//
//------------------------------------
// Build the Texture logistics manager
//------------------------------------
//
bool manage_textures = model->m_textureDataResourceID != ResourceID::Null;
bool dedicated_server = Application::GetInstance()->m_localMissionParameters->m_runDedicated!=0 ? true : false;
if (manage_textures && Compost::TerrainTextureLogistic::GetResolution()>0 && !dedicated_server)
{
gos_PushCurrentHeap(Compost::Heap);
Compost::TexturePool::Instance = new Compost::TexturePool;
Check_Object(Compost::TexturePool::Instance);
//
//-----------------------------------------------------------
// Set up the texture path until texture data stream is coded
//-----------------------------------------------------------
//
char name[1024];
gos_GetCurrentPath(name, 1024);
Compost::TexturePool::Instance->SetTexturePath("Content\\Textures\\CompostTexture");
Verify(model->m_tcfResourceID!=ResourceID::Null);
Resource tcf_resource(model->m_tcfResourceID);
NotationFile tcf_data(&tcf_resource);
Compost::TexturePool::Instance->LoadIndex(&tcf_data);
Resource texture_spec(model->m_textureDataResourceID);
Verify(texture_spec.DoesResourceExist());
Compost::TerrainTextureLogistic::Instance =
new Compost::TerrainTextureLogistic(
m_columnZoneCount*e_TilesPerZone,
m_rowZoneCount*e_TilesPerZone,
c_TileSize,
c_TileSize,
&texture_spec
);
Check_Object(Compost::TerrainTextureLogistic::Instance);
Compost::TerrainTextureLogistic::Instance->SetOffset(
m_rowZoneOrigin,
m_columnZoneOrigin
);
gos_PopCurrentHeap();
}
//
//----------------------------
// Allocate the array of Zones
//----------------------------
//
Verify(m_zoneCount > 0 && m_zoneCount == m_columnZoneCount * m_rowZoneCount);
m_zones = new Zone[m_zoneCount];
Check_Pointer(m_zones);
Zone *zone=m_zones;
WORD index=0;
for (BYTE row=0; row<m_rowZoneCount; ++row)
{
for (BYTE column=0; column<m_columnZoneCount; ++column, ++index, ++zone)
{
//
//----------------------------------------
// Load the erf for the zone and attach it
//----------------------------------------
//
Check_Object(zone);
zone->m_row = row;
zone->m_column = column;
zone->LockBounds();
zone->CreateTileGrid(
m_rowZoneOrigin + row*c_ZoneSize,
m_columnZoneOrigin + column*c_ZoneSize
);
grid->AttachIndexedChild(row, column, zone);
}
}
//
//-----------------
// Create the props
//-----------------
//
propListResourceID = ResourceID::Null;
if (message->m_propStreamResourceID != ResourceID::Null)
{
Resource stream(message->m_propStreamResourceID);
Verify(stream.DoesResourceExist());
stream.AdvancePointer(replicatorID.localID);
while (stream.GetBytesRemaining() > 0)
{
Entity::CreateMessage *message =
Cast_Pointer(Entity::CreateMessage*, stream.GetPointer());
Check_Object(message);
Entity *entity = CreateEntity(&stream, base_id);
Check_Object(entity);
entity->SetPropType(MapPropType);
AddChild(entity);
stream.AdvancePointer(message->messageLength);
}
propListResourceID = message->m_propStreamResourceID;
}
//
//------------------------
// Build the cultural data
//------------------------
//
bool manage_culturals = model->m_culturalDataResourceID != ResourceID::Null;
if (manage_culturals) // switch to turn off cuturals
{
Resource culturalData_resource(model->m_culturalDataResourceID);
int mlr_version = MidLevelRenderer::ReadMLRVersion(&culturalData_resource);
OBB obb;
culturalData_resource >> obb;
if(mlr_version>13)
{
RegisteredClass::ClassID class_id;
culturalData_resource >> class_id;
}
MidLevelRenderer::MLRCulturShape::culturalRevolution = MidLevelRenderer::MLRShape::Make(&culturalData_resource, mlr_version);
}
else
{
if(MidLevelRenderer::MLRCulturShape::culturalRevolution!=NULL)
{
MidLevelRenderer::MLRCulturShape::culturalRevolution->DetachReference();
MidLevelRenderer::MLRCulturShape::culturalRevolution = NULL;
}
}
//
//------------------------
//Set up the footstep pool
//------------------------
//
Verify(!MidLevelRenderer::MLRFootStep::Instance);
MidLevelRenderer::MLRFootStep::Instance = new MidLevelRenderer::MLRFootStep(64);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Map::~Map()
{
Check_Object(this);
GlobalPointers::ClearPointer(MapGlobalPointerIndex);
//
//----------------------------------------------
// Tell all the children to become uninteresting
//----------------------------------------------
//
ChainIteratorOf<Entity*> children(&childEntityChain);
Entity *entity;
while ((entity = children.ReadAndNext()) != NULL)
{
Check_Object(entity);
entity->BecomeUninteresting();
}
//
//---------------------------------------------
// Turn off the terrain compositing controllers
//---------------------------------------------
//
if (Compost::TerrainTextureLogistic::Instance)
{
Check_Object(Compost::TerrainTextureLogistic::Instance);
delete Compost::TerrainTextureLogistic::Instance;
Compost::TerrainTextureLogistic::Instance = NULL;
}
if (Compost::TexturePool::Instance)
{
Check_Object(Compost::TexturePool::Instance);
delete Compost::TexturePool::Instance;
Compost::TexturePool::Instance = NULL;
}
//
//-----------------
// Delete our zones
//-----------------
//
Check_Pointer(m_zones);
delete[] m_zones;
//
//-------------------------------------------------------------------
// Delete our collision grid - our parent class will take care of our
// child entities
//-------------------------------------------------------------------
//
Check_Object(CollisionGrid::Instance);
delete CollisionGrid::Instance;
CollisionGrid::Instance = NULL;
//
//----------------------
//Kill the FootStep pool
//----------------------
//
if (MidLevelRenderer::MLRFootStep::Instance)
{
delete MidLevelRenderer::MLRFootStep::Instance;
MidLevelRenderer::MLRFootStep::Instance = NULL;
}
//
//------------------------
//Kill the cultural meshes
//------------------------
//
if(MidLevelRenderer::MLRCulturShape::culturalRevolution!=NULL)
{
MidLevelRenderer::MLRCulturShape::culturalRevolution->DetachReference();
MidLevelRenderer::MLRCulturShape::culturalRevolution = NULL;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Map::AddChild(Entity *entity)
{
Check_Object(this);
Check_Object(entity);
//
//------------------------------------------
// Find the zone that this entity belongs to
//------------------------------------------
//
Start_Timer(Attaching_To_Map);
ElementRenderer::Element *child_element = entity->GetElement();
Check_Object(child_element);
#ifdef HUNT_ADD_EFFECT_BUG
if (entity == NULL)
{
STOP(("ADDING OBJECT FAILED : ENTITY NULL"));
}
if (child_element == NULL)
{
STOP(("ADDING OBJECT FAILED : CHILD ELEMENT NULL"));
}
#endif
Point3D translation(child_element->GetNewLocalToParent());
int index = FindZone(translation);
Verify(static_cast<unsigned>(index) < m_zoneCount);
Zone *zone = &m_zones[index];
Check_Object(zone);
#ifdef HUNT_ADD_EFFECT_BUG
if (zone == NULL)
{
STOP(("ADDING OBJECT FAILED : location : %f %f %f Zone : %d", translation.x, translation.y, translation.z, index));
}
if (static_cast<unsigned>(index) >= m_zoneCount)
{
STOP(("ADDING OBJECT FAILED : location : %f %f %f Zone : %d", translation.x, translation.y, translation.z, index));
}
#endif
//
//-----------------------------
// Hook up the entity hierarchy
//-----------------------------
//
Verify(!entity->parentEntity);
entity->parentEntity = this;
childEntityChain.Add(entity);
entity->NeedMatrixSync();
#if defined(HIERARCHY)
SPEW((0, "Attaching %s(+", entity->GetClassString()));
Spew(0, entity->GetReplicatorID());
SPEW((0, ") to %s(+", GetClassString()));
Spew(0, GetReplicatorID());
SPEW((0, ")"));
#endif
zone->AttachChild(child_element);
Stop_Timer(Attaching_To_Map);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Map::RemoveChild(Entity *entity)
{
Check_Object(this);
Check_Object(entity);
//
//--------------------------------
// Unhook the entity from the zone
//--------------------------------
//
ElementRenderer::Element *element = entity->GetElement();
Check_Object(element);
ElementRenderer::Element *parent_ele=element->GetParentElement();
Check_Object(parent_ele);
Zone *zone;
if(parent_ele->GetClassID() == TileClassID)
{
Verify(parent_ele->IsDerivedFrom(Tile::DefaultData));
zone = Cast_Object(Zone*, parent_ele->GetParentElement()->GetParentElement());
}
else
{
zone = Cast_Object(Zone*, parent_ele);
}
zone->DetachChild(element);
//
//---------------------------------
// Unook the entity from the parent
//---------------------------------
//
entity->parentEntity = NULL;
childEntityChain.Remove(entity);
entity->NeedMatrixSync();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Map::ChildPreCollisionChanged(Entity *entity)
{
Check_Object(this);
Check_Object(entity);
//
//-----------------------------
// Find the zone for the entity
//-----------------------------
//
ElementRenderer::Element *element = entity->GetElement();
Check_Object(element);
ElementRenderer::Element *parent_ele=element->GetParentElement();
Check_Object(parent_ele);
Zone *zone;
if(parent_ele->GetClassID() == TileClassID)
{
Verify(parent_ele->IsDerivedFrom(Tile::DefaultData));
zone = Cast_Object(Zone*, parent_ele->GetParentElement()->GetParentElement());
}
else
{
zone = Cast_Object(Zone*, parent_ele);
}
//
//-------------------
// Turn the entity on
//-------------------
//
if((entity->executionState->GetOldState() == ExecutionStateEngine::NeverExecuteState)
&&(entity->executionState->GetState() != ExecutionStateEngine::NeverExecuteState))
{
zone->AddExecutor(entity);
}
//
//--------------------
// Turn off the entity
//--------------------
//
else if((entity->executionState->GetOldState() != ExecutionStateEngine::NeverExecuteState)
&&(entity->executionState->GetState() == ExecutionStateEngine::NeverExecuteState))
{
zone->RemoveExecutor(entity);
}
}
#if defined(NDEBUG)
#pragma optimize("a",off)
#endif
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Map::UpdateZone(Entity *entity)
{
Check_Object(this);
Check_Object(entity);
Verify(entity->parentEntity == this);
Verify(this == Map::GetInstance());
Verify(!entity->IsTileBound());
//
//------------------------------------------
// Find out where the child wants to move to
//------------------------------------------
//
ElementRenderer::Element *child_element = entity->GetElement();
Check_Object(child_element);
Zone *old_zone = Cast_Object(Zone*, child_element->GetParentElement());
Point3D translation(entity->GetLocalToWorld());
//
//------------------
// Find the new zone
//------------------
//
Scalar column = translation.x - m_columnZoneOrigin;
Scalar row = translation.z - m_rowZoneOrigin;
column *= m_columnZoneScale;
row *= m_rowZoneScale;
Verify(column>=0.0f && column<m_columnZoneCount && row>=0.0f && row<m_rowZoneCount);
//
//--------------------------------------------------------------------------
// See if the child is moving to a new zone. If so, change the zones of the
// child. We are manipulating the entity's element flags directly rather
// than calling a sync because we are only changing parentage, and both are
// rooted at the origin.
//--------------------------------------------------------------------------
//
int index = Truncate_Float_To_Byte(row)*m_columnZoneCount + Truncate_Float_To_Byte(column);
Verify(static_cast<unsigned>(index) < m_zoneCount);
Zone *new_zone = &m_zones[index];
Check_Object(new_zone);
if (old_zone != new_zone || entity->GetCollisionMask() == EditorIsMovingFlag)
{
AbstractEvent *event = entity->m_pendingInterestMessage.GetCurrent();
if (event)
event->Process();
InterestLevel level = entity->GetInterestLevel();
unsigned element_state = child_element->GetElementState();
old_zone->DetachChild(child_element);
new_zone->AttachChild(child_element);
if (level == entity->GetInterestLevel())
child_element->SetElementState(element_state);
}
//
//------------------------------
// Clear the entity's dirty flag
//------------------------------
//
entity->replicatorFlags &= ~DirtyZoneFlag;
}
#if defined(NDEBUG)
#pragma optimize("a",on)
#endif
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
Map::FindZone(const Stuff::Point3D &where)
{
Check_Object(this);
Verify(
Close_Enough(
GetElement()->GetLocalToWorld(),
LinearMatrix4D::Identity
)
);
Verify(
Close_Enough(
GetElement()->GetNewLocalToParent(),
LinearMatrix4D::Identity
)
);
unsigned index = GetElement()->FindElementIndex(where.z, where.x);
if (index < GetElement()->GetActiveCount())
return index;
return -1;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Map::GetMapExtents(
Stuff::Scalar *min_z,
Stuff::Scalar *max_z,
Stuff::Scalar *min_x,
Stuff::Scalar *max_x
)
{
Check_Object(this);
Check_Pointer(min_z);
Check_Pointer(max_z);
Check_Pointer(min_x);
Check_Pointer(max_x);
*min_x = m_columnZoneOrigin;
*max_x = m_columnZoneOrigin + m_columnZoneCount/m_columnZoneScale;
*min_z = m_rowZoneOrigin;
*max_z = m_rowZoneOrigin + m_rowZoneCount/m_rowZoneScale;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Map::PreCollisionExecute(Time till)
{
Check_Object(this);
PRECOLLISION_LOGIC("Map");
//
//---------------------------------
// Verify that this always executes
//---------------------------------
//
Check_Object(executionState);
Verify(
executionState->GetState() !=
ExecutionStateEngine::NeverExecuteState
);
Entity::PreCollisionExecute(till);
//
//-------------------------------
// Clear out the execution hashes
//-------------------------------
//
int i;
for (i=0; i<m_executionSlots.GetLength(); ++i)
m_executionSlots[i] = NULL;
//
//--------------
// Execute zones
//--------------
//
ChainIteratorOf<Zone*> zones(&m_executingZones);
Zone *zone;
while ((zone = zones.ReadAndNext()) != NULL)
{
Check_Object(zone);
Verify(zone->GetInterestLevel() != DormantInterestLevel);
zone->PreCollisionExecute(till);
}
//
//-------------------------
// Now execute the entities
//-------------------------
//
for (i=0; i<m_executionSlots.GetLength(); ++i)
{
Entity *entity = m_executionSlots[i];
while (entity)
{
Check_Object(entity);
entity->PreCollisionExecute(till);
Verify(!entity->IsUsingPostCollision() || EntityManager::GetInstance()->IsInPostCollisionExecution(entity));
entity = entity->nextPreExecution;
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Map::SyncMatrices(bool update_matrix)
{
Check_Object(this);
SYNC_LOGIC("Map");
#if defined(HIERARCHY)
if (update_matrix)
{
SPEW((HIERARCHY, "Map::SyncMatrices %s(+", GetClassString()));
Spew(HIERARCHY, GetReplicatorID());
SPEW((HIERARCHY, ")"));
}
#endif
//
//-----------------------------------------
// If we have a dirty locator, sync with it
//-----------------------------------------
//
if (IsMatrixDirty())
{
if (update_matrix)
{
Check_Object(entityElement);
entityElement->Sync();
update_matrix = false;
}
ClearNeedMatrixSync();
}
//
//-------------------------
// Sync the executing zones
//-------------------------
//
ChainIteratorOf<Zone*> zones(&m_executingZones);
Zone *zone;
while ((zone = zones.ReadAndNext()) != NULL)
{
Check_Object(zone);
Verify(zone->GetInterestLevel() != DormantInterestLevel);
zone->SyncMatrices(update_matrix);
}
#if defined(HIERARCHY)
if (update_matrix)
SPEW((0, ""));
#endif
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Map::UpdateRenderOrigin(const Stuff::Point3D &location)
{
Check_Object(this);
Check_Object(&location);
//
//------------------------------------------------------------------
// Find the zone that this entity belongs to, and if the zone hasn't
// changed, we are done
//------------------------------------------------------------------
//
int index = FindZone(location);
Verify(static_cast<unsigned>(index) < m_zoneCount);
Zone *new_zone = &m_zones[index];
Check_Object(new_zone);
if (new_zone == m_renderOrigin)
return;
//
//--------------------------------------------
// Find the bounds on where the render will be
//--------------------------------------------
//
unsigned row = index / m_columnZoneCount;
unsigned column = index - row*m_columnZoneCount;
unsigned min_column = (column>=LoadRadius) ? column-LoadRadius : 0;
unsigned min_row = (row>=LoadRadius) ? row-LoadRadius : 0;
unsigned max_column = (column+LoadRadius >= m_columnZoneCount) ? m_columnZoneCount : column+LoadRadius+1;
unsigned max_row = (row+LoadRadius >= m_rowZoneCount) ? m_rowZoneCount : row+LoadRadius+1;
//
//----------------------------------------------------------
// Make any active zone not in the active zone uninteresting
//----------------------------------------------------------
//
ChainIteratorOf<Zone*> zones(&m_renderedZones);
Zone *zone;
while ((zone = zones.ReadAndNext()) != NULL)
{
Check_Object(zone);
if (
zone->m_row < min_row || zone->m_row >= max_row
|| zone->m_column < min_column || zone->m_column >= max_column
)
zone->DisableRendering();
}
//
//-------------------------------------
// Tell each zone to become interesting
//-------------------------------------
//
m_renderOrigin = new_zone;
for (row=min_row; row<max_row; ++row)
{
zone = &m_zones[row*m_columnZoneCount + min_column];
for (column=min_column; column<max_column; ++column,++zone)
{
if (zone->GetInterestLevel() != RenderingInterestLevel)
zone->EnableRendering();
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Map::ActivateZones()
{
Check_Object(this);
//
//-------------------------------------
// Tell each zone to become interesting
//-------------------------------------
//
for (int row=0; row<m_rowZoneCount; ++row)
{
for (int column=0; column<m_columnZoneCount; ++column)
{
m_zones[row*m_columnZoneCount + column].ActivateZone();
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Zone::ResourceData*
Map::GetZoneResourceData(unsigned index)
{
Check_Object(this);
return &Cast_Pointer(Zone::ResourceData*, m_zonesResource.GetPointer())[index];
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Map::WorldToZoneCoords(Stuff::Scalar& x, Stuff::Scalar& y) const
{
x = (x - m_columnZoneOrigin) * m_columnZoneScale;
y = (y - m_rowZoneOrigin) * m_rowZoneScale; // jcem - m_columnZoneScale->m_rowZoneScale
}