1290 lines
31 KiB
C++
1290 lines
31 KiB
C++
//-----------------------------------------------------------------------------
|
|
// Torque Game Engine
|
|
// Copyright (C) GarageGames.com, Inc.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "map2dif plus/entityTypes.h"
|
|
#include "core/tokenizer.h"
|
|
#include "map2dif plus/csgBrush.h"
|
|
#include "interior/interior.h"
|
|
#include "map2dif plus/morianUtil.h"
|
|
#include "dgl/gBitmap.h"
|
|
|
|
DoorEntity *gCurrentDoor = NULL;
|
|
U32 gTriggerId = 0;
|
|
|
|
void parseBrushList(Vector<CSGBrush*>& brushes, Tokenizer* pToker, EditGeometry& geom)
|
|
{
|
|
// Ok, this is where it gets interesting. We have to parse in the brushes, and place
|
|
// them in our list before we return to the editGeometry. I'm copying almost all this
|
|
// code from the parseMapFile function in editGeometry.cc
|
|
//
|
|
while (pToker->getToken()[0] == '{') {
|
|
pToker->advanceToken(true);
|
|
|
|
brushes.push_back(gBrushArena.allocateBrush());
|
|
CSGBrush& rBrush = *brushes.last();
|
|
|
|
if (!parseBrush (rBrush, pToker, geom)) return;
|
|
|
|
rBrush.disambiguate();
|
|
pToker->advanceToken(true);
|
|
}
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
WorldSpawnEntity::WorldSpawnEntity()
|
|
{
|
|
mDetailNumber = 0;
|
|
mMinPixels = 250;
|
|
|
|
mGeometryScale = 32.0f;
|
|
mLumelScale = 32.0f;
|
|
|
|
mAmbientColor.set(0,0,0);
|
|
mEmergencyAmbientColor.set(0,0,0);
|
|
|
|
mWadPrefix[0] = '\0';
|
|
}
|
|
|
|
WorldSpawnEntity::~WorldSpawnEntity()
|
|
{
|
|
|
|
}
|
|
|
|
bool WorldSpawnEntity::parseEntityDescription(InteriorMapResource::Entity* ent)
|
|
{
|
|
// This gets handled in convert.cc in getWorldSpawn() b/c WorldSpawn
|
|
// sets up some important information
|
|
return true;
|
|
}
|
|
|
|
BrushType WorldSpawnEntity::getBrushType()
|
|
{
|
|
return StructuralBrush;
|
|
}
|
|
|
|
const char* WorldSpawnEntity::getClassName()
|
|
{
|
|
return "worldspawn";
|
|
}
|
|
|
|
bool WorldSpawnEntity::isPointClass() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const char* WorldSpawnEntity::getName() const
|
|
{
|
|
static char bogoChar = '\0';
|
|
return &bogoChar;
|
|
}
|
|
const Point3D& WorldSpawnEntity::getOrigin() const
|
|
{
|
|
static Point3D bogoPoint(0, 0, 0);
|
|
return bogoPoint;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
DetailEntity::DetailEntity()
|
|
{
|
|
|
|
}
|
|
|
|
DetailEntity::~DetailEntity()
|
|
{
|
|
|
|
}
|
|
|
|
bool DetailEntity::parseEntityDescription(InteriorMapResource::Entity* ent)
|
|
{
|
|
// No properties - parsing is handled elsewhere now
|
|
|
|
return true;
|
|
}
|
|
|
|
BrushType DetailEntity::getBrushType()
|
|
{
|
|
return DetailBrush;
|
|
}
|
|
|
|
const char* DetailEntity::getClassName()
|
|
{
|
|
return "detail";
|
|
}
|
|
|
|
bool DetailEntity::isPointClass() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const char* DetailEntity::getName() const
|
|
{
|
|
static char bogoChar = '\0';
|
|
return &bogoChar;
|
|
}
|
|
const Point3D& DetailEntity::getOrigin() const
|
|
{
|
|
static Point3D bogoPoint(0, 0, 0);
|
|
return bogoPoint;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
CollisionEntity::CollisionEntity()
|
|
{
|
|
|
|
}
|
|
|
|
CollisionEntity::~CollisionEntity()
|
|
{
|
|
|
|
}
|
|
|
|
bool CollisionEntity::parseEntityDescription(InteriorMapResource::Entity* ent)
|
|
{
|
|
// No properties - parsing is handled elsewhere now
|
|
|
|
return true;
|
|
}
|
|
|
|
BrushType CollisionEntity::getBrushType()
|
|
{
|
|
return CollisionBrush;
|
|
}
|
|
|
|
const char* CollisionEntity::getClassName()
|
|
{
|
|
return "collision";
|
|
}
|
|
|
|
bool CollisionEntity::isPointClass() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const char* CollisionEntity::getName() const
|
|
{
|
|
static char bogoChar = '\0';
|
|
return &bogoChar;
|
|
}
|
|
const Point3D& CollisionEntity::getOrigin() const
|
|
{
|
|
static Point3D bogoPoint(0, 0, 0);
|
|
return bogoPoint;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
PortalEntity::PortalEntity()
|
|
{
|
|
passAmbientLight = false;
|
|
}
|
|
|
|
PortalEntity::~PortalEntity()
|
|
{
|
|
|
|
}
|
|
|
|
bool PortalEntity::parseEntityDescription(InteriorMapResource::Entity* ent)
|
|
{
|
|
// Get the values of this entity
|
|
char* value;
|
|
|
|
value = ent->getValue("ambient_light");
|
|
if (value)
|
|
passAmbientLight = dAtoi(value) == 0 ? false : true;
|
|
|
|
return true;
|
|
}
|
|
|
|
BrushType PortalEntity::getBrushType()
|
|
{
|
|
return PortalBrush;
|
|
}
|
|
|
|
const char* PortalEntity::getClassName()
|
|
{
|
|
return "portal";
|
|
}
|
|
|
|
bool PortalEntity::isPointClass() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const char* PortalEntity::getName() const
|
|
{
|
|
static char bogoChar = '\0';
|
|
return &bogoChar;
|
|
}
|
|
const Point3D& PortalEntity::getOrigin() const
|
|
{
|
|
static Point3D bogoPoint(0, 0, 0);
|
|
return bogoPoint;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
TargetEntity::TargetEntity()
|
|
{
|
|
mTargetName[0] = '\0';
|
|
mOrigin.set(0,0,0);
|
|
}
|
|
|
|
TargetEntity::~TargetEntity()
|
|
{
|
|
//
|
|
}
|
|
|
|
bool TargetEntity::parseEntityDescription(InteriorMapResource::Entity* ent)
|
|
{
|
|
char* value;
|
|
|
|
value = ent->getValue("origin");
|
|
if (value)
|
|
dSscanf(value, "%lf %lf %lf", &mOrigin.x, &mOrigin.y, &mOrigin.z);
|
|
|
|
value = ent->getValue("name");
|
|
if (value)
|
|
dStrcpy(mTargetName, value);
|
|
|
|
return true;
|
|
}
|
|
|
|
BrushType TargetEntity::getBrushType()
|
|
{
|
|
AssertISV(false, "brushes cannot be associated with targets!");
|
|
return DetailBrush;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//-------------------------------------- LIGHT TYPES...
|
|
//
|
|
BaseLightEmitterEntity::BaseLightEmitterEntity()
|
|
{
|
|
mTargetLight[0] = '\0';
|
|
mStateIndex = 0;
|
|
mOrigin.set(0,0,0);
|
|
}
|
|
|
|
BrushType BaseLightEmitterEntity::getBrushType()
|
|
{
|
|
AssertISV(false, "brushes cannot be associated with lights!");
|
|
return DetailBrush;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Light Emitters
|
|
//------------------------------------------------------------------------------
|
|
|
|
PointEmitterEntity::PointEmitterEntity()
|
|
{
|
|
mFalloffType = BaseLightEmitterEntity::Linear;
|
|
mFalloff1 = 10;
|
|
mFalloff2 = 100;
|
|
mFalloff3 = 0;
|
|
}
|
|
|
|
bool PointEmitterEntity::parseEntityDescription(InteriorMapResource::Entity* ent)
|
|
{
|
|
char* value;
|
|
|
|
value = ent->getValue("origin");
|
|
if (value)
|
|
dSscanf(value, "%lf %lf %lf", &mOrigin.x, &mOrigin.y, &mOrigin.z);
|
|
|
|
value = ent->getValue("target");
|
|
if (value)
|
|
dStrcpy(mTargetLight, value);
|
|
|
|
value = ent->getValue("state_index");
|
|
if (value)
|
|
mStateIndex = dAtoi(value);
|
|
|
|
value = ent->getValue("falloff_type");
|
|
if (value)
|
|
mFalloffType = (dAtoi(value) == 0) ? BaseLightEmitterEntity::Distance : BaseLightEmitterEntity::Linear;
|
|
|
|
value = ent->getValue("falloff1");
|
|
if (value)
|
|
mFalloff1 = dAtoi(value);
|
|
|
|
value = ent->getValue("falloff2");
|
|
if (value)
|
|
mFalloff2 = dAtoi(value);
|
|
|
|
value = ent->getValue("falloff3");
|
|
if (value)
|
|
mFalloff3 = dAtoi(value);
|
|
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
SpotEmitterEntity::SpotEmitterEntity()
|
|
{
|
|
mFalloffType = BaseLightEmitterEntity::Linear;
|
|
mDirection.set(0,0,-1);
|
|
mFalloff1 = 10;
|
|
mFalloff2 = 100;
|
|
mFalloff3 = 0;
|
|
mInnerAngle = 0.2;
|
|
mOuterAngle = 0.4;
|
|
}
|
|
|
|
bool SpotEmitterEntity::parseEntityDescription(InteriorMapResource::Entity* ent)
|
|
{
|
|
char* value;
|
|
|
|
value = ent->getValue("origin");
|
|
if (value)
|
|
dSscanf(value, "%lf %lf %lf", &mOrigin.x, &mOrigin.y, &mOrigin.z);
|
|
|
|
value = ent->getValue("target");
|
|
if (value)
|
|
dStrcpy(mTargetLight, value);
|
|
|
|
value = ent->getValue("state_index");
|
|
if (value)
|
|
mStateIndex = dAtoi(value);
|
|
|
|
value = ent->getValue("falloff_type");
|
|
if (value)
|
|
mFalloffType = (dAtoi(value) == 0) ? BaseLightEmitterEntity::Distance : BaseLightEmitterEntity::Linear;
|
|
|
|
value = ent->getValue("falloff1");
|
|
if (value)
|
|
mFalloff1 = dAtoi(value);
|
|
|
|
value = ent->getValue("falloff2");
|
|
if (value)
|
|
mFalloff2 = dAtoi(value);
|
|
|
|
value = ent->getValue("falloff3");
|
|
if (value)
|
|
mFalloff3 = dAtoi(value);
|
|
|
|
value = ent->getValue("direction");
|
|
if (value)
|
|
dSscanf(value, "%lf %lf %lf", &mDirection.x, &mDirection.y, &mDirection.z);
|
|
|
|
value = ent->getValue("theta");
|
|
if (value)
|
|
mInnerAngle = dAtof(value);
|
|
|
|
value = ent->getValue("phi");
|
|
if (value)
|
|
mOuterAngle = dAtof(value);
|
|
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
BaseLightEntity::BaseLightEntity()
|
|
{
|
|
mFlags = Interior::AnimationAmbient | Interior::AnimationLoop;
|
|
mAlarmStatus = NormalOnly;
|
|
mOrigin.set(0,0,0);
|
|
mLightName[0] = '\0';
|
|
}
|
|
|
|
BrushType BaseLightEntity::getBrushType()
|
|
{
|
|
AssertISV(false, "brushes cannot be associated with lights!");
|
|
return DetailBrush;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Light
|
|
//------------------------------------------------------------------------------
|
|
|
|
LightEntity::LightEntity()
|
|
{
|
|
mNumStates = 0;
|
|
dMemset(mStates, 0, sizeof(mStates));
|
|
}
|
|
|
|
bool LightEntity::parseEntityDescription(InteriorMapResource::Entity* ent)
|
|
{
|
|
char* value;
|
|
|
|
value = ent->getValue("origin");
|
|
if (value)
|
|
dSscanf(value, "%lf %lf %lf", &mOrigin.x, &mOrigin.y, &mOrigin.z);
|
|
|
|
value = ent->getValue("name");
|
|
if (value)
|
|
dStrcpy(mLightName, value);
|
|
|
|
value = ent->getValue("spawnflags");
|
|
if (value)
|
|
mFlags = dAtoi(value) & Interior::AnimationTypeMask;
|
|
|
|
value = ent->getValue("alarm_type");
|
|
if (value)
|
|
mAlarmStatus = (AlarmStatus)dAtoi(value);
|
|
|
|
//value = ent->getValue("state");
|
|
//else if(dStrncmp(pToker->getToken(), "state", 5))
|
|
//{
|
|
// char buffer[Tokenizer::MaxTokenSize];
|
|
// dStrcpy(buffer, pToker->getToken() + 5);
|
|
|
|
// pToker->advanceToken(false, true);
|
|
|
|
// // parse the number
|
|
// char * end = dStrchr(buffer, '_');
|
|
// if(!end)
|
|
// {
|
|
// pToker->advanceToken(true);
|
|
// continue;
|
|
// }
|
|
// *end++ = '\0';
|
|
// S32 stateNum = dAtoi(buffer);
|
|
// if(stateNum < 0 || stateNum > StateInfo::MaxStates)
|
|
// {
|
|
// pToker->advanceToken(true);
|
|
// continue;
|
|
// }
|
|
|
|
// // read in the value
|
|
// if(!dStricmp(end, "duration"))
|
|
// {
|
|
// mStates[stateNum].mDuration = dAtof(pToker->getToken());
|
|
// mStates[stateNum].mFlags |= StateInfo::DurationValid;
|
|
// }
|
|
// else if(!dStricmp(end, "color"))
|
|
// {
|
|
// dSscanf(pToker->getToken(), "%f %f %f",
|
|
// &mStates[stateNum].mColor.red,
|
|
// &mStates[stateNum].mColor.green,
|
|
// &mStates[stateNum].mColor.blue);
|
|
//
|
|
// mStates[stateNum].mColor.red /= 255.0f;
|
|
// mStates[stateNum].mColor.green /= 255.0f;
|
|
// mStates[stateNum].mColor.blue /= 255.0f;
|
|
|
|
// mStates[stateNum].mFlags |= StateInfo::ColorValid;
|
|
// }
|
|
//}
|
|
|
|
// check the state info
|
|
if(!mNumStates)
|
|
return(false);
|
|
|
|
for(U32 i = 0; i < mNumStates; i++)
|
|
if(!(mStates[i].mFlags & StateInfo::Valid))
|
|
return(false);
|
|
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// static stock lights
|
|
//------------------------------------------------------------------------------
|
|
|
|
LightOmniEntity::LightOmniEntity()
|
|
{
|
|
mColor.set(1,1,1);
|
|
mFalloff1 = 20;
|
|
mFalloff2 = 300;
|
|
}
|
|
|
|
bool LightOmniEntity::parseEntityDescription(InteriorMapResource::Entity* ent)
|
|
{
|
|
char* value;
|
|
|
|
value = ent->getValue("origin");
|
|
if (value)
|
|
dSscanf(value, "%lf %lf %lf", &mOrigin.x, &mOrigin.y, &mOrigin.z);
|
|
|
|
value = ent->getValue("name");
|
|
if (value)
|
|
dStrcpy(mLightName, value);
|
|
|
|
value = ent->getValue("color");
|
|
if (value)
|
|
{
|
|
dSscanf(value, "%f %f %f", &mColor.red, &mColor.green, &mColor.blue);
|
|
mColor.red /= 255.0f;
|
|
mColor.green /= 255.0f;
|
|
mColor.blue /= 255.0f;
|
|
}
|
|
|
|
// For Quake maps
|
|
value = ent->getValue("_color");
|
|
if (value)
|
|
{
|
|
dSscanf(value, "%f %f %f", &mColor.red, &mColor.green, &mColor.blue);
|
|
mColor.red /= 255.0f;
|
|
mColor.green /= 255.0f;
|
|
mColor.blue /= 255.0f;
|
|
}
|
|
|
|
value = ent->getValue("alarm_type");
|
|
if (value)
|
|
mAlarmStatus = (AlarmStatus)dAtoi(value);
|
|
|
|
value = ent->getValue("falloff1");
|
|
if (value)
|
|
mFalloff1 = dAtoi(value);
|
|
|
|
value = ent->getValue("falloff2");
|
|
if (value)
|
|
mFalloff2 = dAtoi(value);
|
|
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
LightSpotEntity::LightSpotEntity()
|
|
{
|
|
mTarget[0] = '\0';
|
|
mColor.set(1,1,1);
|
|
mInnerDistance = 10;
|
|
mOuterDistance = 100;
|
|
mFalloff1 = 10;
|
|
mFalloff2 = 100;
|
|
}
|
|
|
|
bool LightSpotEntity::parseEntityDescription(InteriorMapResource::Entity* ent)
|
|
{
|
|
char* value;
|
|
|
|
value = ent->getValue("origin");
|
|
if (value)
|
|
dSscanf(value, "%lf %lf %lf", &mOrigin.x, &mOrigin.y, &mOrigin.z);
|
|
|
|
value = ent->getValue("name");
|
|
if (value)
|
|
dStrcpy(mLightName, value);
|
|
|
|
value = ent->getValue("target");
|
|
if (value)
|
|
dStrcpy(mTarget, value);
|
|
|
|
value = ent->getValue("color");
|
|
if (value)
|
|
{
|
|
dSscanf(value, "%f %f %f", &mColor.red, &mColor.green, &mColor.blue);
|
|
mColor.red /= 255.0f;
|
|
mColor.green /= 255.0f;
|
|
mColor.blue /= 255.0f;
|
|
}
|
|
|
|
value = ent->getValue("alarm_type");
|
|
if (value)
|
|
mAlarmStatus = (AlarmStatus)dAtoi(value);
|
|
|
|
value = ent->getValue("falloff1");
|
|
if (value)
|
|
mFalloff1 = dAtoi(value);
|
|
|
|
value = ent->getValue("falloff2");
|
|
if (value)
|
|
mFalloff2 = dAtoi(value);
|
|
|
|
value = ent->getValue("distance1");
|
|
if (value)
|
|
mInnerDistance = dAtoi(value);
|
|
|
|
value = ent->getValue("distance2");
|
|
if (value)
|
|
mOuterDistance = dAtoi(value);
|
|
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// animated stock lignts
|
|
//------------------------------------------------------------------------------
|
|
|
|
LightStrobeEntity::LightStrobeEntity()
|
|
{
|
|
mSpeed = Normal;
|
|
mColor1.set(0,0,0);
|
|
mColor2.set(1,1,1);
|
|
mFalloff1 = 10;
|
|
mFalloff2 = 100;
|
|
}
|
|
|
|
bool LightStrobeEntity::parseEntityDescription(InteriorMapResource::Entity* ent)
|
|
{
|
|
char* value;
|
|
|
|
value = ent->getValue("origin");
|
|
if (value)
|
|
dSscanf(value, "%lf %lf %lf", &mOrigin.x, &mOrigin.y, &mOrigin.z);
|
|
|
|
value = ent->getValue("name");
|
|
if (value)
|
|
dStrcpy(mLightName, value);
|
|
|
|
value = ent->getValue("spawnflags");
|
|
if (value)
|
|
mFlags = dAtoi(value) & Interior::AnimationTypeMask;
|
|
|
|
|
|
value = ent->getValue("color1");
|
|
if (value)
|
|
{
|
|
dSscanf(value, "%f %f %f", &mColor1.red, &mColor1.green, &mColor1.blue);
|
|
mColor1.red /= 255.0f;
|
|
mColor1.green /= 255.0f;
|
|
mColor1.blue /= 255.0f;
|
|
}
|
|
|
|
value = ent->getValue("color2");
|
|
if (value)
|
|
{
|
|
dSscanf(value, "%f %f %f", &mColor2.red, &mColor2.green, &mColor2.blue);
|
|
mColor2.red /= 255.0f;
|
|
mColor2.green /= 255.0f;
|
|
mColor2.blue /= 255.0f;
|
|
}
|
|
|
|
value = ent->getValue("alarm_type");
|
|
if (value)
|
|
mAlarmStatus = (AlarmStatus)dAtoi(value);
|
|
|
|
value = ent->getValue("falloff1");
|
|
if (value)
|
|
mFalloff1 = dAtoi(value);
|
|
|
|
value = ent->getValue("falloff2");
|
|
if (value)
|
|
mFalloff2 = dAtoi(value);
|
|
|
|
value = ent->getValue("speed");
|
|
if (value)
|
|
mSpeed = dAtoi(value);
|
|
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
LightPulseEntity::LightPulseEntity()
|
|
{
|
|
mSpeed = Normal;
|
|
mColor1.set(0,0,0);
|
|
mColor2.set(1,1,1);
|
|
mFalloff1 = 10;
|
|
mFalloff2 = 100;
|
|
}
|
|
|
|
bool LightPulseEntity::parseEntityDescription(InteriorMapResource::Entity* ent)
|
|
{
|
|
char* value;
|
|
|
|
value = ent->getValue("origin");
|
|
if (value)
|
|
dSscanf(value, "%lf %lf %lf", &mOrigin.x, &mOrigin.y, &mOrigin.z);
|
|
|
|
value = ent->getValue("name");
|
|
if (value)
|
|
dStrcpy(mLightName, value);
|
|
|
|
value = ent->getValue("spawnflags");
|
|
if (value)
|
|
mFlags = dAtoi(value) & Interior::AnimationTypeMask;
|
|
|
|
value = ent->getValue("color1");
|
|
if (value)
|
|
{
|
|
dSscanf(value, "%f %f %f", &mColor1.red, &mColor1.green, &mColor1.blue);
|
|
mColor1.red /= 255.0f;
|
|
mColor1.green /= 255.0f;
|
|
mColor1.blue /= 255.0f;
|
|
}
|
|
|
|
value = ent->getValue("color2");
|
|
if (value)
|
|
{
|
|
dSscanf(value, "%f %f %f", &mColor2.red, &mColor2.green, &mColor2.blue);
|
|
mColor2.red /= 255.0f;
|
|
mColor2.green /= 255.0f;
|
|
mColor2.blue /= 255.0f;
|
|
}
|
|
|
|
value = ent->getValue("alarm_type");
|
|
if (value)
|
|
mAlarmStatus = (AlarmStatus)dAtoi(value);
|
|
|
|
value = ent->getValue("falloff1");
|
|
if (value)
|
|
mFalloff1 = dAtoi(value);
|
|
|
|
value = ent->getValue("falloff2");
|
|
if (value)
|
|
mFalloff2 = dAtoi(value);
|
|
|
|
value = ent->getValue("speed");
|
|
if (value)
|
|
mSpeed = dAtoi(value);
|
|
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
LightPulse2Entity::LightPulse2Entity()
|
|
{
|
|
mColor1.set(0,0,0);
|
|
mColor2.set(1,1,1);
|
|
mFalloff1 = 10;
|
|
mFalloff2 = 100;
|
|
mAttack = mSustain1 = mDecay = mSustain2 = 1.f;
|
|
}
|
|
|
|
bool LightPulse2Entity::parseEntityDescription(InteriorMapResource::Entity* ent)
|
|
{
|
|
char* value;
|
|
|
|
value = ent->getValue("origin");
|
|
if (value)
|
|
dSscanf(value, "%lf %lf %lf", &mOrigin.x, &mOrigin.y, &mOrigin.z);
|
|
|
|
value = ent->getValue("name");
|
|
if (value)
|
|
dStrcpy(mLightName, value);
|
|
|
|
value = ent->getValue("spawnflags");
|
|
if (value)
|
|
mFlags = dAtoi(value) & Interior::AnimationTypeMask;
|
|
|
|
value = ent->getValue("color1");
|
|
if (value)
|
|
{
|
|
dSscanf(value, "%f %f %f", &mColor1.red, &mColor1.green, &mColor1.blue);
|
|
mColor1.red /= 255.0f;
|
|
mColor1.green /= 255.0f;
|
|
mColor1.blue /= 255.0f;
|
|
}
|
|
|
|
value = ent->getValue("color2");
|
|
if (value)
|
|
{
|
|
dSscanf(value, "%f %f %f", &mColor2.red, &mColor2.green, &mColor2.blue);
|
|
mColor2.red /= 255.0f;
|
|
mColor2.green /= 255.0f;
|
|
mColor2.blue /= 255.0f;
|
|
}
|
|
|
|
value = ent->getValue("alarm_type");
|
|
if (value)
|
|
mAlarmStatus = (AlarmStatus)dAtoi(value);
|
|
|
|
value = ent->getValue("falloff1");
|
|
if (value)
|
|
mFalloff1 = dAtoi(value);
|
|
|
|
value = ent->getValue("falloff2");
|
|
if (value)
|
|
mFalloff2 = dAtoi(value);
|
|
|
|
value = ent->getValue("attack");
|
|
if (value)
|
|
mAttack = dAtof(value);
|
|
|
|
value = ent->getValue("decay");
|
|
if (value)
|
|
mDecay = dAtof(value);
|
|
|
|
value = ent->getValue("sustain1");
|
|
if (value)
|
|
mSustain1 = dAtof(value);
|
|
|
|
value = ent->getValue("sustain2");
|
|
if (value)
|
|
mSustain2 = dAtof(value);
|
|
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
LightFlickerEntity::LightFlickerEntity()
|
|
{
|
|
mSpeed = Normal;
|
|
mColor1.set(1,1,1);
|
|
mColor2.set(0,0,0);
|
|
mColor3.set(0,0,0);
|
|
mColor4.set(0,0,0);
|
|
mColor5.set(0,0,0);
|
|
mFalloff1 = 10;
|
|
mFalloff2 = 100;
|
|
}
|
|
|
|
bool LightFlickerEntity::parseEntityDescription(InteriorMapResource::Entity* ent)
|
|
{
|
|
char* value;
|
|
|
|
value = ent->getValue("origin");
|
|
if (value)
|
|
dSscanf(value, "%lf %lf %lf", &mOrigin.x, &mOrigin.y, &mOrigin.z);
|
|
|
|
value = ent->getValue("name");
|
|
if (value)
|
|
dStrcpy(mLightName, value);
|
|
|
|
value = ent->getValue("spawnflags");
|
|
if (value)
|
|
mFlags = dAtoi(value) & Interior::AnimationTypeMask;
|
|
|
|
value = ent->getValue("color1");
|
|
if (value)
|
|
{
|
|
dSscanf(value, "%f %f %f", &mColor1.red, &mColor1.green, &mColor1.blue);
|
|
mColor1.red /= 255.0f;
|
|
mColor1.green /= 255.0f;
|
|
mColor1.blue /= 255.0f;
|
|
}
|
|
|
|
value = ent->getValue("color2");
|
|
if (value)
|
|
{
|
|
dSscanf(value, "%f %f %f", &mColor2.red, &mColor2.green, &mColor2.blue);
|
|
mColor2.red /= 255.0f;
|
|
mColor2.green /= 255.0f;
|
|
mColor2.blue /= 255.0f;
|
|
}
|
|
|
|
value = ent->getValue("color3");
|
|
if (value)
|
|
{
|
|
dSscanf(value, "%f %f %f", &mColor3.red, &mColor3.green, &mColor3.blue);
|
|
mColor3.red /= 255.0f;
|
|
mColor3.green /= 255.0f;
|
|
mColor3.blue /= 255.0f;
|
|
}
|
|
|
|
value = ent->getValue("color4");
|
|
if (value)
|
|
{
|
|
dSscanf(value, "%f %f %f", &mColor4.red, &mColor4.green, &mColor4.blue);
|
|
mColor4.red /= 255.0f;
|
|
mColor4.green /= 255.0f;
|
|
mColor4.blue /= 255.0f;
|
|
}
|
|
|
|
value = ent->getValue("color5");
|
|
if (value)
|
|
{
|
|
dSscanf(value, "%f %f %f", &mColor5.red, &mColor5.green, &mColor5.blue);
|
|
mColor5.red /= 255.0f;
|
|
mColor5.green /= 255.0f;
|
|
mColor5.blue /= 255.0f;
|
|
}
|
|
|
|
value = ent->getValue("alarm_type");
|
|
if (value)
|
|
mAlarmStatus = (AlarmStatus)dAtoi(value);
|
|
|
|
value = ent->getValue("falloff1");
|
|
if (value)
|
|
mFalloff1 = dAtoi(value);
|
|
|
|
value = ent->getValue("falloff2");
|
|
if (value)
|
|
mFalloff2 = dAtoi(value);
|
|
|
|
value = ent->getValue("speed");
|
|
if (value)
|
|
mSpeed = dAtoi(value);
|
|
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
LightRunwayEntity::LightRunwayEntity()
|
|
{
|
|
mEndTarget[0] = '\0';
|
|
mColor.set(1,1,1);
|
|
mSpeed = Normal;
|
|
mPingPong = false;
|
|
mSteps = 0;
|
|
mFalloff1 = 10;
|
|
mFalloff2 = 100;
|
|
}
|
|
|
|
bool LightRunwayEntity::parseEntityDescription(InteriorMapResource::Entity* ent)
|
|
{
|
|
char* value;
|
|
|
|
value = ent->getValue("origin");
|
|
if (value)
|
|
dSscanf(value, "%lf %lf %lf", &mOrigin.x, &mOrigin.y, &mOrigin.z);
|
|
|
|
value = ent->getValue("name");
|
|
if (value)
|
|
dStrcpy(mLightName, value);
|
|
|
|
value = ent->getValue("spawnflags");
|
|
if (value)
|
|
mFlags = dAtoi(value) & Interior::AnimationTypeMask;
|
|
|
|
value = ent->getValue("target");
|
|
if (value)
|
|
dStrcpy(mEndTarget, value);
|
|
|
|
value = ent->getValue("color");
|
|
if (value)
|
|
{
|
|
dSscanf(value, "%f %f %f", &mColor.red, &mColor.green, &mColor.blue);
|
|
mColor.red /= 255.0f;
|
|
mColor.green /= 255.0f;
|
|
mColor.blue /= 255.0f;
|
|
}
|
|
|
|
value = ent->getValue("alarm_type");
|
|
if (value)
|
|
mAlarmStatus = (AlarmStatus)dAtoi(value);
|
|
|
|
value = ent->getValue("falloff1");
|
|
if (value)
|
|
mFalloff1 = dAtoi(value);
|
|
|
|
value = ent->getValue("falloff2");
|
|
if (value)
|
|
mFalloff2 = dAtoi(value);
|
|
|
|
value = ent->getValue("speed");
|
|
if (value)
|
|
mSpeed = dAtoi(value);
|
|
|
|
value = ent->getValue("steps");
|
|
if (value)
|
|
mSteps = dAtoi(value);
|
|
|
|
value = ent->getValue("pingpong");
|
|
if (value)
|
|
mPingPong = dAtoi(value) ? true : false;
|
|
|
|
return true;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//--------------------------------------
|
|
U32 MirrorSurfaceEntity::smZoneKeyAllocator = 0;
|
|
|
|
MirrorSurfaceEntity::MirrorSurfaceEntity()
|
|
{
|
|
mZoneKey = smZoneKeyAllocator | 0x40000000;
|
|
smZoneKeyAllocator++;
|
|
|
|
mRealZone = 0xFFFFFFFF;
|
|
}
|
|
|
|
bool MirrorSurfaceEntity::parseEntityDescription(InteriorMapResource::Entity* ent)
|
|
{
|
|
char* value;
|
|
|
|
value = ent->getValue("origin");
|
|
if (value)
|
|
dSscanf(value, "%lf %lf %lf", &mOrigin.x, &mOrigin.y, &mOrigin.z);
|
|
|
|
value = ent->getValue("alpha_level");
|
|
if (value)
|
|
{
|
|
S32 alevel = dAtoi(value);
|
|
if (alevel < 0)
|
|
alevel = 0;
|
|
else if (alevel > 6)
|
|
alevel = 6;
|
|
|
|
switch (alevel)
|
|
{
|
|
case 0: mAlphaLevel = 0.0; break;
|
|
case 1: mAlphaLevel = 0.1666666666; break;
|
|
case 2: mAlphaLevel = 0.3333333333; break;
|
|
case 3: mAlphaLevel = 0.5; break;
|
|
case 4: mAlphaLevel = 0.6666666666; break;
|
|
case 5: mAlphaLevel = 0.8333333333; break;
|
|
case 6: mAlphaLevel = 1.0; break;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
BrushType MirrorSurfaceEntity::getBrushType()
|
|
{
|
|
AssertISV(false, "brushes cannot be associated with mirrors!");
|
|
return DetailBrush;
|
|
}
|
|
|
|
void MirrorSurfaceEntity::markSurface(Vector<CSGBrush*>& rStructural,
|
|
Vector<CSGBrush*>& /*rDetail*/)
|
|
{
|
|
U32 brushIndex = 0;
|
|
U32 planeIndex = 0;
|
|
F64 minDist = 1e10;
|
|
for (U32 i = 0; i < rStructural.size(); i++) {
|
|
CSGBrush* pBrush = rStructural[i];
|
|
|
|
for (U32 j = 0; j < pBrush->mPlanes.size(); j++) {
|
|
CSGPlane& rPlane = pBrush->mPlanes[j];
|
|
const PlaneEQ& rPlaneEQ = gWorkingGeometry->getPlaneEQ(rPlane.planeEQIndex);
|
|
F64 dist = mFabs(rPlaneEQ.distanceToPlane(getOrigin()));
|
|
|
|
if (dist < minDist) {
|
|
bool goodPlane = true;
|
|
|
|
// First, confirm that the point is behind all the other planes...
|
|
for (U32 k = 0; k < pBrush->mPlanes.size(); k++) {
|
|
if (k == j)
|
|
continue;
|
|
|
|
CSGPlane& rPlaneTest = pBrush->mPlanes[k];
|
|
const PlaneEQ& rPlaneEQTest = gWorkingGeometry->getPlaneEQ(rPlaneTest.planeEQIndex);
|
|
|
|
if (rPlaneEQTest.whichSidePerfect(getOrigin()) == PlaneFront) {
|
|
goodPlane = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (goodPlane == true) {
|
|
minDist = dist;
|
|
brushIndex = i;
|
|
planeIndex = j;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Plane must be very close to be considered
|
|
if (minDist < 1.0f) {
|
|
CSGBrush* pBrush = rStructural[brushIndex];
|
|
CSGPlane& rPlane = pBrush->mPlanes[planeIndex];
|
|
|
|
AssertFatal(rPlane.owningEntity == NULL, "Error, brush already owned!");
|
|
rPlane.owningEntity = this;
|
|
}
|
|
}
|
|
|
|
void MirrorSurfaceEntity::grabSurface(EditGeometry::Surface& rSurface)
|
|
{
|
|
if (mRealZone == 0xFFFFFFFF) {
|
|
mRealZone = rSurface.winding.zoneIds[0];
|
|
} else {
|
|
if (rSurface.winding.zoneIds[0] != mRealZone) {
|
|
dPrintf("\n *** ACK! Mirrored brush surfaces may NOT cross zone boundaries. Surface disregarded");
|
|
return;
|
|
}
|
|
}
|
|
|
|
// This must be unique to the entity...
|
|
rSurface.winding.zoneIds[0] = mZoneKey;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//--------------------------------------
|
|
//
|
|
TriggerEntity::TriggerEntity()
|
|
{
|
|
dStrcpy(mName, "MustChange");
|
|
mDataBlock[0] = 0;
|
|
|
|
mOrigin.set(0, 0, 0);
|
|
|
|
mCurrBrushId = 0;
|
|
mValid = false;
|
|
}
|
|
|
|
TriggerEntity::~TriggerEntity()
|
|
{
|
|
for (U32 i = 0; i < mBrushes.size(); i++)
|
|
gBrushArena.freeBrush(mBrushes[i]);
|
|
}
|
|
|
|
BrushType TriggerEntity::getBrushType()
|
|
{
|
|
AssertISV(false, "brushes should have been parsed out in the entity!");
|
|
return DetailBrush;
|
|
}
|
|
|
|
bool TriggerEntity::parseEntityDescription(InteriorMapResource::Entity* ent)
|
|
{
|
|
char* value;
|
|
|
|
value = ent->getValue("name");
|
|
if (value)
|
|
dStrcpy(mName, value);
|
|
|
|
value = ent->getValue("datablock");
|
|
if (value)
|
|
dStrcpy(mDataBlock, value);
|
|
|
|
//parseBrushList(mBrushes, pToker, *gWorkingGeometry);
|
|
generateTrigger();
|
|
|
|
gTriggerId++;
|
|
return true;
|
|
}
|
|
|
|
void TriggerEntity::generateTrigger()
|
|
{
|
|
if (mBrushes.size() != 1) {
|
|
dPrintf(" * Error * Trigger must have one and only one brush (name: %s has %d)", getName(), mBrushes.size());
|
|
mValid = false;
|
|
return;
|
|
}
|
|
|
|
// Ok, we assume that this brush is a cube, check by looking at the number of planes.
|
|
// Note that this is a really lousy check, we might want to add some better ones later.
|
|
// Also, most of this is really hacky, there's definitely a better way to extract the
|
|
// canonical box...
|
|
//
|
|
CSGBrush* pBrush = mBrushes[0];
|
|
if (pBrush->mPlanes.size() != 6) {
|
|
dPrintf(" * Error * Trigger must be a rectilinear polytope (name: %s isn't)", getName());
|
|
mValid = false;
|
|
return;
|
|
}
|
|
|
|
Point3D normals[3];
|
|
U32 normalIndices[3];
|
|
|
|
normals[0] = pBrush->mPlanes[0].getNormal();
|
|
normalIndices[0] = 0;
|
|
|
|
U32 currentNormal = 1;
|
|
for (U32 i = 1; i < 6 && currentNormal < 3; i++) {
|
|
bool ortho = true;
|
|
for (U32 j = 0; j < currentNormal; j++) {
|
|
if (mFabs(mDot(pBrush->mPlanes[i].getNormal(), normals[j])) > 0.01)
|
|
ortho = false;
|
|
}
|
|
|
|
// Found the next normal?
|
|
if (ortho) {
|
|
normals[currentNormal] = pBrush->mPlanes[i].getNormal();
|
|
normalIndices[currentNormal] = i;
|
|
currentNormal++;
|
|
}
|
|
}
|
|
|
|
if (currentNormal < 3) {
|
|
dPrintf(" * Error * Trigger missing 3 ortho planes. (name: %s)", getName());
|
|
mValid = false;
|
|
return;
|
|
}
|
|
|
|
F64 diameters[3] = { 0, 0, 0 };
|
|
for (U32 i = 0; i < 3; i++) {
|
|
for (U32 j = 0; j < 6; j++) {
|
|
if (mDot(pBrush->mPlanes[j].getNormal(), normals[i]) < -0.999) {
|
|
// Counter part
|
|
diameters[i] += pBrush->mPlanes[j].getDist();
|
|
} else if (mDot(pBrush->mPlanes[j].getNormal(), normals[i]) > 0.9999) {
|
|
// actual
|
|
diameters[i] += pBrush->mPlanes[j].getDist();
|
|
}
|
|
}
|
|
|
|
diameters[i] = mFabs(diameters[i]);
|
|
}
|
|
|
|
// This is a really hacky way to get the center coordinate...
|
|
U32 antiNormalIndices[3];
|
|
U32 currentAnti = 0;
|
|
for (U32 i = 0; i < 6; i++) {
|
|
bool n = false;
|
|
for (U32 j = 0; j < 3; j++)
|
|
if (normalIndices[j] == i)
|
|
n = true;
|
|
if (n == false)
|
|
antiNormalIndices[currentAnti++] = i;
|
|
}
|
|
AssertFatal(currentAnti == 3, "Hm, that's bad");
|
|
|
|
Point3D min, antiMin;
|
|
|
|
bool intersect = pBrush->intersectPlanes(normalIndices[0], normalIndices[1], normalIndices[2], &min);
|
|
AssertFatal(intersect, "Also, this is bad");
|
|
intersect = pBrush->intersectPlanes(antiNormalIndices[0], antiNormalIndices[1], antiNormalIndices[2], &antiMin);
|
|
AssertFatal(intersect, "Also, this is bad");
|
|
|
|
mOrigin = (min + antiMin) * 0.5;
|
|
mOrigin /= gWorkingGeometry->mWorldEntity->mGeometryScale;
|
|
|
|
Box3F tempBox;
|
|
tempBox.min.set(-diameters[0] / 2.0, -diameters[1] / 2.0, -diameters[2] / 2.0);
|
|
tempBox.min /= gWorkingGeometry->mWorldEntity->mGeometryScale;
|
|
tempBox.max.set( diameters[0] / 2.0, diameters[1] / 2.0, diameters[2] / 2.0);
|
|
tempBox.max /= gWorkingGeometry->mWorldEntity->mGeometryScale;
|
|
|
|
Point3F temp;
|
|
Point3D realNormals[3];
|
|
realNormals[0] = pBrush->mPlanes[normalIndices[0]].getNormal();
|
|
realNormals[1] = pBrush->mPlanes[normalIndices[1]].getNormal();
|
|
realNormals[2] = pBrush->mPlanes[normalIndices[2]].getNormal();
|
|
mCross(realNormals[0], realNormals[1], &realNormals[2]);
|
|
realNormals[2].neg();
|
|
mCross(realNormals[0], realNormals[2], &realNormals[1]);
|
|
realNormals[0].normalize();
|
|
realNormals[1].normalize();
|
|
realNormals[2].normalize();
|
|
|
|
MatrixF tempXForm(true);
|
|
for (U32 i = 0; i < 3; i++) {
|
|
const Point3D& rNorm = realNormals[i];
|
|
temp.x = rNorm.x;
|
|
temp.y = rNorm.y;
|
|
temp.z = rNorm.z;
|
|
|
|
tempXForm.setColumn(i, temp);
|
|
}
|
|
// Export the polyhedron...
|
|
triggerPolyhedron.buildBox(tempXForm, tempBox);
|
|
|
|
mValid = true;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//--------------------------------------
|
|
|
|
GameEntity::GameEntity()
|
|
{
|
|
mDataBlock[0] = 0;
|
|
mOrigin.set(0, 0, 0);
|
|
}
|
|
|
|
GameEntity::~GameEntity()
|
|
{
|
|
//
|
|
}
|
|
|
|
BrushType GameEntity::getBrushType()
|
|
{
|
|
AssertISV(false, "brushes cannot be associated with GameEntities!");
|
|
return DetailBrush;
|
|
}
|
|
|
|
bool GameEntity::parseEntityDescription(InteriorMapResource::Entity* ent)
|
|
{
|
|
char* value;
|
|
|
|
value = ent->getValue("origin");
|
|
if (value)
|
|
dSscanf(value, "%lf %lf %lf", &mOrigin.x, &mOrigin.y, &mOrigin.z);
|
|
|
|
value = ent->getValue("game_class");
|
|
if (value)
|
|
dStrcpy(mGameClass, value);
|
|
|
|
value = ent->getValue("datablock");
|
|
if (value)
|
|
dStrcpy(mDataBlock, value);
|
|
|
|
return true;
|
|
}
|