Files
firestorm/Gameleap/code/mw4/Libraries/Adept/Zone.cpp
T
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

1983 lines
60 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 "Zone.hpp"
#include "Map.hpp"
#include "RendererManager.hpp"
#include "ExecutionState.hpp"
#include "Application.hpp"
#include <ElementRenderer\GridElement.hpp>
#include <Compost\TerrainTextureLogistic.hpp>
#include <Compost\TexturePool.hpp>
#include "Tile.hpp"
#include "CollisionVolume.hpp"
#include "CollisionGrid.hpp"
#include "LightManager.hpp"
#include <ElementRenderer\StateChange.hpp>
#include <ElementRenderer\CameraElement.hpp>
#include <ElementRenderer\LightElement.hpp>
#include <MLR\MLRInfiniteLightWithFalloff.hpp>
#include "dropzone.hpp"
#ifdef LAB_ONLY
#include <GameOS\ToolOS.hpp>
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<Factory>(&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<DrawMethod>(&Zone::Draw);
AdoptStateChange(new ElementRenderer::StateChange);
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Zone::~Zone()
{
Check_Object(this);
//
//------------------------------------
// Detach any children that were tiled
//------------------------------------
//
ChainIteratorOf<ElementRenderer::Element*> 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<ElementRenderer::Element*> 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<int>(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<ElementRenderer::Element*> 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<e_TilesPerZone; ++r)
{
for (BYTE c=0; c<e_TilesPerZone; ++c)
{
Tile *tile =
new Tile(
this,
static_cast<BYTE>(m_row*e_TilesPerZone+r),
static_cast<BYTE>(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<Entity*>(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<Entity*>(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<DrawMethod>(&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<ElementRenderer::Element*> 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<BYTE>(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<BYTE>(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; k<base_light; ++k)
{
Check_Object(mixed.m_lights[k]);
object_state.m_lights[k] = mixed.m_lights[k];
}
//
//----------------------
// Now look at each tile
//----------------------
//
for (BYTE z=min_row; z<=max_row; ++z)
{
for (BYTE x=min_col; x<=max_col; ++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();
ElementRenderer::StateChange *tile_state = tile->GetStateChange();
Check_Object(tile_state);
if (max_light==base_light)
{
for (
k=0;
k<MidLevelRenderer::Limits::Max_Number_Of_Lights_Per_Primitive
&& tile_state->m_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;
j<MidLevelRenderer::Limits::Max_Number_Of_Lights_Per_Primitive
&& tile_state->m_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; kk<max_light; ++kk)
{
if (light == object_state.m_lights[kk])
break;
}
if (kk == max_light)
{
object_state.m_lights[max_light++] = light;
if (max_light == MidLevelRenderer::Limits::Max_Number_Of_Lights_Per_Primitive)
goto Draw_Now;
}
}
}
}
}
//
//---------------------------------------------------
// We have figured out the lights, so draw it already
//---------------------------------------------------
//
if (max_light < MidLevelRenderer::Limits::Max_Number_Of_Lights_Per_Primitive)
object_state.m_lights[max_light] = NULL;
Draw_Now:
child->DrawTo(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<BYTE>(m_row<<3); z<=static_cast<BYTE>((m_row<<3)+7); ++z)
{
for (BYTE x=static_cast<BYTE>(m_column<<3); x<=static_cast<BYTE>((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;
k<MidLevelRenderer::Limits::Max_Number_Of_Lights_Per_Primitive
&& tile_state->m_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<Entity*> 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<Point3D> 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;j<lotsOfPoints.GetLength();j++)
{
Stuff::Line3D line;
Point3D point;
point = lotsOfPoints[j];
point.y += 500.0f;
line.m_length = 1000.0f;
line.m_direction = Vector3D::Down;
line.SetOrigin(point);
//
// Prepare query
//
Stuff::Normal3D inormal;
Stuff::Line3D iline;
Stuff::Normal3D normal;
TerrainBSP::CollisionQuery
bsp_query(&line, &normal, this, tile);
bool hit = tile->m_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<BYTE>(m_row*e_TilesPerZone),
static_cast<BYTE>(m_column*e_TilesPerZone)
);
}
//
//------------------------------------------------
// Now, make the non-rendered entities interesting
//------------------------------------------------
//
Check_Object(RendererManager::Instance);
ChainIteratorOf<Entity*> 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<Entity*> 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<BYTE>(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<BYTE>(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<Entity*> 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<BYTE>(tile->m_row);
entity->maxTileRow = static_cast<BYTE>(tile->m_row);
entity->minTileColumn = static_cast<BYTE>(tile->m_column);
entity->maxTileColumn = static_cast<BYTE>(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<BYTE>(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<BYTE>(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<Entity*> 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<Entity*> 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<int>(floor(256.0*local_x));
Clamp(x, 0, 255);
int z = 256 - static_cast<int>(floor(256.0*local_z));
Clamp(z, 0, 255);
int index = (z<<8) + x;
Verify(index >= 0 && index < 0x10000);
return m_materialArray[index];
}