Initial commit

This commit is contained in:
Eagle517
2025-02-17 23:17:30 -06:00
commit 7cad314c94
4726 changed files with 1145203 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,201 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _BSPNODE_H_
#define _BSPNODE_H_
//Includes
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#endif
#ifndef _MORIANBASICS_H_
#include "map2dif plus/morianBasics.h"
#endif
class CSGBrush;
class CSGPlane;
//------------------------------------------------------------------------------
class EditBSPNode {
public:
struct PortalEntry {
public:
~PortalEntry();
Vector<Winding*> windings;
U32 planeEQIndex;
U32 portalId;
Point3D ortho1;
Point3D ortho2;
void copyEntry(const PortalEntry&);
};
struct VisLink {
public:
Winding winding;
U32 planeEQIndex;
S32 portalId;
EditBSPNode* pFront;
EditBSPNode* pBack;
VisLink* pNext;
public:
bool intersect(U32 planeEQIndex);
PlaneSide whichSide(U32 planeEQIndex);
};
enum PlaneType {
Structural = 0,
Portal = 1,
Detail = 2
};
private:
void createPortalWindings(const PortalEntry& rBaseWindings, PortalEntry* pFinalEntry);
private:
S32 calcPlaneRating(U32 testPlane);
bool planeInParents(U32 testPlane);
U32 selectBestPlane();
void eraseReferencingLinks();
void splitBrushList();
void splitVisLinks();
void splitPortalEntries();
CSGBrush* findSolidBrush();
public:
S32 planeEQIndex;
EditBSPNode* pParent;
EditBSPNode* pFront;
EditBSPNode* pBack;
PlaneType planeType;
bool isSolid;
CSGBrush* solidBrush;
S32 zoneId;
U32 nodeId;
// Portal information
Vector<PortalEntry*> portals;
// Vising information
Vector<VisLink*> visLinks;
void enterLink(VisLink*);
// For building BSP. List of mInteriorRes->mBrushes
Vector<CSGBrush*> brushList;
public:
EditBSPNode() : planeEQIndex(-1), planeType(Detail),
pParent(NULL), pFront(NULL), pBack(NULL) { isSolid = false; solidBrush = NULL; }
~EditBSPNode();
//-------------------------------------- BSP/Portal/Zone creation/manipulation
public:
void createBSP(PlaneType _planeType);
void createVisLinks();
void zoneFlood();
void floodZone(S32 markZoneId);
void gatherPortals();
S32 findZone(const Point3D& rPoint);
PortalEntry* mungePortalBrush(CSGBrush* pBrush);
void insertPortalEntry(PortalEntry* pPortal);
void breakWindingS(const Vector<Winding>& windings,
U32 windingPlaneIndex,
const CSGBrush* sourceBrush,
Vector<Winding>& outputWindings);
void breakWinding(const Vector<Winding>& windings,
U32 windingPlaneIndex,
const CSGBrush* sourceBrush,
Vector<Winding>& outputWindings);
//-------------------------------------- Statistics
public:
void gatherBSPStats(U32* pNumLeaves,
U32* pTotalLeafDepth,
U32* pMaxLeafDepth,
U32 depth);
void gatherVISStats(U32* pEmptyLeaves,
U32* pTotalLinks,
U32* pMaxLinks);
void removeVISInfo();
};
inline void EditBSPNode::enterLink(VisLink* pEnter)
{
visLinks.push_back(pEnter);
}
//------------------------------------------------------------------------------
class NodeArena {
public:
Vector<EditBSPNode*> mBuffers;
U32 arenaSize;
EditBSPNode* currBuffer;
U32 currPosition;
public:
NodeArena(U32 _arenaSize);
~NodeArena();
EditBSPNode* allocateNode(EditBSPNode* pParent);
};
inline EditBSPNode* NodeArena::allocateNode(EditBSPNode* _pParent)
{
static U32 sNodeIdAlloc = 0;
AssertFatal(currPosition <= arenaSize, "How did this happen? Arenasize is absolute!");
if (currPosition == arenaSize) {
// Need to allocate a new buffer...
currBuffer = new EditBSPNode[arenaSize];
currPosition = 0;
mBuffers.push_back(currBuffer);
}
EditBSPNode* pRet = &currBuffer[currPosition++];
pRet->pParent = _pParent;
pRet->zoneId = -1;
pRet->nodeId = sNodeIdAlloc++;
return pRet;
}
class VisLinkArena {
Vector<EditBSPNode::VisLink*> mBuffers;
U32 arenaSize;
EditBSPNode::VisLink* pCurrent;
public:
VisLinkArena(U32 _arenaSize);
~VisLinkArena();
EditBSPNode::VisLink* allocateLink();
void releaseLink(EditBSPNode::VisLink*);
void clearAll();
};
#endif //_BSPNODE_H_

View File

@ -0,0 +1,340 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
// This file contains all of the functions for converting an InteriorMap into an EditGeometry
#include "map2dif plus/convert.h"
#include "dgl/gBitmap.h"
extern const char* gWadPath;
extern GBitmap* loadBitmap(const char* file);
void loadTextures(InteriorMap* map)
{
// Insert the dummy textures
gWorkingGeometry->insertTexture("NULL");
gWorkingGeometry->insertTexture("TRIGGER");
// Basically we just need to load the textures to get the texture sizes
GBitmap** textures = new GBitmap*[map->mInteriorRes->mMaterials.size()];
Con::printf(" Loading textures:");
dPrintf("\n");
for (int i = 0; i < map->mInteriorRes->mMaterials.size(); i++)
{
// Get the texture file name
char loadBuffer[4096];
dSprintf(loadBuffer, sizeof(loadBuffer), "%s%s", gWadPath, map->mInteriorRes->mMaterials[i]);
// loadBitmap() will walk up the path till it finds the texture
textures[i] = loadBitmap(loadBuffer);
// Notify the user we couldn't load the texture
if (!textures[i])
{
Con::printf(" Unable to load texture %s", map->mInteriorRes->mMaterials[i]);
dPrintf(" Unable to load texture %s\n", map->mInteriorRes->mMaterials[i]);
dFflushStdout();
}
else
Con::printf(" Loaded texture %s", map->mInteriorRes->mMaterials[i]);
}
// Divide our texgens through by the texture sizes
if (map->mInteriorRes->mBrushFormat != InteriorMapResource::QuakeOld && map->mInteriorRes->mBrushFormat != InteriorMapResource::Valve220)
return;
for (U32 i = 0; i < map->mInteriorRes->mMaterials.size(); i++)
{
F32 width = 16.0f;
F32 height = 16.0f;
if (textures[i])
{
width = textures[i]->getWidth();
height = textures[i]->getHeight();
if (!isPow2((U32)width) || !isPow2((U32)height))
{
Con::printf(" Error: Non-power of two sized texture - %s (%d x %d)", map->mInteriorRes->mMaterials[i], (U32)width, (U32)height);
dPrintf(" Error: Non-power of two sized texture - %s (%d x %d)\n", map->mInteriorRes->mMaterials[i], (U32)width, (U32)height);
}
}
dFflushStdout();
for (U32 j = 0; j < map->mInteriorRes->mBrushes.size(); j++)
{
for (U32 k = 0; k < map->mInteriorRes->mBrushes[j]->mFaces.mPolyList.size(); k++)
{
if (i == map->mInteriorRes->mBrushes[j]->mFaces.mPolyList[k].material)
{
map->mInteriorRes->mBrushes[j]->mTexInfos[k].texDiv[0] = width;
map->mInteriorRes->mBrushes[j]->mTexInfos[k].texDiv[1] = height;
map->mInteriorRes->mBrushes[j]->mTexInfos[k].texGens[0].x /= width;
map->mInteriorRes->mBrushes[j]->mTexInfos[k].texGens[0].y /= width;
map->mInteriorRes->mBrushes[j]->mTexInfos[k].texGens[0].z /= width;
map->mInteriorRes->mBrushes[j]->mTexInfos[k].texGens[0].d /= width;
map->mInteriorRes->mBrushes[j]->mTexInfos[k].texGens[1].x /= height;
map->mInteriorRes->mBrushes[j]->mTexInfos[k].texGens[1].y /= height;
map->mInteriorRes->mBrushes[j]->mTexInfos[k].texGens[1].z /= height;
map->mInteriorRes->mBrushes[j]->mTexInfos[k].texGens[1].d /= height;
}
}
}
}
// Flag all of the faces that couldn't load a texture
for (U32 i = 0; i < map->mInteriorRes->mMaterials.size(); i++)
{
if (textures[i])
continue;
for (U32 j = 0; j < map->mInteriorRes->mBrushes.size(); j++)
{
for (U32 k = 0; k < map->mInteriorRes->mBrushes[j]->mFaces.mPolyList.size(); k++)
{
if (i == map->mInteriorRes->mBrushes[j]->mFaces.mPolyList[k].material)
map->mInteriorRes->mBrushes[j]->mFaces.mPolyList[k].material = -1;
}
}
}
// Clean up our textures
for (int i = 0; i < map->mInteriorRes->mMaterials.size(); i++)
delete textures[i];
delete [] textures;
}
void convertInteriorMap(InteriorMap* map)
{
// First copy over the worldspawn entity
getWorldSpawn(map);
gWorkingGeometry->mMinBound.set(1e10, 1e10, 1e10);
gWorkingGeometry->mMaxBound.set(-1e10, -1e10, -1e10);
// Next add our mInteriorRes->mBrushes
getBrushes(map);
// Now get our mInteriorRes->mEntities
getEntities(map);
}
void getBrushes(InteriorMap* map)
{
CSGBrush* pBrush;
for (U32 i = 0; i < map->mInteriorRes->mBrushes.size(); i++)
{
// Only load good mInteriorRes->mBrushes
if (map->mInteriorRes->mBrushes[i]->mStatus != ConvexBrush::Good)
{
Con::printf(" Error: Brush %d - %s", i, map->mInteriorRes->mBrushes[i]->mDebugInfo);
dPrintf(" Error: Brush %d - %s\n", i, map->mInteriorRes->mBrushes[i]->mDebugInfo);
continue;
}
if (map->mInteriorRes->mBrushes[i]->mType == InteriorMapResource::Structural)
{
gWorkingGeometry->mStructuralBrushes.push_back(gBrushArena.allocateBrush());
pBrush = gWorkingGeometry->mStructuralBrushes.last();
pBrush->mBrushType = StructuralBrush;
}
else if (map->mInteriorRes->mBrushes[i]->mType == InteriorMapResource::Detail)
{
gWorkingGeometry->mDetailBrushes.push_back(gBrushArena.allocateBrush());
pBrush = gWorkingGeometry->mDetailBrushes.last();
pBrush->mBrushType = DetailBrush;
}
else if (map->mInteriorRes->mBrushes[i]->mType == InteriorMapResource::Portal)
{
gWorkingGeometry->mPortalBrushes.push_back(gBrushArena.allocateBrush());
pBrush = gWorkingGeometry->mPortalBrushes.last();
pBrush->mBrushType = PortalBrush;
}
else if (map->mInteriorRes->mBrushes[i]->mType == InteriorMapResource::Collision)
{
gWorkingGeometry->mSpecialCollisionBrushes.push_back(gBrushArena.allocateBrush());
pBrush = gWorkingGeometry->mSpecialCollisionBrushes.last();
pBrush->mBrushType = CollisionBrush;
}
else
continue;
pBrush->materialType = 0;
pBrush->brushId = gWorkingGeometry->mCurrBrushId++;
for (U32 j = 0; j < map->mInteriorRes->mBrushes[i]->mFaces.mPolyList.size(); j++)
{
// Copy over the plane for the face
CSGPlane plane;
plane.flags = 0;
plane.owningEntity = NULL;
plane.winding.numNodes = 0;
plane.winding.numZoneIds = 0;
PlaneF normal = map->mInteriorRes->mBrushes[i]->mFaces.mPlaneList[map->mInteriorRes->mBrushes[i]->mFaces.mPolyList[j].plane];
plane.planeEQIndex = gWorkingGeometry->insertPlaneEQ(Point3D(normal.x, normal.y, normal.z), normal.d);
// Set up the texture
S32 tx = map->mInteriorRes->mBrushes[i]->mFaces.mPolyList[j].material;
if (tx > -1)
{
char* texture = (char*)map->mInteriorRes->mMaterials[tx];
plane.pTextureName = gWorkingGeometry->insertTexture(texture);
}
else
{
plane.pTextureName = gWorkingGeometry->insertTexture("WHITE");
}
// Copy over the texgens
PlaneF tGenX = map->mInteriorRes->mBrushes[i]->mTexInfos[j].texGens[0];
PlaneF tGenY = map->mInteriorRes->mBrushes[i]->mTexInfos[j].texGens[1];
plane.texGenIndex = addTexGen(tGenX, tGenY);
pBrush->addPlane(plane);
}
}
}
// Entity conversions
void getWorldSpawn(InteriorMap* map)
{
gWorkingGeometry->mWorldEntity = new WorldSpawnEntity;
InteriorMapResource::Entity* world = map->getEntity("worldspawn");
if (world)
{
char* value;
value = world->getValue("detail_number");
if (value)
gWorkingGeometry->mWorldEntity->mDetailNumber = dAtoi(value);
value = world->getValue("min_pixels");
if (value)
gWorkingGeometry->mWorldEntity->mMinPixels = dAtoi(value);
value = world->getValue("geometry_scale");
if (value)
gWorkingGeometry->mWorldEntity->mGeometryScale = dAtof(value);
value = world->getValue("light_geometry_scale");
if (value)
gWorkingGeometry->mWorldEntity->mLumelScale = dAtof(value);
value = world->getValue("ambient_color");
if (value)
{
dSscanf(value, "%f %f %f",
&gWorkingGeometry->mWorldEntity->mAmbientColor.red,
&gWorkingGeometry->mWorldEntity->mAmbientColor.green,
&gWorkingGeometry->mWorldEntity->mAmbientColor.blue);
}
}
}
void getEntities(InteriorMap* map)
{
for (U32 i = 0; i < map->mInteriorRes->mEntities.size(); i++)
{
// Going to use an odd version of the old map2dif entity code
EditGeometry::Entity* pEntity = NULL;
InteriorMapResource::Entity* ent = map->mInteriorRes->mEntities[i];
if (dStricmp(ent->classname, DetailEntity::getClassName()) == 0)
pEntity = new DetailEntity;
else if (dStricmp(ent->classname, CollisionEntity::getClassName()) == 0)
pEntity = new CollisionEntity;
else if (dStricmp(ent->classname, PortalEntity::getClassName()) == 0)
pEntity = new PortalEntity;
else if (dStricmp(ent->classname, TargetEntity::getClassName()) == 0)
pEntity = new TargetEntity;
// lighting: emitters
if (dStricmp(ent->classname, PointEmitterEntity::getClassName()) == 0)
pEntity = new PointEmitterEntity;
else if (dStricmp(ent->classname, SpotEmitterEntity::getClassName()) == 0)
pEntity = new SpotEmitterEntity;
// lighting: lights
else if (dStricmp(ent->classname, LightEntity::getClassName()) == 0)
{
// For now just shove quake lights into omni_lights
if (map->mInteriorRes->mBrushFormat == InteriorMapResource::QuakeOld)
{
pEntity = new LightOmniEntity;
LightOmniEntity* pLight = static_cast<LightOmniEntity*>(pEntity);
pLight->mColor.set(0.6f, 0.6f, 0.6f);
}
else
pEntity = new LightEntity;
}
else if (dStricmp(ent->classname, "light_globe") == 0)
{
// For now just shove quake lights into omni_lights
pEntity = new LightOmniEntity;
LightOmniEntity* pLight = static_cast<LightOmniEntity*>(pEntity);
pLight->mColor.set(0.6f, 0.6f, 0.6f);
}
// lighting: scripted lights
else if (dStricmp(ent->classname, LightOmniEntity::getClassName()) == 0)
pEntity = new LightOmniEntity;
else if (dStricmp(ent->classname, LightSpotEntity::getClassName()) == 0)
pEntity = new LightSpotEntity;
// lighting: animated lights
else if (dStricmp(ent->classname, LightStrobeEntity::getClassName()) == 0)
pEntity = new LightStrobeEntity;
else if (dStricmp(ent->classname, LightPulseEntity::getClassName()) == 0)
pEntity = new LightPulseEntity;
else if (dStricmp(ent->classname, LightPulse2Entity::getClassName()) == 0)
pEntity = new LightPulse2Entity;
else if (dStricmp(ent->classname, LightFlickerEntity::getClassName()) == 0)
pEntity = new LightFlickerEntity;
else if (dStricmp(ent->classname, LightRunwayEntity::getClassName()) == 0)
pEntity = new LightRunwayEntity;
// Special classes
else if (dStricmp(ent->classname, MirrorSurfaceEntity::getClassName()) == 0)
pEntity = new MirrorSurfaceEntity;
// Trigger Classes
else if (dStricmp(ent->classname, TriggerEntity::getClassName()) == 0)
pEntity = new TriggerEntity;
// Game Classes
else if (dStricmp(ent->classname, GameEntity::getClassName()) == 0)
pEntity = new GameEntity;
// If we have an entity then parse it
if (pEntity)
{
if (pEntity->parseEntityDescription(ent) == false)
{
dPrintf(" Error processing entity %s", ent->classname);
delete pEntity;
}
else
{
gWorkingGeometry->mEntities.push_back(pEntity);
if (dStricmp(ent->classname, PortalEntity::getClassName()) == 0)
gWorkingGeometry->mPortalEntities.push_back(pEntity);
}
}
}
}

View File

@ -0,0 +1,22 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _CONVERT_H_
#define _CONVERT_H_
#include "interior/interiorMap.h"
#include "map2dif plus/csgBrush.h"
#include "map2dif plus/morianBasics.h"
#include "map2dif plus/editGeometry.h"
#include "map2dif plus/entityTypes.h"
#include "console/console.h"
void loadTextures(InteriorMap* map);
void convertInteriorMap(InteriorMap* map);
void getBrushes(InteriorMap* map);
void getWorldSpawn(InteriorMap* map);
void getEntities(InteriorMap* map);
#endif //_CONVERT_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,267 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _inc_createLightMaps
#define _inc_createLightMaps
#ifndef _ENTITYTYPES_H_
#include "map2dif plus/entityTypes.h"
#endif
#ifndef _EDITGEOMETRY_H_
#include "map2dif plus/editGeometry.h"
#endif
#ifndef _CSGBRUSH_H_
#include "map2dif plus/csgBrush.h"
#endif
#ifndef _DATACHUNKER_H_
#include "core/dataChunker.h"
#endif
#ifndef _INTERIOR_H_
#include "interior/interior.h"
#endif
static const U32 LexelPointStoreSize = 100;
static const U32 LightingMaxWindingPoints = 36;
//------------------------------------------------------------------------------
class Lighting
{
public:
// 132 bytes from 396
struct MiniWinding
{
union {
U32 mNumIndices;
MiniWinding * mNext;
};
U32 mIndices[LightingMaxWindingPoints];
};
class EmitterInfo
{
public:
U32 mEmitter;
U32 mShadowVolume;
UniqueVector mShadowed;
// info for animated lights.
GBitmap * mLightMap;
};
Chunker<EmitterInfo> mEmitterInfoChunker;
EmitterInfo * createEmitterInfo();
//
class SVNode
{
public:
enum Side
{
Front = 0,
Back = 1,
On = 2,
Split = 3
};
enum Type
{
PolyPlane = 0,
ShadowPlane = 1,
LexelPlane = 2,
};
Type mType;
SVNode * mFront;
SVNode * mBack;
U32 mPlaneIndex;
MiniWinding * mWinding;
// polyPlane member info
SVNode * mTarget;
EmitterInfo * mEmitterInfo;
Point3D getCenter();
void split(SVNode ** front, SVNode ** back, U32 planeIndex);
void insertShadowVolume(SVNode ** root);
void insertFront(SVNode ** root);
void insertBack(SVNode ** root);
void insert(SVNode ** root);
void addToList(SVNode ** list);
void move(SVNode ** list);
void clipToVolume(SVNode ** store, SVNode * volume);
void clipToInverseVolume(SVNode ** store, SVNode * volume);
// help functions
const Point3D & getPoint(U32);
U32 insertPoint(const Point3D &);
// use only with lexel plane nodes
F64 getWindingSurfaceArea();
bool clipWindingToPlaneFront(U32 planeEQIndex);
SVNode::Side whichSide(SVNode * node);
};
// have only lexel/poly nodes with windings (keeps size of
// shadow volume down by 128 bytes each... with possibly well
// over 100k of them, saves alot of mem)
MiniWinding * createWinding();
void recycleWinding(MiniWinding *);
Chunker<MiniWinding> mWindingChunker;
MiniWinding * mWindingStore;
//
Chunker<SVNode> mNodeChunker;
SVNode * mNodeRepository;
SVNode * createNode(SVNode::Type type);
void recycleNode(SVNode * node);
class Surface
{
public:
U32 mPlaneIndex;
MiniWinding mWinding;
U32 mSurfaceIndex;
SVNode * mPolyNode;
U32 mNumEmitters;
EmitterInfo ** mEmitters;
EmitterInfo * getEmitterInfo(U32 emitter);
};
Surface * createSurface();
Chunker<Surface> mSurfaceChunker;
class Emitter
{
public:
Point3D mPos;
ColorF mColor;
U32 mPoint;
U32 mIndex;
U32 mNumSurfaces;
U32 * mSurfaces;
bool mAnimated;
Emitter();
void processBSP();
virtual bool isSurfaceLit(const Surface * surface) = 0;
virtual F64 calcIntensity(SVNode * lSurface) = 0;
};
class PointEmitter : public Emitter
{
public:
F64 mFalloffs[2];
bool isSurfaceLit(const Surface * surface);
F64 calcIntensity(SVNode * lSurface);
};
class SpotEmitter : public Emitter
{
public:
F64 mFalloffs[2];
F64 mAngles[2];
Point3D mDirection;
bool isSurfaceLit(const Surface * surface);
F64 calcIntensity(SVNode * lSurface);
};
class Light
{
public:
Light();
~Light();
class LightState {
public:
U32 mNumEmitters;
U32 mEmitterIndex;
F32 mDuration;
void fillStateData(EditGeometry::LightState * state);
};
U32 mNumStates;
U32 mStateIndex;
char * mName;
bool mAnimated;
U32 mAnimType;
bool alarm;
bool getTargetPosition(const char * name, Point3D & pos);
// each of the worldcraft light types will be processed here
bool buildLight(BaseLightEntity * entity);
// scripted lights
bool buildOmniLight(BaseLightEntity * entity);
bool buildSpotLight(BaseLightEntity * entity);
// animated...
bool buildStrobeLight(BaseLightEntity * entity);
bool buildPulseLight(BaseLightEntity * entity);
bool buildPulse2Light(BaseLightEntity * entity);
bool buildFlickerLight(BaseLightEntity * entity);
bool buildRunwayLight(BaseLightEntity * entity);
bool build(BaseLightEntity * entity);
};
Vector<Light::LightState> mLightStates;
Vector<U32> mLightStateEmitterStore;
//
Lighting();
~Lighting();
void grabLights(bool alarmMode);
void convertToFan(MiniWinding &, U32);
void copyWinding(MiniWinding &, Winding &);
U32 constructPlane(const Point3D&, const Point3D&, const Point3D&) const;
void grabSurfaces();
void processSurfaces();
void createShadowVolumes();
void processEmitterBSPs();
void lightSurfaces();
void processAnimatedLights();
//
Vector<Light *> mLights;
Vector<BaseLightEmitterEntity *> mBaseLightEmitters;
Vector<TargetEntity *> mTargets;
Vector<Emitter *> mEmitters;
Vector<Surface *> mSurfaces;
Vector<SVNode *> mShadowVolumes;
EmitterInfo ** mSurfaceEmitterInfos;
U32 * mEmitterSurfaceIndices;
ColorF mAmbientColor;
SVNode * getShadowVolume(U32 index);
Surface * getSurface(U32 index);
F64 getLumelScale();
//
Vector<Point3D> mLexelPoints;
U32 mNumAmbiguousPlanes;
const Point3D & getLexelPoint(U32 index);
U32 insertLexelPoint(const Point3D & pnt);
void flushLexelPoints();
};
#endif

View File

@ -0,0 +1,607 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
//
// Copyright (c) 2003 GarageGames.Com
//-----------------------------------------------------------------------------
#include "dgl/gBitmap.h"
#include "map2dif plus/csgBrush.h"
#include "core/tokenizer.h"
extern int gQuakeVersion;
// For the moment these exist in InteriorMap.cc
// MDFFIX: clean this up
extern F32 baseaxis[18][3];
extern void textureAxisFromPlane(const VectorF& normal, F32* xv, F32* yv);
extern void quakeTextureVecs(const VectorF& normal, F32 offsetX, F32 offsetY, F32 rotate, F32 scaleX, F32 scaleY, PlaneF* u, PlaneF *v);
void CopyConvexToCSG(ConvexBrush* convex, CSGBrush* csg)
{
for (U32 i = 0; i < convex->mFaces.mPolyList.size(); i++)
{
PlaneF normal = convex->mFaces.mPlaneList[convex->mFaces.mPolyList[i].plane];
U32 planeEQIndex = gWorkingGeometry->insertPlaneEQ(Point3D(normal.x, normal.y, normal.z), normal.d);
CSGPlane* rPlane;
if (i < csg->mPlanes.size() && planeEQIndex == csg->mPlanes[i].planeEQIndex)
rPlane = &csg->mPlanes[i];
else
{
csg->mPlanes.increment();
rPlane = &csg->mPlanes.last();
rPlane->planeEQIndex = planeEQIndex;
rPlane->pTextureName = NULL;
rPlane->flags = 0;
}
// Copy over the windings
rPlane->winding.numIndices = convex->mFaces.mPolyList[i].vertexCount;
rPlane->winding.numNodes = 0;
rPlane->winding.numZoneIds = 0;
for (U32 j = 0; j < convex->mFaces.mPolyList[i].vertexCount; j++)
{
U32 idx = convex->mFaces.mIndexList[convex->mFaces.mPolyList[i].vertexStart + j];
Point3F pt = convex->mFaces.mVertexList[idx];
U32 vdx = gWorkingGeometry->insertPoint(Point3D(pt.x, pt.y, pt.z));
rPlane->winding.indices[j] = vdx;
}
}
// Set the brush bounds
csg->mMinBound.set(1e10, 1e10, 1e10);
csg->mMaxBound.set(-1e10, -1e10, -1e10);
Box3F bounds = convex->mBounds;
csg->mMinBound.setMin(Point3D(bounds.min.x, bounds.min.y, bounds.min.z));
csg->mMaxBound.setMax(Point3D(bounds.max.x, bounds.max.y, bounds.max.z));
// Set the map bounds
gWorkingGeometry->mMinBound.setMin(Point3D(bounds.min.x, bounds.min.y, bounds.min.z));
gWorkingGeometry->mMaxBound.setMax(Point3D(bounds.max.x, bounds.max.y, bounds.max.z));
}
void CopyCSGToConvex(CSGBrush* csg, ConvexBrush* convex)
{
// Add all of the planes
// These will match up
for (U32 i = 0; i < csg->mPlanes.size(); i++)
{
CSGPlane* rPlane = &csg->mPlanes[i];
const PlaneEQ& rPlaneEQ = gWorkingGeometry->getPlaneEQ(rPlane->planeEQIndex);
PlaneF plane(rPlaneEQ.normal.x, rPlaneEQ.normal.y, rPlaneEQ.normal.z, rPlaneEQ.dist);
convex->addPlane(plane);
}
// Now process it
convex->processBrush();
}
U32 addTexGen(PlaneF tGenX, PlaneF tGenY)
{
// add it...
bool found = false;
for (U32 i = 0; i < gWorkingGeometry->mTexGenEQs.size(); i++)
{
if (gWorkingGeometry->mTexGenEQs[i].planeX == tGenX && gWorkingGeometry->mTexGenEQs[i].planeX.d == tGenX.d &&
gWorkingGeometry->mTexGenEQs[i].planeY == tGenY && gWorkingGeometry->mTexGenEQs[i].planeY.d == tGenY.d)
return i;
}
gWorkingGeometry->mTexGenEQs.increment();
gWorkingGeometry->mTexGenEQs.last().planeX = tGenX;
gWorkingGeometry->mTexGenEQs.last().planeY = tGenY;
return gWorkingGeometry->mTexGenEQs.size() - 1;
}
bool parseBrush (CSGBrush& rBrush, Tokenizer* pToker, EditGeometry& geom)
{
while (pToker->getToken()[0] == '(') {
// Enter the plane...
F64 points[3][3];
for (S32 i = 0; i < 3; i++) {
if (pToker->getToken()[0] != '(')
goto EntityBrushlistError;
for (S32 j = 0; j < 3; j++) {
pToker->advanceToken(false);
points[i][j] = dAtof(pToker->getToken());
}
pToker->advanceToken(false);
if (pToker->getToken()[0] != ')')
goto EntityBrushlistError;
pToker->advanceToken(false);
}
CSGPlane& rPlane = rBrush.constructBrushPlane(Point3D(points[0][0], points[0][1], points[0][2]),
Point3D(points[1][0], points[1][1], points[1][2]),
Point3D(points[2][0], points[2][1], points[2][2]));
// advanced already...
if (pToker->tokenAvailable() == false)
goto EntityBrushlistError;
rPlane.pTextureName = geom.insertTexture(pToker->getToken());
U32 bmIndex = geom.getMaterialIndex(rPlane.pTextureName);
const GBitmap* pBitmap = geom.mTextures[bmIndex];
PlaneF tGenX;
PlaneF tGenY;
if (gQuakeVersion == 2)
{
//hl ( 564 -396 -672 ) ( 564 -372 -672 ) ( 512 -372 -672 ) WALL_BLOCK01 [ 1 0 0 -213 ] [ 0 -1 0 -117 ] 0 1 1
if (pToker->advanceToken(false) == false) goto EntityBrushlistError;
if (pToker->getToken()[0] != '[') goto EntityBrushlistError;
if (pToker->advanceToken(false) == false) goto EntityBrushlistError;
tGenX.x = dAtof(pToker->getToken());
if (pToker->advanceToken(false) == false) goto EntityBrushlistError;
tGenX.y = dAtof(pToker->getToken());
if (pToker->advanceToken(false) == false) goto EntityBrushlistError;
tGenX.z = dAtof(pToker->getToken());
if (pToker->advanceToken(false) == false) goto EntityBrushlistError;
tGenX.d = dAtof(pToker->getToken());
if (pToker->advanceToken(false) == false) goto EntityBrushlistError;
if (pToker->getToken()[0] != ']') goto EntityBrushlistError;
if (pToker->advanceToken(false) == false) goto EntityBrushlistError;
if (pToker->getToken()[0] != '[') goto EntityBrushlistError;
if (pToker->advanceToken(false) == false) goto EntityBrushlistError;
tGenY.x = dAtof(pToker->getToken());
if (pToker->advanceToken(false) == false) goto EntityBrushlistError;
tGenY.y = dAtof(pToker->getToken());
if (pToker->advanceToken(false) == false) goto EntityBrushlistError;
tGenY.z = dAtof(pToker->getToken());
if (pToker->advanceToken(false) == false) goto EntityBrushlistError;
tGenY.d = dAtof(pToker->getToken());
if (pToker->advanceToken(false) == false) goto EntityBrushlistError;
if (pToker->getToken()[0] != ']') goto EntityBrushlistError;
if (pToker->advanceToken(false) == false) goto EntityBrushlistError;
if (pToker->advanceToken(false) == false) goto EntityBrushlistError;
F32 scaleX = dAtof(pToker->getToken());
if (pToker->advanceToken(false) == false) goto EntityBrushlistError;
F32 scaleY = dAtof(pToker->getToken());
tGenX.x /= scaleX * F32(pBitmap->getWidth());
tGenX.y /= scaleX * F32(pBitmap->getWidth());
tGenX.z /= scaleX * F32(pBitmap->getWidth());
tGenX.d /= F32(pBitmap->getWidth());
tGenY.x /= scaleY * F32(pBitmap->getHeight());
tGenY.y /= scaleY * F32(pBitmap->getHeight());
tGenY.z /= scaleY * F32(pBitmap->getHeight());
tGenY.d /= F32(pBitmap->getHeight());
}
else if (gQuakeVersion == 3)
{
//q1 ( 88 -40 8 ) ( -56 -40 8 ) ( -56 -64 8 ) block10d 0 0 0 1.000000 1.000000
//q2 ( 88 -40 8 ) ( -56 -40 8 ) ( -56 -64 8 ) block10d 0 0 0 1.000000 1.000000
//q3 ( 88 -40 8 ) ( -56 -40 8 ) ( -56 -64 8 ) block10d 0 0 0 0.500000 0.500000 0 0 0
if (pToker->advanceToken(false) == false) goto EntityBrushlistError;
F32 shiftU = dAtof (pToker->getToken());
if (pToker->advanceToken(false) == false) goto EntityBrushlistError;
F32 shiftV = dAtof (pToker->getToken());
if (pToker->advanceToken(false) == false) goto EntityBrushlistError;
F32 rot = dAtof (pToker->getToken());
if (pToker->advanceToken(false) == false) goto EntityBrushlistError;
F32 scaleX = dAtof(pToker->getToken());
if (pToker->advanceToken(false) == false) goto EntityBrushlistError;
F32 scaleY = dAtof(pToker->getToken());
// Skip last 3 tokens
//if (pToker->advanceToken(false) == false) goto EntityBrushlistError;
//if (pToker->advanceToken(false) == false) goto EntityBrushlistError;
//if (pToker->advanceToken(false) == false) goto EntityBrushlistError;
pToker->advanceToken(false);
pToker->advanceToken(false);
pToker->advanceToken(false);
// Compute the normal
VectorF normal;
VectorF t1, t2;
t1 = VectorF (points[0][0], points[0][1], points[0][2]) - VectorF (points[1][0], points[1][1], points[1][2]);
t2 = VectorF (points[2][0], points[2][1], points[2][2]) - VectorF (points[1][0], points[1][1], points[1][2]);
mCross (t1, t2, normal);
normal.normalize ();
quakeTextureVecs (normal, shiftU, shiftV, rot, scaleX, scaleY, &tGenX, &tGenY);
F32 width = F32(pBitmap->getWidth());
F32 height = F32(pBitmap->getHeight());
tGenX.x /= F32(pBitmap->getWidth());
tGenX.y /= F32(pBitmap->getWidth());
tGenX.z /= F32(pBitmap->getWidth());
tGenX.d /= F32(pBitmap->getWidth());
tGenY.x /= F32(pBitmap->getHeight());
tGenY.y /= F32(pBitmap->getHeight());
tGenY.z /= F32(pBitmap->getHeight());
tGenY.d /= F32(pBitmap->getHeight());
}
else
{
goto EntityBrushlistError;
}
// add it...
bool found = false;
for(U32 i = 0; !found && (i < geom.mTexGenEQs.size()); i++)
if(!dMemcmp(&geom.mTexGenEQs[i].planeX, &tGenX, sizeof(PlaneF)) &&
!dMemcmp(&geom.mTexGenEQs[i].planeY, &tGenY, sizeof(PlaneF)))
{
found = true;
rPlane.texGenIndex = i;
}
//
if(!found)
{
geom.mTexGenEQs.increment();
geom.mTexGenEQs.last().planeX = tGenX;
geom.mTexGenEQs.last().planeY = tGenY;
rPlane.texGenIndex = geom.mTexGenEQs.size() - 1;
}
pToker->advanceToken(true);
}
return true;
EntityBrushlistError:
return false;
}
U32 CSGBrush::addPlane(CSGPlane plane)
{
for (U32 i = 0; i < mPlanes.size(); i++)
{
if (mPlanes[i].flags == plane.flags &&
mPlanes[i].owningEntity == plane.owningEntity &&
mPlanes[i].planeEQIndex == plane.planeEQIndex &&
mPlanes[i].pTextureName == plane.pTextureName &&
mPlanes[i].texGenIndex == plane.texGenIndex)
return i;
}
mPlanes.increment();
mPlanes.last() = plane;
return mPlanes.size() - 1;
}
void CSGPlane::construct(const Point3D& Point1, const Point3D& Point2, const Point3D& Point3)
{
// |yi zi 1| |xi zi 1| |xi yi 1| |xi yi zi|
// |yj zj 1| x + |xj zj 1| y + |xj yj 1| z = |xj yj zj|
// |yk zk 1| |xk zk 1| |xk yk 1| |xk yk zk|
//
Point3D normal;
F64 dist;
normal.x = Point1.y * Point2.z - Point1.y * Point3.z +
Point3.y * Point1.z - Point2.y * Point1.z +
Point2.y * Point3.z - Point3.y * Point2.z;
normal.y = Point1.x * Point2.z - Point1.x * Point3.z +
Point3.x * Point1.z - Point2.x * Point1.z +
Point2.x * Point3.z - Point3.x * Point2.z;
normal.z = Point1.x * Point2.y - Point1.x * Point3.y +
Point3.x * Point1.y - Point2.x * Point1.y +
Point2.x * Point3.y - Point3.x * Point2.y;
dist = Point1.x * Point2.y * Point3.z - Point1.x * Point2.z * Point3.y +
Point1.y * Point2.z * Point3.x - Point1.y * Point2.x * Point3.z +
Point1.z * Point2.x * Point3.y - Point1.z * Point2.y * Point3.x;
normal.x = -normal.x;
normal.z = -normal.z;
//
planeEQIndex = gWorkingGeometry->insertPlaneEQ(normal, dist);
flags = 0;
}
//------------------------------------------------------------------------------
// Needs to insert new plane equation. parameter is positive amount
// to extrude outward.
void CSGPlane::extrude(F64 byAmount)
{
const PlaneEQ & eq = gWorkingGeometry->getPlaneEQ(planeEQIndex);
planeEQIndex = gWorkingGeometry->insertPlaneEQ(eq.normal, eq.dist - byAmount);
}
//------------------------------------------------------------------------------
bool CSGPlane::createBaseWinding(const Vector<U32>& rPoints)
{
return ::createBaseWinding(rPoints, getNormal(), &winding);
}
//------------------------------------------------------------------------------
// Try a more accurate version of this.
PlaneSide CSGPlane::sideCheckEpsilon(const Point3D& testPoint, F64 epsilon) const
{
F64 distance = distanceToPlane(testPoint);
if (distance < - epsilon)
return PlaneBack;
else if (distance > epsilon)
return PlaneFront;
else
return PlaneOn;
}
// Need more info for asserts.
const char* CSGPlane::sideCheckInfo(const Point3D & P, const char * msg, F64 E) const
{
F64 D = distanceToPlane(P);
const char * txt = D < -E ? "BACK" : (D > E ? "FRONT" : "ON");
return avar( "%s: Side=%s E=%lf D=%1.20lf P=(%lf,%lf,%lf)", msg, txt, E, D, P.x, P.y, P.z );
}
// See if this plane lies along an edge of the supplied winding. Return the
// points if so (they're needed), else return NULL for false.
//
// Maybe need a better point here.
Point3D * CSGPlane::sharesEdgeWith(const Winding & W) const
{
static Point3D edgePts[2];
for( U32 i = 0; i < W.numIndices; i++ )
{
edgePts[0] = gWorkingGeometry->getPoint(W.indices[i]);
// if( sideCheckEpsilon( edgePts[0] ) == PlaneOn )
if( whichSide( edgePts[0] ) == PlaneOn )
{
edgePts[1] = gWorkingGeometry->getPoint(W.indices[(i + 1) % W.numIndices]);
// if( sideCheckEpsilon( edgePts[1] ) == PlaneOn )
if( whichSide( edgePts[1] ) == PlaneOn )
return edgePts;
}
}
return NULL;
}
// Assuming this is a brush that has already been selfClip()d, make
// and return a new brush that is extruded version of this
// one (tho not clipped) in given direction.
//
// If doBoth, then extrude also in negative of direction.
//
// Adds additional planes on those edges which are boundaries with
// respect to the direction axis. That is, those edges which will
// will be on the outside of the shape perimeter when viewing
// along the given direction axis, and so planes need to be added
// to limit unwanted extrusion outside of the intended axis.
//
CSGBrush* CSGBrush::createExtruded(const Point3D & extrudeDir, bool doBoth) const
{
CSGBrush * newBrush = gBrushArena.allocateBrush();
newBrush->copyBrush( this );
for( U32 i = 0; i < mPlanes.size(); i++ )
{
// Get extrusion component along normal.
const Point3D & curNormal = mPlanes[i].getNormal();
F64 extrudeComponent = mDot( extrudeDir, curNormal );
if( mFabsD(extrudeComponent) > 0.001 )
{
const Winding & curWinding = mPlanes[i].winding;
// Look for planes that are opposite with respect to this
// direction and which have a shared edge. We create 'clamping'
// planes along such edges to avoid spikes.
for( U32 j = i + 1; j < mPlanes.size(); j++ )
{
if( mDot(mPlanes[j].getNormal(),extrudeDir) * extrudeComponent < -0.0001 )
{
if( Point3D * edgePts = mPlanes[j].sharesEdgeWith(curWinding) )
{
Point3D other = edgePts[0] + extrudeDir;
CSGPlane & rPlane = (extrudeComponent > 0)
?
newBrush->constructBrushPlane( other, edgePts[0], edgePts[1] )
:
newBrush->constructBrushPlane( edgePts[1], edgePts[0], other );
rPlane.pTextureName = mPlanes[0].pTextureName;
rPlane.xShift = 0;
rPlane.yShift = 0;
rPlane.rotation = 0;
rPlane.xScale = rPlane.yScale = 1.0;
}
}
}
if( extrudeComponent > 0 || doBoth )
newBrush->mPlanes[i].extrude( mFabsD( extrudeComponent ) );
}
}
AssertFatal( newBrush->mPlanes.size() >= mPlanes.size(),
"CSGBrush::createExtruded(): new brush shouldn't be smaller" );
return newBrush;
}
//------------------------------------------------------------------------------
bool CSGBrush::intersectPlanes(U32 i, U32 j, U32 k,
Point3D* pOutput)
{
AssertFatal(i < mPlanes.size() && j < mPlanes.size() && k < mPlanes.size() &&
i != j && i != k && j != k, "CSGBrush::intersectPlanes: bad plane indices");
CSGPlane& rPlane1 = mPlanes[i];
CSGPlane& rPlane2 = mPlanes[j];
CSGPlane& rPlane3 = mPlanes[k];
const PlaneEQ& rPlaneEQ1 = gWorkingGeometry->getPlaneEQ(rPlane1.planeEQIndex);
const PlaneEQ& rPlaneEQ2 = gWorkingGeometry->getPlaneEQ(rPlane2.planeEQIndex);
const PlaneEQ& rPlaneEQ3 = gWorkingGeometry->getPlaneEQ(rPlane3.planeEQIndex);
F64 bc = (rPlaneEQ2.normal.y * rPlaneEQ3.normal.z) - (rPlaneEQ3.normal.y * rPlaneEQ2.normal.z);
F64 ac = (rPlaneEQ2.normal.x * rPlaneEQ3.normal.z) - (rPlaneEQ3.normal.x * rPlaneEQ2.normal.z);
F64 ab = (rPlaneEQ2.normal.x * rPlaneEQ3.normal.y) - (rPlaneEQ3.normal.x * rPlaneEQ2.normal.y);
F64 det = (rPlaneEQ1.normal.x * bc) - (rPlaneEQ1.normal.y * ac) + (rPlaneEQ1.normal.z * ab);
if (mFabs(det) < 1e-7) {
// Parallel planes
return false;
}
F64 dc = (rPlaneEQ2.dist * rPlaneEQ3.normal.z) - (rPlaneEQ3.dist * rPlaneEQ2.normal.z);
F64 db = (rPlaneEQ2.dist * rPlaneEQ3.normal.y) - (rPlaneEQ3.dist * rPlaneEQ2.normal.y);
F64 ad = (rPlaneEQ3.dist * rPlaneEQ2.normal.x) - (rPlaneEQ2.dist * rPlaneEQ3.normal.x);
F64 detInv = 1.0 / det;
pOutput->x = ((rPlaneEQ1.normal.y * dc) - (rPlaneEQ1.dist * bc) - (rPlaneEQ1.normal.z * db)) * detInv;
pOutput->y = ((rPlaneEQ1.dist * ac) - (rPlaneEQ1.normal.x * dc) - (rPlaneEQ1.normal.z * ad)) * detInv;
pOutput->z = ((rPlaneEQ1.normal.y * ad) + (rPlaneEQ1.normal.x * db) - (rPlaneEQ1.dist * ab)) * detInv;
return true;
}
//------------------------------------------------------------------------------
bool CSGBrush::selfClip()
{
// MDFFIX: Really hacky way of doing it for now but it will work
ConvexBrush brush;
CopyCSGToConvex(this, &brush);
CopyConvexToCSG(&brush, this);
return true;
}
void CSGBrush::copyBrush(const CSGBrush* pCopy)
{
mPlanes = pCopy->mPlanes;
mIsAmbiguous = pCopy->mIsAmbiguous;
mBrushType = pCopy->mBrushType;
mMinBound = pCopy->mMinBound;
mMaxBound = pCopy->mMaxBound;
brushId = pCopy->brushId;
materialType = pCopy->materialType;
}
//------------------------------------------------------------------------------
bool CSGBrush::disambiguate()
{
AssertFatal(mIsAmbiguous == false, "error, already disambiguated?");
for (U32 i = 0; i < mPlanes.size(); i++) {
for (U32 j = i + 1; j < mPlanes.size();) {
// Compare i to j. if j == i, with different tex parameters, increment
// ambiguous mInteriorRes->mBrushes (once only), and remove the plane.
//
CSGPlane& rPlane1 = mPlanes[i];
CSGPlane& rPlane2 = mPlanes[j];
if (rPlane1.planeEQIndex == rPlane2.planeEQIndex) {
// Possible ambiguous plane pairing...
//
if (rPlane1.pTextureName != rPlane2.pTextureName ||
rPlane1.xShift != rPlane2.xShift ||
rPlane1.yShift != rPlane2.yShift ||
rPlane1.rotation != rPlane2.rotation ||
rPlane1.xScale != rPlane2.xScale ||
rPlane1.yScale != rPlane2.yScale) {
mIsAmbiguous = true;
} else {
// Same texture parameters, should be fine, just erase it...
//
}
mPlanes.erase(j);
} else {
// Plane is fine...
j++;
}
}
}
return mIsAmbiguous;
}
//------------------------------------------------------------------------------
/*CSGPlane& CSGBrush::constructBrushPlane(const Point3I& rPoint1,
const Point3I& rPoint2,
const Point3I& rPoint3)
{
mPlanes.increment();
CSGPlane& rPlane = mPlanes.last();
rPlane.flags = 0;
rPlane.owningEntity = NULL;
rPlane.winding.numNodes = 0;
rPlane.winding.numZoneIds = 0;
Point3D Point1(rPoint1.x, rPoint1.y, rPoint1.z);
Point3D Point2(rPoint2.x, rPoint2.y, rPoint2.z);
Point3D Point3(rPoint3.x, rPoint3.y, rPoint3.z);
rPlane.construct(Point1, Point2, Point3);
if (rPlane.getNormal().x == 0 && rPlane.getNormal().y == 0 && rPlane.getNormal().z == 0) {
AssertISV(false, "Error, degenerate plane (colinear points)");
mPlanes.decrement();
return *((CSGPlane*)NULL);
}
return rPlane;
}*/
CSGPlane& CSGBrush::constructBrushPlane(const Point3D& Point1,
const Point3D& Point2,
const Point3D& Point3)
{
mPlanes.increment();
CSGPlane& rPlane = mPlanes.last();
rPlane.flags = 0;
rPlane.owningEntity = NULL;
rPlane.winding.numNodes = 0;
rPlane.winding.numZoneIds = 0;
rPlane.construct(Point1, Point2, Point3);
if (rPlane.getNormal().x == 0 && rPlane.getNormal().y == 0 && rPlane.getNormal().z == 0) {
AssertISV(false, "Error, degenerate plane (colinear points)");
mPlanes.decrement();
return *((CSGPlane*)NULL);
}
return rPlane;
}
bool CSGBrush::isEquivalent(const CSGBrush& testBrush) const
{
for (U32 i = 0; i < mPlanes.size(); i++) {
U32 j;
for (j = 0; j < testBrush.mPlanes.size(); j++) {
if (testBrush.mPlanes[j].planeEQIndex == mPlanes[i].planeEQIndex)
break;
}
if (j == testBrush.mPlanes.size())
return false;
}
return true;
}

View File

@ -0,0 +1,180 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _CSGBRUSH_H_
#define _CSGBRUSH_H_
//Includes
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#endif
#ifndef _MORIANBASICS_H_
#include "map2dif plus/morianBasics.h"
#endif
#ifndef _EDITGEOMETRY_H_
#include "map2dif plus/editGeometry.h"
#endif
#ifndef _MORIANUTIL_H_
#include "map2dif plus/morianUtil.h"
#endif
#ifndef _MMATHFN_H_
#include "math/mMathFn.h"
#endif
#include "collision/convexBrush.h"
bool parseBrush (CSGBrush& brush, Tokenizer* pToker, EditGeometry& geom);
void CopyConvexToCSG(ConvexBrush* convex, CSGBrush* csg);
void CopyCSGToConvex(CSGBrush* csg, ConvexBrush* convex);
U32 addTexGen(PlaneF tGenX, PlaneF tGenY);
class CSGPlane {
public:
// Plane equation given as mDot(normal, (x, y, z)) = d;
U32 planeEQIndex;
const char* pTextureName;
F32 xShift;
F32 yShift;
F32 rotation;
F32 xScale;
F32 yScale;
U32 texGenIndex;
Winding winding;
U32 flags;
EditGeometry::Entity* owningEntity;
public:
const Point3D& getNormal() const;
F64 getDist() const;
PlaneSide whichSide(const Point3D&) const;
PlaneSide whichSideLow(const Point3D&) const;
F64 distanceToPlane(const Point3D&) const;
void snapPointToPlane(Point3D&) const;
Point3D * sharesEdgeWith(const Winding &) const;
void extrude(F64 byAmount);
PlaneSide sideCheckEpsilon(const Point3D& testPoint, F64 E=0.000000001) const;
const char* sideCheckInfo(const Point3D & point, const char * msg, F64 epsilon) const;
bool createBaseWinding(const Vector<U32>&);
bool clipWindingToPlaneFront(const U32 planeEQIndex);
void construct(const Point3D& Point1, const Point3D& Point2, const Point3D& Point3);
enum Flags {
Inserted = 1 << 0
};
void markInserted() { flags |= Inserted; }
void markUninserted() { flags &= ~Inserted; }
bool isInserted() const { return (flags & Inserted) != 0; }
};
class CSGBrush
{
public:
bool intersectPlanes(U32 i, U32 j, U32 k, Point3D* pOutput);
public:
CSGBrush() : mIsAmbiguous(false) { }
Vector<CSGPlane> mPlanes;
Point3D mMinBound;
Point3D mMaxBound;
bool mIsAmbiguous;
BrushType mBrushType;
U32 brushId;
U32 materialType;
CSGBrush* pNext;
public:
CSGPlane& constructBrushPlane(const Point3I& rPoint1,
const Point3I& rPoint2,
const Point3I& rPoint3);
CSGPlane& constructBrushPlane(const Point3D&, const Point3D&,const Point3D&);
bool disambiguate();
bool selfClip();
U32 addPlane(CSGPlane plane);
bool doesBBoxSersect(const CSGBrush& testBrush) const;
bool isEquivalent(const CSGBrush& testBrush) const;
bool noMoreInsertables() const;
public:
void copyBrush(const CSGBrush* pCopy);
CSGBrush * createExtruded(const Point3D & extDir, bool bothWays) const;
};
//------------------------------------------------------------------------------
inline const Point3D& CSGPlane::getNormal() const
{
return gWorkingGeometry->getPlaneEQ(planeEQIndex).normal;
}
inline F64 CSGPlane::getDist() const
{
AssertFatal(gWorkingGeometry != NULL, "No working geometry?");
return gWorkingGeometry->getPlaneEQ(planeEQIndex).dist;
}
inline PlaneSide CSGPlane::whichSide(const Point3D& testPoint) const
{
return gWorkingGeometry->getPlaneEQ(planeEQIndex).whichSide(testPoint);
}
inline PlaneSide CSGPlane::whichSideLow(const Point3D& testPoint) const
{
return gWorkingGeometry->getPlaneEQ(planeEQIndex).whichSideLow(testPoint);
}
inline F64 CSGPlane::distanceToPlane(const Point3D& rPoint) const
{
return gWorkingGeometry->getPlaneEQ(planeEQIndex).distanceToPlane(rPoint);
}
inline bool CSGPlane::clipWindingToPlaneFront(const U32 _planeEQIndex)
{
return ::clipWindingToPlaneFront(&winding, _planeEQIndex);
}
inline void CSGPlane::snapPointToPlane(Point3D& rPoint) const
{
F64 distance = mDot(rPoint, getNormal()) + getDist();
rPoint -= getNormal() * distance;
}
inline bool CSGBrush::doesBBoxSersect(const CSGBrush& testBrush) const
{
if (testBrush.mMinBound.x > mMaxBound.x ||
testBrush.mMinBound.y > mMaxBound.y ||
testBrush.mMinBound.z > mMaxBound.z)
return false;
if (testBrush.mMaxBound.x < mMinBound.x ||
testBrush.mMaxBound.y < mMinBound.y ||
testBrush.mMaxBound.z < mMinBound.z)
return false;
return true;
}
inline bool CSGBrush::noMoreInsertables() const
{
for (U32 i = 0; i < mPlanes.size(); i++)
if (mPlanes[i].isInserted() == false)
return false;
return true;
}
#endif //_CSGBRUSH_H_

View File

@ -0,0 +1,76 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "map2dif plus/editGeometry.h"
#include "map2dif plus/editFloorPlanRes.h"
void EditFloorPlanResource::pushArea(const Winding & winding, U32 planeEQ)
{
mWindings.push_back(winding);
mPlaneEQs.push_back(planeEQ);
}
void EditFloorPlanResource::clearFloorPlan()
{
mPlaneTable.clear();
mPointTable.clear();
mPointLists.clear();
mAreas.clear();
}
// Build data to persist.
void EditFloorPlanResource::constructFloorPlan()
{
UniqueVector planes, points;
U32 i, j, maxPointIndex=0, maxPlaneIndex=0, totalPoints=0;
clearFloorPlan();
// Get the lists of unique points and planes, figure out max for remap tables.
for( i = 0; i < mWindings.size(); i++ )
{
const Winding & W = mWindings[i];
for( j = 0; j < W.numIndices; j++, totalPoints++ )
{
if( W.indices[j] > maxPointIndex )
maxPointIndex = W.indices[j];
points.pushBackUnique( W.indices[j] );
}
if( mPlaneEQs[i] > maxPlaneIndex )
maxPlaneIndex = mPlaneEQs[i];
planes.pushBackUnique( mPlaneEQs[i] );
}
// Allocate index remap tables
Vector<U32> remapPoints; remapPoints.setSize(maxPointIndex + 1);
Vector<U32> remapPlanes; remapPlanes.setSize(maxPlaneIndex + 1);
// Build the index remap tables while copying over the point and plane
// vector data into the FloorPlanResource.
for( i = 0, mPointTable.reserve(points.size()); i < points.size(); i++ )
{
Point3D point = gWorkingGeometry->getPoint(points[i]) / 32.0;
mPointTable.push_back( Point3F(point.x,point.y,point.z) );
remapPoints[ points[i] ] = i;
}
for( i = 0, mPlaneTable.reserve(planes.size()); i < planes.size(); i++ )
{
PlaneEQ pl64 = gWorkingGeometry->getPlaneEQ(planes[i]);
Point3F norm ( pl64.normal.x, pl64.normal.y, pl64.normal.z );
F64 dist ( pl64.dist / 32.0 );
mPlaneTable.push_back( PlaneF(norm.x, norm.y, norm.z, dist) );
remapPlanes[ planes[i] ] = i;
}
// Construct the areas
for( i = 0, mPointLists.reserve(totalPoints); i < mWindings.size(); i++ )
{
const Winding & W = mWindings[i];
Area area(W.numIndices, mPointLists.size(), remapPlanes[mPlaneEQs[i]] );
mAreas.push_back( area );
for( j = 0; j < W.numIndices; j++ )
mPointLists.push_back( remapPoints[ W.indices[j] ] );
}
}

View File

@ -0,0 +1,30 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _H_EDITFLOORPLANRES_
#define _H_EDITFLOORPLANRES_
#ifndef _FLOORPLANRES_H_
#include "interior/floorPlanRes.h"
#endif
class EditFloorPlanResource : public FloorPlanResource
{
protected:
Vector<Winding> mWindings;
Vector<U32> mPlaneEQs;
void clearFloorPlan();
public:
// In Nav graph generation mode, windings are saved during the BSP process.
void pushArea(const Winding & winding, U32 planeEQ);
// When done, this assembles the FloorPlanResource data.
// Uses gWorkingGeometry...
void constructFloorPlan();
};
#endif // _H_EDITFLOORPLANRES_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,593 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _EDITGEOMETRY_H_
#define _EDITGEOMETRY_H_
//Includes
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#endif
#ifndef _PLATFORMASSERT_H_
#include "platform/platformAssert.h"
#endif
#ifndef _MORIANBASICS_H_
#include "map2dif plus/morianBasics.h"
#endif
#ifndef _MORIANUTIL_H_
#include "map2dif plus/morianUtil.h"
#endif
#ifndef _BSPNODE_H_
#include "map2dif plus/bspNode.h"
#endif
#ifndef _MPLANE_H_
#include "math/mPlane.h"
#endif
#ifndef _COLOR_H_
#include "core/color.h"
#endif
#ifndef _EDITFLOORPLANRES_H_
#include "map2dif plus/editFloorPlanRes.h"
#endif
#include "interior/interiorMap.h"
#include "interior/interiorResObjects.h"
class Tokenizer;
class Interior;
class CSGBrush;
class GBitmap;
class CSGPlane;
class WorldSpawnEntity;
class MirrorSurfaceEntity;
class TriggerEntity;
class DoorEntity;
class ForceFieldEntity;
class PathStartEntity;
class SpecialNodeEntity;
class GameEntity;
class InteriorResource;
struct TempHullReference;
//------------------------------------------------------------------------------
class EditGeometry
{
friend class EditBSPNode;
friend class Lighting;
friend void parseBrushList(Vector<CSGBrush*>& Brushes, Tokenizer* pToker);
//-------------------------------------- first class structures
public:
struct Portal {
U32 portalId;
S32 planeEQIndex;
S32 frontZone;
S32 backZone;
bool passAmbientLight;
Vector<Winding> windings;
Point3D mMin;
Point3D mMax;
Point3D x;
Point3D y;
};
struct Zone {
U32 zoneId;
bool active;
bool ambientLit;
Vector<U32> referencingPortals;
};
struct Surface {
bool isMemberOfZone(U32);
U32 uniqueKey;
U32 planeIndex;
U32 textureIndex;
Winding winding;
Winding originalWinding;
U32 texGenIndex;
U32 lMapDimX;
U32 lMapDimY;
U32 offsetX;
U32 offsetY;
bool lmapTexGenSwapped;
F32 lmapTexGenX[4];
F32 lmapTexGenY[4];
F32 tempScale[2];
GBitmap* pLMap;
GBitmap* pNormalLMap;
GBitmap* pAlarmLMap;
U32 sheetIndex;
U32 alarmSheetIndex;
U32 flags;
U32 fanMask;
U32 numLights;
U32 stateDataStart;
bool mustPortalExtend;
U32 temptemptemp;
};
struct NullSurface {
U32 planeIndex;
Winding winding;
U32 flags;
};
class Entity {
public:
Entity() { }
virtual ~Entity() { };
InteriorDict mDictionary;
virtual bool parseEntityDescription(InteriorMapResource::Entity* ent) = 0;
virtual BrushType getBrushType() = 0;
virtual bool isPointClass() const = 0;
virtual const char* getName() const = 0;
virtual const Point3D& getOrigin() const = 0;
virtual void grabSurface(Surface&) { }
};
struct PlaneHashEntry {
U32 planeIndex;
PlaneHashEntry* pNext;
};
struct PointHashEntry {
U32 pointIndex;
PointHashEntry* pNext;
};
struct TexGenPlanes {
PlaneF planeX;
PlaneF planeY;
};
//-------------------------------------- animated lighting structures
public:
struct StateData {
GBitmap* pLMap; // 8-Bit intensity map
U32 surfaceIndex; // Surface affected by this state
U32 stateDataIndex; // index
};
struct LightState {
ColorI color;
F32 duration;
Vector<StateData> stateData;
};
struct AnimatedLight {
char* name;
U32 type; // From Interior::LightType
bool alarm; // entity->mAlarmStatus != NormalOnly
Vector<LightState*> states;
AnimatedLight() : name(NULL), type(0) { }
};
Vector<AnimatedLight*> mAnimatedLights;
//-------------------------------------- arenas
public:
class PlaneHashArena {
Vector<PlaneHashEntry*> mBuffers;
U32 arenaSize;
PlaneHashEntry* currBuffer;
U32 currPosition;
public:
PlaneHashArena(U32 _arenaSize);
~PlaneHashArena();
PlaneHashEntry* allocateEntry();
};
class PointHashArena {
Vector<PointHashEntry*> mBuffers;
U32 arenaSize;
PointHashEntry* currBuffer;
U32 currPosition;
public:
PointHashArena(U32 _arenaSize);
~PointHashArena();
PointHashEntry* allocateEntry();
};
//------------------------------------------------------------------------------
//-------------------------------------- DATA
private:
//-------------------------------------- Error variables
U32 mNumAmbiguousBrushes;
U32 mNumOrphanPolys;
//-------------------------------------- Brushes and texture vars
public:
Point3D mMinBound;
Point3D mMaxBound;
public:
U32 mCurrBrushId;
U32 mSurfaceKey;
Vector<CSGBrush*> mStructuralBrushes;
Vector<CSGBrush*> mDetailBrushes;
Vector<CSGBrush*> mSpecialCollisionBrushes;
Vector<CSGBrush*> mVehicleCollisionBrushes;
Vector<NullSurface> mVehicleNullSurfaces;
Vector<CSGBrush*> mPortalBrushes;
Vector<Entity*> mPortalEntities;
Vector<char*> mTextureNames;
Vector<GBitmap*> mTextures;
Vector<Portal*> mPortals;
Vector<Zone*> mZones;
U32 mOutsideZoneIndex;
Vector<TexGenPlanes> mTexGenEQs;
Vector<Surface> mSurfaces;
Vector<NullSurface> mNullSurfaces;
Vector<GBitmap*> mLightmaps;
bool mHasAlarmState;
//-------------------------------------- Nav Graph Generation
bool mPerformExtrusion;
bool mGenerateGraph;
bool mHashPlanes, mHashPoints;
UniqueVector mGraphSurfacePts;
EditFloorPlanResource mEditFloorPlanRes;
//-------------------------------------- Planes and Points
PlaneHashEntry mPlaneHashTable[1 << 12];
Vector<PlaneEQ> mPlaneEQs;
Vector<S32> mPlaneRemaps;
U16 remapPlaneIndex(S32 inPlaneIndex);
U16 remapVehiclePlaneIndex(S32 inPlaneIndex, Interior*);
PointHashEntry mPointHashTable[1 << 12];
Vector<Point3D> mPoints;
struct ExportPointMapEntry {
U32 originalIndex;
U32 runtimeIndex;
};
Vector<ExportPointMapEntry> mExportPointMap;
Vector<ExportPointMapEntry> mVehicleExportPointMap;
public:
PlaneHashArena mPlaneHashArena;
PointHashArena mPointHashArena;
//-------------------------------------- BSP info
public:
NodeArena mNodeArena;
VisLinkArena mVisLinkArena;
private:
EditBSPNode* mBSPRoot;
//-------------------------------------- Entity information
public:
WorldSpawnEntity* mWorldEntity;
Vector<Entity*> mEntities;
//------------------------------------------------------------------------------
//-------------------------------------- FUNCTIONS
private:
Entity* parseEntity(Tokenizer* pToker);
const Entity* getNamedEntity(const char*) const;
public:
const char* insertTexture(const char*);
void fixSparkles();
void convertToStrips();
void markSurfaceOriginalPoints();
void sortSurfaces();
void sortLitSurfaces();
private:
void createBrushPolys();
void buildBSP();
void findOutsideZone();
void enterPortalZoneRefs();
void ambientVisitZone(const U32 zone);
void floodAmbientLight();
public:
void preprocessLighting();
private:
void postProcessLighting(Interior*);
U32 exportIntensityMap(Interior* pRuntime, GBitmap*);
void exportLightsToRuntime(Interior* pRuntime);
void exportDMLToRuntime(Interior* pRuntime, Vector<char*>&);
U16 exportBSPToRuntime(Interior* pRuntime, EditBSPNode* pNode);
void exportWindingToRuntime(Interior* pRuntime, const Winding& rWinding);
void exportVehicleWindingToRuntime(Interior* pRuntime, const Winding& rWinding);
U32 exportPointToRuntime(Interior* pRuntime, const U32 pointIndex);
void exportHullToRuntime(Interior* pRuntime, CSGBrush* pBrush);
U32 exportVehiclePointToRuntime(Interior* pRuntime, const U32 pointIndex);
void exportVehicleHullToRuntime(Interior* pRuntime, CSGBrush* pBrush);
void exportHullBins(Interior* pRuntime);
void exportPlanes(Interior*);
U32 exportEmitStringToRuntime(Interior* pRuntime,
const U8* pString,
const U32 stringLen);
U32 exportVehicleEmitStringToRuntime(Interior* pRuntime,
const U8* pString,
const U32 stringLen);
bool fixTJuncs();
void rotateSurfaceToNonColinear(Surface& surface);
void dumpSurfaceToRuntime(Interior* pRuntime,
Surface& editSurface);
void dumpNullSurfaceToRuntime(Interior* pRuntime,
NullSurface& editSurface);
void dumpVehicleNullSurfaceToRuntime(Interior* pRuntime,
NullSurface& editSurface);
void dumpMirrorToRuntime(Interior* pRuntime,
MirrorSurfaceEntity* pEntity);
void dumpTriggerToRuntime(Interior* pRuntime,
InteriorResource* pResource,
TriggerEntity* pEntity);
void dumpPathToRuntime(Interior* pRuntime,
InteriorResource* pResource,
PathStartEntity* pEntity);
//void dumpAISpecialToRuntime(Interior* pRuntime,
// InteriorResource* pResource,
// SpecialNodeEntity* pEntity);
void dumpGameEntityToRuntime(Interior* pRuntime,
InteriorResource* pResource,
GameEntity* pEntity);
//void dumpDoorToRuntime(Interior* /*pRuntime*/,
// InteriorResource* pResource,
// DoorEntity* pEntity);
//void dumpForceFieldToRuntime(Interior* /*pRuntime*/,
// InteriorResource* pResource,
// ForceFieldEntity* pEntity);
void fillInLightmapInfo(Surface& rSurface);
void adjustLMapTexGen(Surface&);
void createBrushSurfaces(const CSGBrush& brush);
void createBoundingVolumes(Interior* pRuntime);
public:
EditGeometry();
~EditGeometry();
//-------------------------------------- High level functions
public:
bool parseMapFile(Tokenizer*);
bool createBSP();
void createSurfaces();
void markEmptyZones();
void packLMaps();
void nudge();
void computeLightmaps(const bool alarmMode);
bool exportToRuntime(Interior*, InteriorResource*);
U16 getMaterialIndex(const char* texName) const;
//-------------------------------------- Point/Plane buffer functions
public:
U32 insertPlaneEQ(const Point3D& normal, const F64);
const U32 getPlaneInverse(const U32 planeIndex);
const PlaneEQ& getPlaneEQ(const U32) const;
bool isCoplanar(const U32, const U32) const;
U32 insertPoint(const Point3D&);
const Point3D& getPoint(const U32) const;
void giftWrapPortal(Winding& winding, Portal* portal);
//-------------------------------------- NavGraph functions
public:
void setGraphGeneration(bool generate=false,bool extrude=false);
void gatherLinksForGraph(EditBSPNode * pLeafNode);
U32 writeGraphInfo();
void doGraphExtrusions(Vector<CSGBrush*> & brushList);
void xferDetailToStructural();
//-------------------------------------- Statistics
public:
U32 getTotalNumBrushes() const;
U32 getNumStructuralBrushes() const;
U32 getNumDetailBrushes() const;
U32 getNumPortalBrushes() const;
U32 getNumAmbiguousBrushes() const;
U32 getNumOrphanPolys() const;
U32 getNumUniquePlanes() const;
U32 getNumUniquePoints() const;
U32 getNumZones() const;
U32 getNumSurfaces() const;
const Point3D& getMinBound() const;
const Point3D& getMaxBound() const;
};
extern EditGeometry* gWorkingGeometry;
inline U32 EditGeometry::getNumStructuralBrushes() const
{
return mStructuralBrushes.size();
}
inline U32 EditGeometry::getNumDetailBrushes() const
{
return mDetailBrushes.size();
}
inline U32 EditGeometry::getNumPortalBrushes() const
{
return mPortalBrushes.size();
}
inline U32 EditGeometry::getNumAmbiguousBrushes() const
{
return mNumAmbiguousBrushes;
}
inline U32 EditGeometry::getNumOrphanPolys() const
{
return mNumOrphanPolys;
}
inline U32 EditGeometry::getTotalNumBrushes() const
{
return getNumStructuralBrushes() + getNumDetailBrushes() + getNumPortalBrushes();
}
inline U32 EditGeometry::getNumUniquePlanes() const
{
return mPlaneEQs.size() / 2;
}
inline U32 EditGeometry::getNumUniquePoints() const
{
return mPoints.size();
}
inline U32 EditGeometry::getNumZones() const
{
return mZones.size();
}
inline U32 EditGeometry::getNumSurfaces() const
{
return mSurfaces.size();
}
inline const Point3D& EditGeometry::getMinBound() const
{
return mMinBound;
}
inline const Point3D& EditGeometry::getMaxBound() const
{
return mMaxBound;
}
//------------------------------------------------------------------------------
inline const PlaneEQ& EditGeometry::getPlaneEQ(const U32 planeIndex) const
{
AssertFatal(planeIndex < mPlaneEQs.size(), "EditGeometry::getPlaneEQ: planeIndex out of range");
return mPlaneEQs[planeIndex];
}
inline bool EditGeometry::isCoplanar(const U32 planeIndex1, const U32 planeIndex2) const
{
AssertFatal(planeIndex1 < mPlaneEQs.size() && planeIndex2 < mPlaneEQs.size(),
"EditGeometry::isCoplanar: planeIndex out of range");
return (planeIndex1 & ~1) == (planeIndex2 & ~1);
}
inline const Point3D& EditGeometry::getPoint(const U32 index) const
{
AssertFatal(index < mPoints.size(), "EditGeometry::getPoint: out of bounds point index");
return mPoints[index];
}
inline const U32 EditGeometry::getPlaneInverse(const U32 planeIndex)
{
return (planeIndex ^ 0x1);
}
//------------------------------------------------------------------------------
inline EditGeometry::PlaneHashEntry* EditGeometry::PlaneHashArena::allocateEntry()
{
if (currPosition < arenaSize)
return &currBuffer[currPosition++];
// Need to add another buffer
currBuffer = new EditGeometry::PlaneHashEntry[arenaSize];
currPosition = 1;
mBuffers.push_back(currBuffer);
return currBuffer;
}
inline EditGeometry::PointHashEntry* EditGeometry::PointHashArena::allocateEntry()
{
if (currPosition < arenaSize)
return &currBuffer[currPosition++];
// Need to add another buffer
currBuffer = new EditGeometry::PointHashEntry[arenaSize];
currPosition = 1;
mBuffers.push_back(currBuffer);
return currBuffer;
}
//------------------------------------------------------------------------------
inline F64 PlaneEQ::distanceToPlane(const Point3D& rPoint) const
{
return mDot(rPoint, normal) + dist;
}
inline PlaneSide PlaneEQ::whichSide(const Point3D& testPoint) const
{
F64 distance = distanceToPlane(testPoint);
if (distance < -gcPlaneDistanceEpsilon)
return PlaneBack;
else if (distance > gcPlaneDistanceEpsilon)
return PlaneFront;
else
return PlaneOn;
}
inline PlaneSide PlaneEQ::whichSideLow(const Point3D& testPoint) const
{
F64 distance = distanceToPlane(testPoint);
if (distance < -gcPointEpsilon)
return PlaneBack;
else if (distance > gcPointEpsilon)
return PlaneFront;
else
return PlaneOn;
}
inline PlaneSide PlaneEQ::whichSidePerfect(const Point3D& testPoint) const
{
F64 distance = distanceToPlane(testPoint);
if (distance < 0)
return PlaneBack;
else if (distance > 0)
return PlaneFront;
else
return PlaneOn;
}
#endif //_EDITGEOMETRY_H_

View File

@ -0,0 +1,83 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "dgl/gBitmap.h"
#include "interior/interior.h"
#include "map2dif plus/editInteriorRes.h"
namespace {
int FN_CDECL detailCmp(const void* p1, const void* p2)
{
const Interior* pInterior1 = *(reinterpret_cast<Interior**>(const_cast<void*>(p1)));
const Interior* pInterior2 = *(reinterpret_cast<Interior**>(const_cast<void*>(p2)));
return S32(pInterior1->getDetailLevel()) - S32(pInterior2->getDetailLevel());
}
} // namespace {}
void EditInteriorResource::sortDetailLevels()
{
AssertFatal(mDetailLevels.size() != 0, "Error, no detail levels to sort!");
dQsort(mDetailLevels.address(), mDetailLevels.size(), sizeof(Interior*), detailCmp);
for (U32 i = 0; i < mDetailLevels.size(); i++) {
mDetailLevels[i]->mDetailLevel = i;
if (i == 0)
continue;
AssertFatal(mDetailLevels[i]->getMinPixels() < mDetailLevels[i - 1]->getMinPixels(),
avar("Error, detail %d has greater or same minpixels as %d! (%d %d)",
i, i - 1, mDetailLevels[i]->getMinPixels(),
mDetailLevels[i - 1]->getMinPixels()));
}
}
void EditInteriorResource::addDetailLevel(Interior* pInterior)
{
mDetailLevels.push_back(pInterior);
}
void EditInteriorResource::setPreviewBitmap(GBitmap* bmp)
{
delete mPreviewBitmap;
mPreviewBitmap = bmp;
}
void EditInteriorResource::insertTrigger(InteriorResTrigger* pTrigger)
{
mTriggers.push_back(pTrigger);
}
void EditInteriorResource::insertPathedChild(InteriorPathFollower *pPathFollower)
{
mInteriorPathFollowers.push_back(pPathFollower);
}
void EditInteriorResource::insertGameEntity(ItrGameEntity *ent)
{
mGameEntities.push_back(ent);
}
U32 EditInteriorResource::insertSubObject(Interior* pInterior)
{
mSubObjects.push_back(pInterior);
return mSubObjects.size() - 1;
}
U32 EditInteriorResource::insertField(ForceField* object)
{
mForceFields.push_back(object);
return mForceFields.size() - 1;
}
U32 EditInteriorResource::insertSpecialNode(AISpecialNode* object)
{
mAISpecialNodes.push_back(object);
return mAISpecialNodes.size() - 1;
}

View File

@ -0,0 +1,30 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _EDITINTERIORRES_H_
#define _EDITINTERIORRES_H_
#ifndef _INTERIORRES_H_
#include "interior/interiorRes.h"
#endif
class EditInteriorResource : public InteriorResource
{
public:
void sortDetailLevels();
void addDetailLevel(Interior*);
void setPreviewBitmap(GBitmap*);
void insertTrigger(InteriorResTrigger* pTrigger);
void insertPath(InteriorPath* pPath);
void insertPathedChild(InteriorPathFollower * pPathFollower);
U32 insertSubObject(Interior* pInterior);
U32 insertField(ForceField*);
U32 insertSpecialNode(AISpecialNode*);
void insertGameEntity(ItrGameEntity*);
};
#endif // _H_EDITINTERIORRES_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,470 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _ENTITYTYPES_H_
#define _ENTITYTYPES_H_
//Includes
#ifndef _MORIANBASICS_H_
#include "map2dif plus/morianBasics.h"
#endif
#ifndef _EDITGEOMETRY_H_
#include "map2dif plus/editGeometry.h"
#endif
#ifndef _COLOR_H_
#include "core/color.h"
#endif
#ifndef _MMATRIX_H_
#include "math/mMatrix.h"
#endif
#ifndef _POLYHEDRON_H_
#include "collision/polyhedron.h"
#endif
//------------------------------------------------------------------------------
//-------------------------------------- Brush based entities
class WorldSpawnEntity : public EditGeometry::Entity
{
public:
U32 mDetailNumber;
U32 mMinPixels;
F32 mGeometryScale;
F32 mLumelScale;
ColorF mAmbientColor;
ColorF mEmergencyAmbientColor;
char mWadPrefix[256];
public:
WorldSpawnEntity();
~WorldSpawnEntity();
bool parseEntityDescription(InteriorMapResource::Entity* ent);
BrushType getBrushType();
bool isPointClass() const;
const char* getName() const;
const Point3D& getOrigin() const;
static const char* getClassName();
};
class DetailEntity : public EditGeometry::Entity
{
public:
DetailEntity();
~DetailEntity();
bool parseEntityDescription(InteriorMapResource::Entity* ent);
BrushType getBrushType();
bool isPointClass() const;
const char* getName() const;
const Point3D& getOrigin() const;
static const char* getClassName();
};
class CollisionEntity : public EditGeometry::Entity
{
public:
CollisionEntity();
~CollisionEntity();
bool parseEntityDescription(InteriorMapResource::Entity* ent);
BrushType getBrushType();
bool isPointClass() const;
const char* getName() const;
const Point3D& getOrigin() const;
static const char* getClassName();
};
class PortalEntity : public EditGeometry::Entity
{
public:
PortalEntity();
~PortalEntity();
bool passAmbientLight;
bool parseEntityDescription(InteriorMapResource::Entity* ent);
BrushType getBrushType();
bool isPointClass() const;
const char* getName() const;
const Point3D& getOrigin() const;
static const char* getClassName();
};
//------------------------------------------------------------------------------
//-------------------------------------- Lighting and Target types
class TargetEntity : public EditGeometry::Entity
{
public:
char mTargetName[256];
Point3D mOrigin;
public:
TargetEntity();
~TargetEntity();
bool parseEntityDescription(InteriorMapResource::Entity* ent);
BrushType getBrushType();
bool isPointClass() const { return(true); }
const char* getName() const { return(mTargetName); }
const Point3D& getOrigin() const { return(mOrigin); }
static const char* getClassName() { return("target"); }
};
class BaseLightEmitterEntity : public EditGeometry::Entity
{
public:
enum FalloffType {
Distance = 0,
Linear = 1
};
char mTargetLight[256];
U32 mStateIndex;
Point3D mOrigin;
BaseLightEmitterEntity();
bool isPointClass() const { return(true); }
const char* getName() const { return(""); }
const Point3D& getOrigin() const { return(mOrigin); }
BrushType getBrushType();
};
class PointEmitterEntity : public BaseLightEmitterEntity
{
public:
BaseLightEmitterEntity::FalloffType mFalloffType;
U32 mFalloff1;
U32 mFalloff2;
U32 mFalloff3;
PointEmitterEntity();
bool parseEntityDescription(InteriorMapResource::Entity* ent);
static const char* getClassName() { return("light_emitter_point"); }
};
class SpotEmitterEntity : public BaseLightEmitterEntity
{
public:
BaseLightEmitterEntity::FalloffType mFalloffType;
U32 mFalloff1;
U32 mFalloff2;
U32 mFalloff3;
Point3D mDirection;
F32 mInnerAngle;
F32 mOuterAngle;
SpotEmitterEntity();
bool parseEntityDescription(InteriorMapResource::Entity* ent);
static const char * getClassName() { return("light_emitter_spot"); }
};
//------------------------------------------------------------------------------
class BaseLightEntity : public EditGeometry::Entity
{
public:
enum Speed {
VerySlow = 0,
Slow = 1,
Normal = 3,
Fast = 4,
VeryFast = 5
};
// enum Flags {
// AutoStart = 1 << 0,
// LoopToEndFrame = 1 << 1,
// RandomFrame = 1 << 2,
//
// FlagMask = AutoStart | LoopToEndFrame | RandomFrame
// };
enum AlarmStatus {
NormalOnly = 0,
AlarmOnly = 1,
Both = 2
};
U32 mFlags;
AlarmStatus mAlarmStatus;
public:
Point3D mOrigin;
char mLightName[256];
BaseLightEntity();
bool isPointClass() const { return(true); }
const char* getName() const { return(mLightName); }
const Point3D& getOrigin() const { return(mOrigin); }
BrushType getBrushType();
};
class LightEntity : public BaseLightEntity
{
public:
struct StateInfo {
enum {
DurationValid = 1 << 0,
ColorValid = 1 << 1,
Valid = DurationValid | ColorValid,
MaxStates = 32,
};
F32 mDuration;
ColorF mColor;
U8 mFlags;
};
U32 mNumStates;
StateInfo mStates[StateInfo::MaxStates];
public:
LightEntity();
bool parseEntityDescription(InteriorMapResource::Entity* ent);
static const char* getClassName() { return("light"); }
};
//------------------------------------------------------------------------------
class LightOmniEntity : public BaseLightEntity
{
public:
ColorF mColor;
U32 mFalloff1;
U32 mFalloff2;
LightOmniEntity();
bool parseEntityDescription(InteriorMapResource::Entity* ent);
static const char* getClassName() { return("light_omni"); }
};
//------------------------------------------------------------------------------
class LightSpotEntity : public BaseLightEntity
{
public:
char mTarget[256];
ColorF mColor;
U32 mInnerDistance;
U32 mOuterDistance;
U32 mFalloff1;
U32 mFalloff2;
LightSpotEntity();
bool parseEntityDescription(InteriorMapResource::Entity* ent);
static const char* getClassName() { return("light_spot"); }
};
//------------------------------------------------------------------------------
class LightStrobeEntity : public BaseLightEntity
{
public:
U32 mSpeed;
U32 mFalloff1;
U32 mFalloff2;
ColorF mColor1;
ColorF mColor2;
LightStrobeEntity();
bool parseEntityDescription(InteriorMapResource::Entity* ent);
static const char* getClassName() {return("light_strobe");}
};
//------------------------------------------------------------------------------
class LightPulseEntity : public BaseLightEntity
{
public:
U32 mSpeed;
U32 mFalloff1;
U32 mFalloff2;
ColorF mColor1;
ColorF mColor2;
LightPulseEntity();
bool parseEntityDescription(InteriorMapResource::Entity* ent);
static const char* getClassName() {return("light_pulse");}
};
//------------------------------------------------------------------------------
class LightPulse2Entity : public BaseLightEntity
{
public:
ColorF mColor1;
ColorF mColor2;
U32 mFalloff1;
U32 mFalloff2;
F32 mAttack;
F32 mSustain1;
F32 mDecay;
F32 mSustain2;
LightPulse2Entity();
bool parseEntityDescription(InteriorMapResource::Entity* ent);
static const char* getClassName() {return("light_pulse2");}
};
//------------------------------------------------------------------------------
class LightFlickerEntity : public BaseLightEntity
{
public:
U32 mSpeed;
ColorF mColor1;
ColorF mColor2;
ColorF mColor3;
ColorF mColor4;
ColorF mColor5;
U32 mFalloff1;
U32 mFalloff2;
LightFlickerEntity();
bool parseEntityDescription(InteriorMapResource::Entity* ent);
static const char* getClassName() {return("light_flicker");}
};
//------------------------------------------------------------------------------
class LightRunwayEntity : public BaseLightEntity
{
public:
char mEndTarget[256];
ColorF mColor;
U32 mSpeed;
bool mPingPong;
U32 mSteps;
U32 mFalloff1;
U32 mFalloff2;
LightRunwayEntity();
bool parseEntityDescription(InteriorMapResource::Entity* ent);
static const char* getClassName() {return("light_runway");}
};
//--------------------------------------------------------------------------
//-------------------------------------- SPECIAL TYPES
//
class MirrorSurfaceEntity : public EditGeometry::Entity
{
static U32 smZoneKeyAllocator;
public:
Point3D mOrigin;
float mAlphaLevel;
U32 mZoneKey;
U32 mRealZone;
MirrorSurfaceEntity();
static const char* getClassName() { return("MirrorSurface"); }
bool parseEntityDescription(InteriorMapResource::Entity* ent);
bool isPointClass() const { return true; }
const char* getName() const { return NULL; }
const Point3D& getOrigin() const { return mOrigin; }
BrushType getBrushType();
void markSurface(Vector<CSGBrush*>&, Vector<CSGBrush*>&);
void grabSurface(EditGeometry::Surface&);
};
//--------------------------------------------------------------------------
//-------------------------------------- Trigger types
//
class TriggerEntity : public EditGeometry::Entity
{
public:
char mName[256];
char mDataBlock[256];
Point3D mOrigin;
bool mValid;
Polyhedron triggerPolyhedron;
Vector<CSGBrush*> mBrushes;
U32 mCurrBrushId;
protected:
void generateTrigger();
public:
TriggerEntity();
~TriggerEntity();
BrushType getBrushType();
bool parseEntityDescription(InteriorMapResource::Entity* ent);
static const char* getClassName() { return "trigger"; }
const char* getName() const { return mName; }
const Point3D& getOrigin() const { return mOrigin; }
bool isPointClass() const { return true; }
};
class GameEntity : public EditGeometry::Entity
{
public:
Point3D mOrigin;
char mDataBlock[1024];
char mGameClass[1024];
public:
GameEntity();
~GameEntity();
BrushType getBrushType();
bool parseEntityDescription(InteriorMapResource::Entity* ent);
static const char* getClassName() { return "game_entity"; }
const char* getName() const { return NULL; }
const Point3D& getOrigin() const { return mOrigin; }
bool isPointClass() const { return true; }
};
#endif //_ENTITYTYPES_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,492 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "map2dif plus/lmapPacker.h"
#include "platform/platformAssert.h"
#include "math/mPoint.h"
/* for FN_CDECL defs */
#include "platform/types.h"
const U32 SheetManager::csm_sheetSize = 256;
SheetManager::SheetManager()
{
m_currSheet = -1;
m_currX = 0;
m_currY = 0;
m_lowestY = 0;
}
SheetManager::~SheetManager()
{
for (U32 i = 0; i < m_sheets.size(); i++)
{
delete m_sheets[i].pData;
m_sheets[i].pData = NULL;
}
m_currSheet = -1;
m_currX = 0;
m_currY = 0;
m_lowestY = 0;
}
void SheetManager::begin()
{
numPixels = 0;
numSheetPixels = 0;
}
void SheetManager::end()
{
repackBlock();
// dPrintf("\n\n"
// " Total Pixels: %d\n"
// " Total SheetP: %d\n"
// " Efficiency: %g\n\n", numPixels, numSheetPixels, F32(numPixels)/F32(numSheetPixels));
m_currY = m_lowestY = csm_sheetSize + 1;
m_currSheet = -1;
}
U32 SheetManager::enterLightMap(const GBitmap* lm)
{
U32 width = lm->getWidth() + (SG_LIGHTMAP_BORDER_SIZE * 2);
U32 height = lm->getHeight() + (SG_LIGHTMAP_BORDER_SIZE * 2);
numPixels += width * height;
if (m_currSheet < 0)
{
// Must initialize the sheets...
setupNewSheet();
}
if (m_currX + width >= csm_sheetSize)
{
// Carriage return...
m_currX = 0;
m_currY = m_lowestY;
}
if (m_currY + height >= csm_sheetSize)
{
// new sheet needed
setupNewSheet();
}
m_lightMaps.increment();
m_lightMaps.last().sheetId = m_currSheet;
m_lightMaps.last().x = m_currX;
m_lightMaps.last().y = m_currY;
m_lightMaps.last().width = width;
m_lightMaps.last().height = height;
// And place the lightmap...
//
AssertFatal(lm->bytesPerPixel == m_sheets[m_currSheet].pData->bytesPerPixel, "Um, bad mismatch of bitmap types...");
U32 y, b;
U32 pixoffset = lm->bytesPerPixel;
U32 borderwidth = SG_LIGHTMAP_BORDER_SIZE * 2;
U32 nonborderpixlen = (width - borderwidth) * pixoffset;
U32 lmheightindex = lm->getHeight() - 1;
U32 lmborderheightindex = lmheightindex + SG_LIGHTMAP_BORDER_SIZE;
U32 borderpixlen = pixoffset * SG_LIGHTMAP_BORDER_SIZE;
for(y=0; y<height; y++)
{
U8 *srun, *drun;
if(y < SG_LIGHTMAP_BORDER_SIZE)
srun = (U8 *)lm->getAddress(0, 0);
else if(y > lmborderheightindex)
srun = (U8 *)lm->getAddress(0, lmheightindex);
else
srun = (U8 *)lm->getAddress(0, (y - SG_LIGHTMAP_BORDER_SIZE));
drun = (U8 *)m_sheets[m_currSheet].pData->getAddress(m_currX, (m_currY + y));
dMemcpy(&drun[borderpixlen], srun, nonborderpixlen);
U8 *ss, *se;
ss = srun;
se = &srun[(nonborderpixlen - pixoffset)];
for(b=0; b<SG_LIGHTMAP_BORDER_SIZE; b++)
{
U32 i = b * pixoffset;
drun[i] = ss[0];
drun[i+1] = ss[1];
drun[i+2] = ss[2];
i = (lm->getWidth() + SG_LIGHTMAP_BORDER_SIZE + b) * pixoffset;
drun[i] = se[0];
drun[i+1] = se[1];
drun[i+2] = se[2];
}
}
m_currX += width;
if (m_currY + height > m_lowestY)
m_lowestY = m_currY + height;
return m_lightMaps.size() - 1;
}
const SheetManager::LightMapEntry &SheetManager::getLightmap(const S32 in_lightMapIndex) const
{
AssertFatal(U32(in_lightMapIndex) < m_lightMaps.size(), "Out of bounds lightmap");
return m_lightMaps[in_lightMapIndex];
}
SheetManager::LightMapEntry &SheetManager::getLightmapNC(const S32 in_lightMapIndex)
{
AssertFatal(U32(in_lightMapIndex) < m_lightMaps.size(), "Out of bounds lightmap");
return m_lightMaps[in_lightMapIndex];
}
void SheetManager::setupNewSheet()
{
m_sheets.increment();
m_currSheet = m_sheets.size() - 1;
m_sheets.last().pData = new GBitmap(csm_sheetSize, csm_sheetSize);
for (U32 y = 0; y < m_sheets.last().pData->getHeight(); y++)
{
for (U32 x = 0; x < m_sheets.last().pData->getWidth(); x++)
{
U8* pDst = m_sheets.last().pData->getAddress(x, y);
pDst[0] = 0xFF;
pDst[1] = 0x00;
pDst[2] = 0xFF;
}
}
m_currX = 0;
m_currY = 0;
m_lowestY = 0;
}
void SheetManager::repackBlock()
{
if (m_lightMaps.size() == 0)
return;
U32 currLightMapStart = 0;
U32 currLightMapEnd = m_lightMaps.size() - 1;
S32 first = 0;
U32 num = m_sheets.size();
// OK, so at this point, we have a block of sheets, and a block of lightmaps on
// that sheet. What we want to do is loop on the lightmaps until we have none
// left, and pack them into new sheets that are as small as possible.
//
do
{
const U32 numSizes = 16;
U32 sizes[numSizes][2] = {
{32, 32}, // 1024
{32, 64}, // 2048
{64, 32}, // 2048
{64, 64}, // 4096
{32, 128}, // 4096
{128, 32}, // 4096
{64, 128}, // 8192
{128, 64}, // 8192
{32, 256}, // 8192
{256, 32}, // 8192
{128, 128}, // 16384
{64, 256}, // 16384
{256, 64}, // 16384
{128, 256}, // 32768
{256, 128}, // 32768
{256, 256} // 65536
};
// const U32 numSizes = 4;
// U32 sizes[numSizes][2] = {
// {32, 32}, // 1024
// {64, 64}, // 4096
// {128, 128}, // 16384
// {256, 256} // 65536
// };
bool success = false;
for (U32 i = 0; i < numSizes; i++)
{
if (doesFit(currLightMapStart, currLightMapEnd, sizes[i][0], sizes[i][1]) == true)
{
// Everything left fits into a 32
//
numSheetPixels += sizes[i][0] * sizes[i][1];
repackSection(currLightMapStart, currLightMapEnd, sizes[i][0], sizes[i][1]);
currLightMapStart = currLightMapEnd;
success = true;
break;
}
}
if (success == false)
{
// BSearch for the max we can get into a 256, then keep going...
//
U32 searchStart = currLightMapStart;
U32 searchEnd = currLightMapEnd - 1;
while (searchStart != searchEnd)
{
U32 probe = (searchStart + searchEnd) >> 1;
if (doesFit(currLightMapStart, probe, 256, 256) == true)
{
if (searchStart != probe)
searchStart = probe;
else
searchEnd = searchStart;
}
else
{
if (searchEnd != probe)
searchEnd = probe;
else
searchEnd = searchStart;
}
}
numSheetPixels += 256*256;
repackSection(currLightMapStart, searchStart, 256, 256, true);
currLightMapStart = searchStart + 1;
}
} while (currLightMapStart < currLightMapEnd);
// All the sheets from the same block id are contigous, so all we have to do is
// decrement the sheetIds of the affected lightmaps...
//
for (U32 i = 0; i < m_lightMaps.size(); i++)
{
if (m_lightMaps[i].sheetId >= (first + num))
{
m_lightMaps[i].sheetId -= num;
}
}
for (U32 i = num; i != 0; i--)
{
SheetEntry& rEntry = m_sheets[first];
delete rEntry.pData;
rEntry.pData = NULL;
m_sheets.erase(first);
}
}
S32 FN_CDECL compY(const void* p1, const void* p2)
{
const Point2I* point1 = (const Point2I*)p1;
const Point2I* point2 = (const Point2I*)p2;
if (point1->y != point2->y)
return point2->y - point1->y;
else
return point2->x - point1->x;
}
SheetManager* g_pManager = NULL;
S32 FN_CDECL compMapY(const void* in_p1, const void* in_p2)
{
const S32* p1 = (const S32*)in_p1;
const S32* p2 = (const S32*)in_p2;
const SheetManager::LightMapEntry& rEntry1 = g_pManager->getLightmap(*p1);
const SheetManager::LightMapEntry& rEntry2 = g_pManager->getLightmap(*p2);
if (rEntry1.height != rEntry2.height)
return rEntry2.height - rEntry1.height;
else
return rEntry2.width - rEntry1.width;
}
void
SheetManager::repackSection(const S32 in_start,
const S32 in_end,
const U32 in_sizeX,
const U32 in_sizeY,
const bool overflow)
{
Vector<S32> sheetIndices;
for (S32 i = in_start; i <= in_end; i++)
sheetIndices.push_back(i);
g_pManager = this;
dQsort(sheetIndices.address(), sheetIndices.size(), sizeof(S32), compMapY);
g_pManager = NULL;
// Ok, we now have the list of entries that we'll be entering, in the correct
// order. Go for it! Create the "right-sized" sheet, and pack.
//
m_sheets.increment();
m_sheets.last().pData = new GBitmap(in_sizeX, in_sizeY);
for (U32 y = 0; y < m_sheets.last().pData->getHeight(); y++)
{
for (U32 x = 0; x < m_sheets.last().pData->getWidth(); x++)
{
U8* pDst = m_sheets.last().pData->getAddress(x, y);
if (overflow == false)
{
pDst[0] = 0xFF;
pDst[1] = 0x00;
pDst[2] = 0xFF;
}
else
{
pDst[0] = 0x00;
pDst[1] = 0xFF;
pDst[2] = 0x00;
}
}
}
U32 currX = 0;
U32 currY = 0;
U32 lowestY = 0;
while (sheetIndices.size() != 0)
{
LightMapEntry& rEntry = getLightmapNC(sheetIndices[0]);
S32 lastOfHeight = 0;
for (U32 j = 1; j < sheetIndices.size(); j++)
{
LightMapEntry& rEntryTest = getLightmapNC(sheetIndices[j]);
if (rEntryTest.height != rEntry.height)
break;
lastOfHeight = j;
}
S32 insert = -1;
for (S32 k = 0; k <= lastOfHeight; k++)
{
LightMapEntry& rEntryTest = getLightmapNC(sheetIndices[k]);
if (currX + rEntryTest.width < in_sizeX)
{
insert = k;
break;
}
}
if (insert == -1)
{
// CR
currY = lowestY;
currX = 0;
insert = 0;
}
LightMapEntry* pInsert = &getLightmapNC(sheetIndices[insert]);
AssertFatal(currY + pInsert->height < in_sizeY, "Error, too many lmaps for this size");
for (S32 y = 0; y < pInsert->height; y++)
{
const U8* pSrc = m_sheets[pInsert->sheetId].pData->getAddress(pInsert->x, (pInsert->y + y));
U8* pDst = m_sheets.last().pData->getAddress(currX, (currY + y));
dMemcpy(pDst, pSrc, pInsert->width * m_sheets[pInsert->sheetId].pData->bytesPerPixel);
}
pInsert->sheetId = m_sheets.size() - 1;
pInsert->x = currX;
pInsert->y = currY;
AssertFatal(pInsert->x + pInsert->width <= m_sheets.last().pData->getWidth(), "very bad");
AssertFatal(pInsert->y + pInsert->height <= m_sheets.last().pData->getHeight(), "also bad");
currX += pInsert->width;
if (currY + pInsert->height > lowestY)
lowestY = currY + pInsert->height;
sheetIndices.erase(insert);
}
}
bool SheetManager::doesFit(const S32 startMap,
const S32 endMap,
const U32 sizeX,
const U32 sizeY) const
{
Vector<Point2I> mapSizes;
mapSizes.setSize(endMap - startMap + 1);
for (S32 i = startMap; i <= endMap; i++)
{
mapSizes[i - startMap].x = m_lightMaps[i].width;
mapSizes[i - startMap].y = m_lightMaps[i].height;
if (m_lightMaps[i].width > sizeX ||
m_lightMaps[i].height > sizeY)
return false;
}
dQsort(mapSizes.address(), mapSizes.size(), sizeof(Point2I), compY);
U32 currX = 0;
U32 currY = 0;
U32 lowestY = 0;
while (mapSizes.size() != 0) {
S32 lastOfHeight = 0;
for (U32 j = 1; j < mapSizes.size(); j++) {
if (mapSizes[j].y != mapSizes[0].y)
break;
lastOfHeight = j;
}
S32 insert = -1;
for (S32 k = 0; k <= lastOfHeight; k++)
{
if (currX + mapSizes[k].x < sizeX)
{
insert = k;
break;
}
}
if (insert == -1)
{
// CR
currX = 0;
currY = lowestY;
insert = 0;
}
if (currY + mapSizes[insert].y >= sizeY)
{
// Failure.
return false;
}
currX += mapSizes[insert].x;
if (currY + mapSizes[insert].y > lowestY)
lowestY = currY + mapSizes[insert].y;
mapSizes.erase(insert);
}
return true;
}

View File

@ -0,0 +1,75 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _ITRSHEETMANAGER_H_
#define _ITRSHEETMANAGER_H_
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#endif
#ifndef _GBITMAP_H_
#include "dgl/gBitmap.h"
#endif
//
// Defines the interior light map border size.
//
// Light map borders prevent visual artifacts
// caused by colors bleeding from adjacent light maps
// or dead texture space.
//
#define SG_LIGHTMAP_BORDER_SIZE 10
class SheetManager
{
public:
struct LightMapEntry
{
U32 sheetId;
U16 x, y;
U16 width, height;
};
struct SheetEntry
{
GBitmap* pData;
};
public:
static const U32 csm_sheetSize;
public:
Vector<LightMapEntry> m_lightMaps;
Vector<SheetEntry> m_sheets;
S32 m_currSheet;
U32 m_currX;
U32 m_currY;
U32 m_lowestY;
void setupNewSheet();
void repackSection(const S32, const S32, const U32 in_sizeX, const U32 in_sizeY, const bool = false);
void repackBlock();
bool doesFit(const S32, const S32, const U32 sizeX, const U32 sizeY) const;
LightMapEntry& getLightmapNC(const S32 in_lightMapIndex);
public:
SheetManager();
~SheetManager();
U32 numPixels;
U32 numSheetPixels;
void begin();
void end();
U32 enterLightMap(const GBitmap* in_pData);
const LightMapEntry& getLightmap(const S32 in_lightMapIndex) const;
};
#endif // _ITRSHEETMANAGER_H_

517
tools/map2dif plus/main.cc Normal file
View File

@ -0,0 +1,517 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "platform/event.h"
#include "platform/platformAssert.h"
#include "platform/platformVideo.h"
#include "math/mMath.h"
#include "console/console.h"
#include "dgl/gBitmap.h"
#include "core/tVector.h"
#include "core/fileStream.h"
#include "dgl/gTexManager.h"
#include "console/consoleTypes.h"
#include "math/mathTypes.h"
#include "core/tokenizer.h"
#include "map2dif plus/editGeometry.h"
#include "interior/interior.h"
#include "map2dif plus/editInteriorRes.h"
#include "interior/floorPlanRes.h"
#include "map2dif plus/morianGame.h"
#include "core/frameAllocator.h"
#include "gui/core/guiCanvas.h"
#include "map2dif plus/lmapPacker.h"
#include "map2dif plus/convert.h"
#include <stdlib.h>
MorianGame GameObject;
// FOR SILLY LINK DEPENDANCY
bool gEditingMission = false;
#if defined(TORQUE_DEBUG)
const char* const gProgramVersion = "1.0d";
#else
const char* const gProgramVersion = "1.0r";
#endif
//bool gRenderPreview = false;
bool gSpecifiedDetailOnly = false;
bool gBuildAsLowDetail = false;
bool gVerbose = false;
const char* gWadPath = "base/textures/";
bool gTextureSearch = true;
int gQuakeVersion = 2;
U32 gMaxPlanesConsidered = 32;
EditInteriorResource* gWorkingResource = NULL;
//#if defined(TORQUE_OS_WIN32) // huger hack
// huge hack
//GuiCanvas *Canvas;
//void GuiCanvas::paint() {}
//#endif
//
static bool initLibraries()
{
// asserts should be created FIRST
// PlatformAssert::create();
FrameAllocator::init(2 << 20);
_StringTable::create();
TextureManager::create();
ResManager::create();
// Register known file types here
ResourceManager->registerExtension(".jpg", constructBitmapJPEG);
ResourceManager->registerExtension(".png", constructBitmapPNG);
ResourceManager->registerExtension(".gif", constructBitmapGIF);
ResourceManager->registerExtension(".dbm", constructBitmapDBM);
ResourceManager->registerExtension(".bmp", constructBitmapBMP);
ResourceManager->registerExtension(".bm8", constructBitmapBM8);
ResourceManager->registerExtension(".gft", constructFont);
ResourceManager->registerExtension(".dif", constructInteriorDIF);
ResourceManager->registerExtension(".map", constructInteriorMAP);
Con::init();
Math::init();
Platform::init(); // platform specific initialization
// Create a log file
Con::setLogMode(6);
return(true);
}
static void shutdownLibraries()
{
// shut down
Platform::shutdown();
Con::shutdown();
TextureManager::destroy();
_StringTable::destroy();
// asserts should be destroyed LAST
FrameAllocator::destroy();
PlatformAssert::destroy();
}
void cleanSlashes(char* path)
{
// Clean up path char.
for (char* ptr = path; *ptr != '\0'; ptr++)
if (*ptr == '\\')
*ptr = '/';
}
void terminate(char* path)
{
// Check termination
char* end = &path[dStrlen(path) - 1];
if (*end != '/')
{
end[1] = '/';
end[2] = 0;
}
}
char* cleanPath(const char* _path)
{
char* path = new char[dStrlen(_path) + 2];
dStrcpy(path, _path);
cleanSlashes(path);
terminate(path);
return path;
}
char* getPath(const char* file)
{
char* path = "\0";
if (!dStrchr(file, '/') && !dStrchr(file, '\\'))
return path;
else
{
path = new char[dStrlen(file) + 2];
dStrcpy(path, file);
}
// Strip back to first path char.
char* slash = dStrrchr(path, '/');
if (!slash)
slash = dStrrchr(path, '\\');
if (slash)
*slash = 0;
cleanSlashes(path);
terminate(path);
return path;
}
char* getBaseName(const char* file)
{
// Get rid of path
const char* slash = dStrrchr(file, '/');
if (!slash)
slash = dStrrchr(file, '\\');
if (!slash)
slash = file;
else
slash++;
char* name = new char[dStrlen(slash) + 1];
dStrcpy(name, slash);
// Strip extension & trailing _N
char* dot = dStrrchr(name, '.') - 2;
if (dot[0] == '_' && (dot[1] >= '0' && dot[1] <= '9'))
dot[0] = '\0';
else
dot[2] = '\0';
return name;
}
S32 MorianGame::main(int argc, const char** argv)
{
// Set the memory manager page size to 64 megs...
setMinimumAllocUnit((U32)( 64 << 20));
if(!initLibraries())
return 0;
// Set up the command line args for the console scripts...
Con::setIntVariable("Game::argc", argc);
for (S32 i = 0; i < argc; i++)
Con::setVariable(avar("Game::argv%d", i), argv[i]);
// Parse command line args...
bool extrusionTest = false;
const char* wadPath = 0;
const char* difPath = 0;
S32 i = 1;
for (; i < argc; i++)
{
if (argv[i][0] != '-')
break;
switch(dToupper(argv[i][1]))
{
case 'D':
gSpecifiedDetailOnly = true;
break;
case 'L':
gSpecifiedDetailOnly = true;
gBuildAsLowDetail = true;
break;
case 'H':
gMaxPlanesConsidered = U32(1 << 30);
break;
case 'S':
gTextureSearch = false;
break;
case 'T':
wadPath = cleanPath(argv[++i]);
break;
case 'O':
difPath = cleanPath(argv[++i]);
break;
}
}
U32 args = argc - i;
if (args != 1)
{
dPrintf("\nmap2dif - Torque .MAP file converter\n"
" Copyright (C) GarageGames.com, Inc.\n"
" Program version: %s\n"
" Programmers: John Folliard, Dave Moore, and Matthew Fairfax\n"
" Built: %s at %s\n\n"
"Usage: map2dif [-s] [-l] [-h] [-e] [-o outputDirectory] [-t textureDirectory] <file>.map\n"
" -d : Process only the detail specified on the command line\n"
" -l : Process as a low detail shape (implies -s)\n"
" -h : Process for final build (exhaustive BSP search)\n"
" -s : Don't search for textures in parent dir.\n"
" -o dir: Directory in which to place the .dif file\n"
" -t dir: Location of textures\n", gProgramVersion, __DATE__, __TIME__);
shutdownLibraries();
return -1;
}
else
dPrintf("\nmap2dif - Torque .MAP file converter\n"
" Copyright (C) GarageGames.com, Inc.\n"
" Program version: %s\n"
" Programmers: John Folliard, Dave Moore, and Matthew Fairfax\n"
" Built: %s at %s\n\n", gProgramVersion, __DATE__, __TIME__);
// Check map file extension
const char* mapFile = argv[i];
const char* pDot = dStrrchr(mapFile, '.');
AssertISV(pDot && ((dStricmp(pDot, ".map") == 0)),
"Error, the map file must have a .MAP extension.");
// Get path and file name arguments
const char* mapPath = getPath(mapFile);
const char* baseName = getBaseName(mapFile);
if (!wadPath)
wadPath = mapPath;
if (!difPath)
difPath = mapPath;
// Wad path
gWadPath = wadPath;
// Print out which file we are loading and what texture search path has been set
Con::printf("Loading %s", mapFile);
dPrintf("\nLoading %s\n", mapFile);
Con::printf("Initial texture search path is set to \"%s\"\n", gWadPath);
dPrintf("Initial texture search path is set to \"%s\"\n\n", gWadPath);
dFflushStdout();
// Dif file name
char* pOutputName = new char[dStrlen(difPath) + dStrlen(baseName) + 5];
dStrcpy(pOutputName, difPath);
dStrcat(pOutputName, baseName);
dStrcat(pOutputName, ".dif");
Vector<char*> mapFileNames;
if (gSpecifiedDetailOnly == false)
{
const char* pDot = dStrrchr(mapFile, '.');
if (pDot && *(pDot - 2) == '_')
{
// This is a detail based interior
char buffer[1024];
dStrcpy(buffer, mapFile);
char* pBufDot = dStrrchr(buffer, '.');
AssertFatal(pBufDot, "Error, why isn't it in this buffer too?");
*(pBufDot-1) = '\0';
for (U32 i = 0; i <= 9; i++)
{
mapFileNames.push_back(new char[1024]);
dSprintf(mapFileNames.last(), 1023, "%s%d%s", buffer, i, pDot);
}
// Now, eliminate all mapFileNames that aren't actually map files
for (S32 i = S32(mapFileNames.size() - 1); i >= 0; i--)
{
Tokenizer* pTokenizer = new Tokenizer();
if (pTokenizer->openFile(mapFileNames[i]) == false)
{
delete [] mapFileNames[i];
mapFileNames.erase(i);
}
delete pTokenizer;
}
}
else
{
// normal interior
mapFileNames.push_back(new char[dStrlen(mapFile) + 1]);
dStrcpy(mapFileNames.last(), mapFile);
}
}
else
{
mapFileNames.push_back(new char[dStrlen(mapFile) + 1]);
dStrcpy(mapFileNames.last(), mapFile);
}
// Fix the slashes
for (U32 i = 0; i < mapFileNames.size(); i++)
cleanSlashes(mapFileNames[i]);
gWorkingResource = new EditInteriorResource;
for (U32 i = 0; i < mapFileNames.size(); i++)
{
// setup the tokenizer
Tokenizer* pTokenizer = new Tokenizer();
if (pTokenizer->openFile(mapFileNames[i]) == false)
{
dPrintf("Error opening map file: %s", mapFileNames[i]);
delete pTokenizer;
shutdownLibraries();
return -1;
}
// Create a geometry object
AssertFatal(gWorkingGeometry == NULL, "Already working?");
gWorkingGeometry = new EditGeometry;
// Parse and create the geometry
// First we need our object to load the file into
InteriorMap map;
// Set the texture path
map.mTexPath = StringTable->insert(wadPath);
// Set our path info
map.setPath(mapFileNames[i]);
// Load resource
map.mInteriorRes = ResourceManager->load(mapFileNames[i], true);
if (map.mInteriorRes)
{
Con::printf("Successfully opened map file: %s", mapFileNames[i]);
dPrintf("Successfully opened map file: %s\n", mapFileNames[i]);
dFflushStdout();
}
else
{
Con::printf(" Unable to load map file: %s", mapFileNames[i]);
dPrintf(" Unable to load map file: %s\n", mapFileNames[i]);
delete pTokenizer;
delete gWorkingGeometry;
delete gWorkingResource;
shutdownLibraries();
return -1;
}
// Little late for this but it looks nice
dPrintf(" Parsing mapfile...");
dFflushStdout();
loadTextures(&map);
// Reserve enough room for all the brushes
// Not truly "dynamic" but it will do for now
gBrushArena.setSize(map.mInteriorRes->mBrushes.size());
convertInteriorMap(&map);
delete pTokenizer;
dPrintf(" done.\n");
gWorkingGeometry->setGraphGeneration(false,extrusionTest);
dPrintf(" Creating BSP...");
dFflushStdout();
if (gWorkingGeometry->createBSP() == false)
{
Con::printf("Error creating BSP for %s!", mapFileNames[i]);
dPrintf("Error creating BSP for %s!\n", mapFileNames[i]);
// delete pTokenizer; (already)
delete gWorkingGeometry;
delete gWorkingResource;
shutdownLibraries();
return -1;
}
dPrintf("done.\n Marking active zones...");
gWorkingGeometry->markEmptyZones();
dPrintf("done\n Creating surfaces..."); dFflushStdout();
gWorkingGeometry->createSurfaces();
dPrintf("done.\n Lightmaps: Normal...");
dFflushStdout();
gWorkingGeometry->computeLightmaps(false);
dPrintf("Alarm...");
dFflushStdout();
gWorkingGeometry->computeLightmaps(true);
dPrintf("done.\n Resorting and Packing LightMaps..."); dFflushStdout();
gWorkingGeometry->preprocessLighting();
gWorkingGeometry->sortLitSurfaces();
gWorkingGeometry->packLMaps();
dPrintf("done.\n");
dFflushStdout();
// Give status
Con::printf("\n STATISTICS\n"
" - Total brushes: %d\n"
" + structural: %d\n"
" + detail: %d\n"
" + portal: %d\n"
" - Number of zones: %d\n"
" - Number of surfaces: %d\n", gWorkingGeometry->getTotalNumBrushes(),
gWorkingGeometry->getNumStructuralBrushes(),
gWorkingGeometry->getNumDetailBrushes(),
gWorkingGeometry->getNumPortalBrushes(),
gWorkingGeometry->getNumZones(),
gWorkingGeometry->getNumSurfaces());
dPrintf("\n STATISTICS\n"
" - Total brushes: %d\n"
" + structural: %d\n"
" + detail: %d\n"
" + portal: %d\n"
" - Number of zones: %d\n"
" - Number of surfaces: %d\n", gWorkingGeometry->getTotalNumBrushes(),
gWorkingGeometry->getNumStructuralBrushes(),
gWorkingGeometry->getNumDetailBrushes(),
gWorkingGeometry->getNumPortalBrushes(),
gWorkingGeometry->getNumZones(),
gWorkingGeometry->getNumSurfaces());
// DMMTODO: store new geometry in the correct instance location
Interior* pRuntime = new Interior;
// Support for interior light map border sizes.
pRuntime->setLightMapBorderSize(SG_LIGHTMAP_BORDER_SIZE);
dPrintf("\n Exporting to runtime..."); dFflushStdout();
gWorkingGeometry->exportToRuntime(pRuntime, gWorkingResource);
dPrintf("done.\n\n");
dFflushStdout();
gWorkingResource->addDetailLevel(pRuntime);
delete gWorkingGeometry;
gWorkingGeometry = NULL;
}
if (gWorkingResource->getNumDetailLevels() > 0)
{
dPrintf(" Writing Resource: "); dFflushStdout();
dPrintf("persist..(%s) ", pOutputName); dFflushStdout();
gWorkingResource->sortDetailLevels();
gWorkingResource->getDetailLevel(0)->processHullPolyLists();
gWorkingResource->getDetailLevel(0)->processVehicleHullPolyLists();
for (U32 i = 1; i < gWorkingResource->getNumDetailLevels(); i++)
gWorkingResource->getDetailLevel(i)->purgeLODData();
FileStream fws;
fws.open(pOutputName, FileStream::Write);
gWorkingResource->write(fws);
fws.close();
dPrintf("Done.\n\n");
dFflushStdout();
delete gWorkingResource;
}
delete [] pOutputName;
for (U32 i = 0; i < mapFileNames.size(); i++)
delete [] mapFileNames[i];
shutdownLibraries();
return 0;
}
void GameReactivate()
{
}
void GameDeactivate( bool )
{
}

View File

@ -0,0 +1,105 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _MORIANBASICS_H_
#define _MORIANBASICS_H_
//Includes
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#endif
#ifndef _TVECTOR_H_
#include "core/tVector.h"
#endif
#ifndef _MPOINT_H_
#include "math/mPoint.h"
#endif
static const F64 gcPlaneDistanceEpsilon = 0.00001;
static const F64 gcPointEpsilon = 0.01;
static const U32 MaxWindingPoints = 64;
static const U32 MaxWindingNodes = 96;
enum BrushType {
StructuralBrush = 0,
PortalBrush = 1,
DetailBrush = 2,
CollisionBrush = 3,
VehicleCollisionBrush = 4
};
enum PlaneSide {
PlaneFront = 1,
PlaneOn = 0,
PlaneBack = -1
};
enum SpecialPlaneSide {
PlaneSpecialFront = 1 << 0,
PlaneSpecialOn = 1 << 1,
PlaneSpecialBack = 1 << 2
};
class UniqueVector : public Vector<U32>
{
public:
UniqueVector(U32 size) : Vector<U32>(size) { }
UniqueVector() : Vector<U32>(32) { }
void pushBackUnique(U32);
};
struct PlaneEQ
{
Point3D normal;
F64 dist;
PlaneSide whichSide(const Point3D&) const;
PlaneSide whichSideLow(const Point3D&) const;
PlaneSide whichSidePerfect(const Point3D&) const;
F64 distanceToPlane(const Point3D&) const;
void neg() { normal.neg(); dist = -dist; }
};
struct Winding {
U32 numIndices;
U32 numNodes;
U32 numZoneIds;
U32 indices[MaxWindingPoints];
U32 solidNodes[MaxWindingNodes];
U32 zoneIds[8];
U32 brushId;
Winding* pNext;
Winding() : numNodes(0), numZoneIds(0), numIndices(0) { }
void insertZone(U32 zone)
{
// FIXME: lame sort to make sure the zones stay sorted
for (U32 i = 0; i < numZoneIds; i++)
if (zoneIds[i] == zone)
return;
AssertFatal(numZoneIds < 8, "Error, too many zones on a surface. Increase count from 8");
zoneIds[numZoneIds++] = zone;
extern int FN_CDECL cmpZoneNum(const void*, const void*);
dQsort(zoneIds, numZoneIds, sizeof(U32), cmpZoneNum);
}
};
//------------------------------------------------------------------------------
//-------------------------------------- Inlines
//
inline void UniqueVector::pushBackUnique(U32 newElem)
{
for (U32 i = 0; i < size(); i++)
if (operator[](i) == newElem)
return;
push_back(newElem);
}
#endif //_MORIANBASICS_H_

View File

@ -0,0 +1,19 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _H_MORIANGAME_
#define _H_MORIANGAME_
#ifndef _GAMEINTERFACE_H_
#include "platform/gameInterface.h"
#endif
class MorianGame : public GameInterface
{
public:
S32 main(S32 argc, const char **argv);
};
#endif // _H_MORIANGAME_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,80 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _MORIANUTIL_H_
#define _MORIANUTIL_H_
//Includes
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#endif
#ifndef _MORIANBASICS_H_
#include "map2dif plus/morianBasics.h"
#endif
#ifndef _MBOX_H_
#include "math/mBox.h"
#endif
//-------------------------------------- Util functions
S32 planeGCD(S32 x, S32 y, S32 z, S32 d);
F64 getWindingSurfaceArea(const Winding& rWinding, U32 planeEQIndex);
bool clipWindingToPlaneFront(Winding* rWinding, const PlaneEQ&);
bool clipWindingToPlaneFront(Winding* rWinding, U32 planeEQIndex);
U32 windingWhichSide(const Winding& rWinding, U32 windingPlaneIndex, U32 planeEQIndex);
bool windingsEquivalent(const Winding& winding1, const Winding& winding2);
bool pointsAreColinear(U32 p1, U32 p2, U32 p3);
bool collapseWindings(Winding& into, const Winding& from);
void createBoundedWinding(const Point3D& minBound,
const Point3D& maxBound,
U32 planeEQIndex,
Winding* finalWinding);
bool createBaseWinding(const Vector<U32>& rPoints, const Point3D& normal, Winding* pWinding);
void dumpWinding(const Winding& winding, const char* prefixString);
bool intersectWGPlanes(const U32, const U32, const U32, Point3D*);
class CSGBrush;
void splitBrush(CSGBrush*& inBrush,
U32 planeEQIndex,
CSGBrush*& outFront,
CSGBrush*& outBack);
struct PlaneEQ;
void assessPlane(const U32 testPlane,
const CSGBrush& rTestBrush,
S32* numCoplanar,
S32* numTinyWindings,
S32* numSplits,
S32* numFront,
S32* numBack);
void reextendName(char* pName, const char* pExt);
void extendName(char* pName, const char* pExt);
class BrushArena {
private:
Vector<CSGBrush*> mBuffers;
bool arenaValid;
U32 arenaSize;
CSGBrush* mFreeListHead;
void newBuffer();
public:
BrushArena(U32 _arenaSize);
~BrushArena();
void setSize(U32 _arenaSize);
CSGBrush* allocateBrush();
void freeBrush(CSGBrush*);
};
extern BrushArena gBrushArena;
#endif //_MORIANUTIL_H_

View File

@ -0,0 +1,165 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
/*
lhdo:
overview above the types / process for generating the floor plan resource.
probably axe this file and migrate methods, several of which should be on the
resource editing class.
*/
#include "map2dif plus/editGeometry.h"
#include "map2dif plus/csgBrush.h"
#include "core/fileStream.h"
#include "math/mMath.h"
// (rendered TMarker list as initial test).
#define MARKER_LIST_TEST 0
// In addition to a flag, it looks like the graph generation will need
// to adjust the precision variables that are used.
void EditGeometry::setGraphGeneration(bool doGeneration, bool doExtrusion)
{
mGenerateGraph = doGeneration;
mPerformExtrusion = doExtrusion;
if( mPerformExtrusion ){
mHashPoints = mHashPlanes = false;
}
else{
mHashPoints = mHashPlanes = true;
}
// Leaves as before:
mHashPoints = mHashPlanes = true;
}
// Called from bottom of VisLink creating recursion
void EditGeometry::gatherLinksForGraph(EditBSPNode * pLeaf)
{
// Just do solid-to-empty links for now.
if( pLeaf->isSolid )
{
// iterate all visLinks that go to empty, save off winding and the plane.
for( U32 i = 0; i < pLeaf->visLinks.size(); i++ )
{
Winding * pWinding = NULL;
EditBSPNode::VisLink * pLink = pLeaf->visLinks[i];
U32 planeEq;
if( pLink->pBack == pLeaf )
{
if( ! pLink->pFront->isSolid )
{
pWinding = & pLink->winding;
planeEq = pLink->planeEQIndex;
}
}
else
{
if( ! pLink->pBack->isSolid )
{
pWinding = & pLink->winding;
planeEq = getPlaneInverse( pLink->planeEQIndex );
}
}
if( pWinding )
{
#if MARKER_LIST_tEST
for( U32 j = 0; j < pWinding->numIndices; j++ )
mGraphSurfacePts.pushBackUnique( pWinding->indices[j] );
#endif
// Save the windings for parsing later.
mEditFloorPlanRes.pushArea(* pWinding, planeEq);
}
}
}
}
// CS file gives list with element count first
// $list[0] = "19";
// $list[1] = "0 0 20";
// $list[2] = "0 0 30";
// ....
static const char formatStr0[] = "$list[0] = \"%d\";\n";
static const char formatStr1[] = "$list[%d] = \"%lf %lf %lf\";\n";
U32 EditGeometry::writeGraphInfo()
{
#if MARKER_LIST_TEST
if( U32 numPoints = mGraphSurfacePts.size() )
{
FileStream pointFile;
char buff[1024];
if( pointFile.open("points.cs", FileStream::Write) )
{
pointFile.write( dSprintf(buff,sizeof(buff),formatStr0,numPoints), buff );
for( U32 i = 0; i < numPoints; i++ )
{
Point3D pt = getPoint( mGraphSurfacePts[i] );
pt /= 32.0;
dSprintf(buff, sizeof(buff), formatStr1, i + 1, pt.x, pt.y, pt.z);
pointFile.write( dStrlen(buff), buff );
}
pointFile.close();
}
else
dPrintf( "Couldn't open point file for write" );
mGraphSurfacePts.clear();
}
else
dPrintf( "No points were generated for graph" );
#endif
// Test writing the resource
mEditFloorPlanRes.constructFloorPlan();
FileStream fws;
fws.open("sample.flr", FileStream::Write);
mEditFloorPlanRes.write(fws);
fws.close();
return mGraphSurfacePts.size();
}
static Point3D extrusions[3] =
{
Point3D( 0.5, 0.0, 0.0 ),
Point3D( 0.0, 0.5, 0.0 ),
Point3D( 0.0, 0.0, -2.0 )
};
// Perform extrusions on the given mInteriorRes->mBrushes. These have not yet been
// selfClip()ped, which is how we leave things. Extrusion routine
// needs the work done by the clipping though (Windings, etc).
void EditGeometry::doGraphExtrusions(Vector<CSGBrush*> & brushList)
{
for( U32 i = 0; i < brushList.size(); i++ )
{
for( U32 axis = 0; axis < 3; axis++ )
{
bool extrudeBothWays = (axis != 2);
CSGBrush * old = brushList[i];
// Create a new extruded brush.
old->selfClip();
brushList[i] = old->createExtruded( extrusions[axis] * 32.0, extrudeBothWays );
gBrushArena.freeBrush( old );
}
}
}
// Just move detail mInteriorRes->mBrushes onto structural list for graph generation.
void EditGeometry::xferDetailToStructural()
{
for( S32 i = 0; i < mDetailBrushes.size(); i++ )
mStructuralBrushes.push_back( mDetailBrushes[i] );
mDetailBrushes.clear();
}

View File

@ -0,0 +1,373 @@
//------------------------------------------------------------------------------
// Torque game definition file (.fgd) Version 1.1
// for Worldcraft 3.+ and the Torque engine
//------------------------------------------------------------------------------
// worldspawn
//------------------------------------------------------------------------------
@SolidClass = worldspawn : "World entity"
[
detail_number(integer) : "Shape's detail index" : 0
min_pixels(integer) : "Minimum pixels for detail" : 250
geometry_scale(string) : "Geometry scale" : "32.0"
light_geometry_scale(string) : "Lighting scale (must be a power of 2)" : "32.0"
ambient_color(color255) : "Ambient color" : "0 0 0"
emergency_ambient_color(color255) : "Emergency ambient color" : "0 0 0"
]
// --------------------------------------
// special classes
// --------------------------------------
@SolidClass = detail : "Detail Brush Entity"
[
]
@SolidClass = collision : "Collision Brush Entity"
[
]
@SolidClass = vehicle_collision : "Vehicle Collision Brush Entity"
[
]
@SolidClass = portal : "Portal Brush Entity"
[
ambient_light(choices) : "Ambient Light" : 0 =
[
0 : "Does not pass through"
1 : "Passes through"
]
]
@PointClass = MirrorSurface : "Mirror Surface Entity"
[
alpha_level(Choices) : "Translucency" : 0 =
[
0 : "Fully Mirrored"
1 : "Barely there"
2 : "Very Translucent"
3 : "Half-and-Half"
4 : "Muddy Pond"
5 : "Don't shave with this"
6 : "Use texture's alpha channel"
]
]
//------------------------------------------------------------------------------
// BaseClasses
//------------------------------------------------------------------------------
@BaseClass = Targetname
[
name(target_source) : "Name"
]
@BaseClass = Target
[
target(target_destination) : "Target"
]
//------------------------------------------------------------------------------
@BaseClass = LightAnimFlags
[
spawnflags(Flags) =
[
1 : "Auto start" : 1
2 : "Loop to end frame" : 1
4 : "Random frame" : 0
]
]
@BaseClass = LightAnimSpeed
[
speed(choices) : "Speed" : 2 =
[
0: "Very slow"
1: "Slow"
2: "Normal"
3: "Fast"
4: "Very fast"
]
]
@BaseClass = LightFalloffs
[
]
//------------------------------------------------------------------------------
// PointClasses - our entities
//------------------------------------------------------------------------------
@PointClass base(Targetname) = target : "Target" []
@PointClass base(TargetName, LightAnimFlags) = light : "Light"
[
name(target_source) : "Name"
state0_duration(string) : "State0 duration" : "1.0"
state0_color(color255) : "State0 color (R G B)" : "255 255 255"
]
//------------------------------------------------------------------------------
@PointClass base(Target) = light_emitter_point : "Point emitter"
[
state_index(integer) : "State index" : 0
falloff_type(choices) : "Falloff type" : 1 =
[
0 : "Distance"
1 : "Linear"
]
falloff1(integer) : "Falloff1" : 10
falloff2(integer) : "Falloff2" : 100
falloff3(integer) : "Falloff3" : 0
]
//------------------------------------------------------------------------------
@PointClass base(light_emitter_point) = light_emitter_spot : "Spot emitter"
[
direction(string) : "Direction" : "0 0 -1"
theta(string) : "Inner angle" : "0.2"
phi(string) : "Outer angle" : "0.4"
]
//------------------------------------------------------------------------------
// Stock static lights...
//------------------------------------------------------------------------------
@PointClass = light_omni : "Omni Light"
[
color(color255) : "Color (R G B)" : "255 255 255"
alarm_type(choices) : "Alarm Type" : 0 =
[
0 : "Normal only"
1 : "Alarm only"
2 : "Both Alarm and Normal"
]
falloff1(integer) : "Falloff1" : 10
falloff2(integer) : "Falloff2" : 100
]
@PointClass base(Target) = light_spot : "Spot Light"
[
color(color255) : "Color (R G B)" : "255 255 255"
alarm_type(choices) : "Alarm Type" : 0 =
[
0 : "Normal only"
1 : "Alarm only"
2 : "Both Alarm and Normal"
]
falloff1(integer) : "Falloff1" : 10
falloff2(integer) : "Falloff2" : 100
distance1(integer) : "Inner distance" : 10
distance2(integer) : "Outer distance" : 100
]
//------------------------------------------------------------------------------
// Animated lights...
//------------------------------------------------------------------------------
@PointClass base(Targetname, LightAnimSpeed, LightAnimFlags) = light_strobe : "Strobe Light"
[
spawnflags(Flags) =
[
1 : "Auto start" : 1
]
alarm_type(choices) : "Alarm Type" : 0 =
[
0 : "Normal only"
1 : "Alarm only"
]
color1(color255) : "Color1 (R G B)" : "255 255 255"
color2(color255) : "Color2 (R G B)" : "0 0 0"
falloff1(integer) : "Falloff1" : 10
falloff2(integer) : "Falloff2" : 100
]
@PointClass base(Targetname, LightAnimSpeed) = light_pulse : "Pulse Light"
[
spawnflags(Flags) =
[
1 : "Auto start" : 1
]
alarm_type(choices) : "Alarm Type" : 0 =
[
0 : "Normal only"
1 : "Alarm only"
]
color1(color255) : "Color1 (R G B)" : "255 255 255"
color2(color255) : "Color2 (R G B)" : "0 0 0"
falloff1(integer) : "Falloff1" : 10
falloff2(integer) : "Falloff2" : 100
]
@PointClass base(Targetname) = light_pulse2 : "Prog. Pulse Light"
[
spawnflags(Flags) =
[
1 : "Auto start" : 1
]
alarm_type(choices) : "Alarm Type" : 0 =
[
0 : "Normal only"
1 : "Alarm only"
]
color1(color255) : "Color1 (R G B)" : "255 255 255"
color2(color255) : "Color2 (R G B)" : "0 0 0"
falloff1(integer) : "Falloff1" : 10
falloff2(integer) : "Falloff2" : 100
attack(string) : "Attack" : "1.0"
sustain1(string) : "Sustain1" : "1.0"
decay(string) : "Decay" : "1.0"
sustain2(string) : "Sustain2" : "1.0"
]
@PointClass base(Targetname, LightAnimSpeed) = light_flicker : "Flicker Light"
[
spawnflags(Flags) =
[
1 : "Auto start" : 1
]
alarm_type(choices) : "Alarm Type" : 0 =
[
0 : "Normal only"
1 : "Alarm only"
]
color1(color255) : "Color1 (R G B)" : "255 255 255"
color2(color255) : "Color2 (R G B)" : "0 0 0"
color3(color255) : "Color3 (R G B)" : "0 0 0"
color4(color255) : "Color4 (R G B)" : "0 0 0"
color5(color255) : "Color5 (R G B)" : "0 0 0"
falloff1(integer) : "Falloff1" : 10
falloff2(integer) : "Falloff2" : 100
]
@PointClass base(Targetname, Target, LightAnimSpeed) = light_runway : "Runway Light"
[
color(color255) : "Color (R G B)" : "255 255 255"
spawnflags(Flags) =
[
1 : "Auto start" : 1
]
alarm_type(choices) : "Alarm Type" : 0 =
[
0 : "Normal only"
1 : "Alarm only"
]
pingpong(choices) : "Ping pong?" : 0 =
[
0 : "No"
1 : "Yes"
]
steps(integer) : "Steps" : 0
falloff1(integer) : "Falloff1" : 10
falloff2(integer) : "Falloff2" : 100
]
// --------------------------------------------------------------------------
// Triggers, etc...
// --------------------------------------------------------------------------
@SolidClass = trigger : "Trigger Entity"
[
name(string) : "Trigger Name" : "MustChange"
]
// --------------------------------------------------------------------------
// Doors, elevators, etc...
// --------------------------------------------------------------------------
@SolidClass = Door_Elevator : "Door or Elevator"
[
name(string) : "Name" : "MustChange"
path_name(string) : "Path subscription" : ""
trigger0_name(string) : "Trigger 0" : ""
trigger1_name(string) : "Trigger 1" : ""
trigger2_name(string) : "Trigger 2" : ""
trigger3_name(string) : "Trigger 3" : ""
trigger4_name(string) : "Trigger 4" : ""
trigger5_name(string) : "Trigger 5" : ""
trigger6_name(string) : "Trigger 6" : ""
trigger7_name(string) : "Trigger 7" : ""
]
@SolidClass = Force_Field : "Force Field"
[
name(string) : "Name" : "MustChange"
color(color255) : "Field color" : "125 216 232"
trigger0_name(string) : "Trigger 0" : ""
trigger1_name(string) : "Trigger 1" : ""
trigger2_name(string) : "Trigger 2" : ""
trigger3_name(string) : "Trigger 3" : ""
trigger4_name(string) : "Trigger 4" : ""
trigger5_name(string) : "Trigger 5" : ""
trigger6_name(string) : "Trigger 6" : ""
trigger7_name(string) : "Trigger 7" : ""
]
// --------------------------------------------------------------------------
// Paths, etc...
// --------------------------------------------------------------------------
@PointClass = path_node : "Path Node"
[
name(target_source) : "Name"
next_node(target_destination) : "Next Node"
next_time(integer) : "MS to next node" : 1000
]
@PointClass = path_start : "Path Start"
[
name(target_source) : "Name"
next_node(target_destination) : "Next Node"
next_time(integer) : "MS to next node" : 1000
]
// --------------------------------------------------------------------------
// Triggers, etc...
// --------------------------------------------------------------------------
//@SolidClass = Volume_Trigger : "Volume Trigger"
//[
// team_only(choices) : "Team Activated" : 0 =
// [
// 0 : "No"
// 1 : "Yes"
// ]
// trigger_name(string) : "Trigger Name" : ""
//]
// --------------------------------------------------------------------------
// AI Special Node - for chutes and special interior cases for Bots
// --------------------------------------------------------------------------
@PointClass = ai_special_node : "AI Special Node"
[
name(target_source) : "Name"
]
// --------------------------------------------------------------------------
// GameEntities
// --------------------------------------------------------------------------
@PointClass = game_entity : "Game Entity"
[
game_class(string) : "Game Class" : ""
datablock(string) : "Datablock" : ""
]