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.
1983 lines
60 KiB
C++
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];
|
|
}
|