added everything
This commit is contained in:
1416
tools/map2difPlus/bspNode.cc
Executable file
1416
tools/map2difPlus/bspNode.cc
Executable file
File diff suppressed because it is too large
Load Diff
201
tools/map2difPlus/bspNode.h
Executable file
201
tools/map2difPlus/bspNode.h
Executable 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 "map2difPlus/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_
|
||||
|
545
tools/map2difPlus/convert.cc
Executable file
545
tools/map2difPlus/convert.cc
Executable file
@ -0,0 +1,545 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// This file contains all of the functions for converting an InteriorMap into an EditGeometry
|
||||
|
||||
#include "map2difPlus/convert.h"
|
||||
#include "dgl/gBitmap.h"
|
||||
|
||||
extern const char* gWadPath;
|
||||
extern GBitmap* loadBitmap(const char* file);
|
||||
|
||||
void CopyConvexToCSG(ConvexBrush* convex, CSGBrush* csg)
|
||||
{
|
||||
if (convex->mType == InteriorMapResource::Structural)
|
||||
csg->mBrushType = StructuralBrush;
|
||||
else if (convex->mType == InteriorMapResource::Detail)
|
||||
csg->mBrushType = DetailBrush;
|
||||
else if (convex->mType == InteriorMapResource::Portal)
|
||||
csg->mBrushType = PortalBrush;
|
||||
else if (convex->mType == InteriorMapResource::Collision)
|
||||
csg->mBrushType = CollisionBrush;
|
||||
else
|
||||
csg->mBrushType = StructuralBrush;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void loadTextures(InteriorMap* map)
|
||||
{
|
||||
// Insert the dummy textures
|
||||
gWorkingGeometry->insertTexture("NULL");
|
||||
gWorkingGeometry->insertTexture("ORIGIN");
|
||||
gWorkingGeometry->insertTexture("TRIGGER");
|
||||
//gWorkingGeometry->insertTexture("EMITTER");
|
||||
|
||||
// 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);
|
||||
|
||||
// Now find our mirror surfaces
|
||||
for (U32 i = 0; i < gWorkingGeometry->mEntities.size(); i++)
|
||||
{
|
||||
if (dynamic_cast<MirrorSurfaceEntity*>(gWorkingGeometry->mEntities[i]) != NULL)
|
||||
{
|
||||
MirrorSurfaceEntity* entity = static_cast<MirrorSurfaceEntity*>(gWorkingGeometry->mEntities[i]);
|
||||
|
||||
entity->markSurface(gWorkingGeometry->mStructuralBrushes, gWorkingGeometry->mDetailBrushes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void getBrushesForEntity(InteriorMap* map, InteriorMapResource::Entity* ent, EditGeometry::Entity* pEntity)
|
||||
{
|
||||
for (U32 i = 0; i < map->mInteriorRes->mBrushes.size(); i++)
|
||||
{
|
||||
CSGBrush* pBrush;
|
||||
|
||||
// Only load good mInteriorRes->mBrushes
|
||||
if (map->mInteriorRes->mBrushes[i]->mStatus != ConvexBrush::Good)
|
||||
continue;
|
||||
|
||||
if (map->mInteriorRes->mBrushes[i]->mOwner == ent)
|
||||
{
|
||||
pEntity->mBrushes.push_back(gBrushArena.allocateBrush());
|
||||
pBrush = pEntity->mBrushes.last();
|
||||
pBrush->mBrushType = StructuralBrush;
|
||||
|
||||
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;
|
||||
else if (dStricmp(ent->classname, DoorEntity::getClassName()) == 0)
|
||||
pEntity = new DoorEntity;
|
||||
else if (dStricmp(ent->classname, sgLightingScaleEntity::getClassName()) == 0)
|
||||
pEntity = new sgLightingScaleEntity;
|
||||
|
||||
// Path classes
|
||||
else if(dStricmp(ent->classname, PathNodeEntity::getClassName()) == 0)
|
||||
pEntity = new PathNodeEntity;
|
||||
|
||||
// Trigger Classes
|
||||
else if (dStricmp(ent->classname, TriggerEntity::getClassName()) == 0)
|
||||
pEntity = new TriggerEntity;
|
||||
|
||||
// Game Classes
|
||||
else
|
||||
pEntity = new GameEntity(ent->classname);
|
||||
|
||||
// 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);
|
||||
|
||||
// Handle entities that have brushes associated with them
|
||||
if (dStricmp(ent->classname, TriggerEntity::getClassName()) == 0)
|
||||
{
|
||||
// First snag the brushes for this entity
|
||||
getBrushesForEntity(map, ent, pEntity);
|
||||
|
||||
TriggerEntity* trigger = static_cast<TriggerEntity*>(pEntity);
|
||||
trigger->generateTrigger();
|
||||
}
|
||||
|
||||
if (dStricmp(ent->classname, DoorEntity::getClassName()) == 0)
|
||||
{
|
||||
// First snag the brushes for this entity
|
||||
getBrushesForEntity(map, ent, pEntity);
|
||||
|
||||
DoorEntity* door = static_cast<DoorEntity*>(pEntity);
|
||||
door->grabOrigin();
|
||||
}
|
||||
|
||||
if (dStricmp(ent->classname, sgLightingScaleEntity::getClassName()) == 0)
|
||||
{
|
||||
// First snag the brushes for this entity
|
||||
getBrushesForEntity(map, ent, pEntity);
|
||||
|
||||
sgLightingScaleEntity* lightScaleEnt = static_cast<sgLightingScaleEntity*>(pEntity);
|
||||
|
||||
for (U32 j = 0; j < lightScaleEnt->mBrushes.size(); j++)
|
||||
{
|
||||
CSGBrush* brush = lightScaleEnt->mBrushes[j];
|
||||
|
||||
brush->sgLightingScale = lightScaleEnt->sgGetLightingScale();
|
||||
brush->sgSelfIllumination = lightScaleEnt->sgGetSelfIllumination();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
tools/map2difPlus/convert.h
Executable file
22
tools/map2difPlus/convert.h
Executable file
@ -0,0 +1,22 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _CONVERT_H_
|
||||
#define _CONVERT_H_
|
||||
|
||||
#include "interior/interiorMap.h"
|
||||
#include "map2difPlus/csgBrush.h"
|
||||
#include "map2difPlus/morianBasics.h"
|
||||
#include "map2difPlus/editGeometry.h"
|
||||
#include "map2difPlus/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_
|
2478
tools/map2difPlus/createLightmaps.cc
Executable file
2478
tools/map2difPlus/createLightmaps.cc
Executable file
File diff suppressed because it is too large
Load Diff
269
tools/map2difPlus/createLightmaps.h
Executable file
269
tools/map2difPlus/createLightmaps.h
Executable file
@ -0,0 +1,269 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _inc_createLightMaps
|
||||
#define _inc_createLightMaps
|
||||
|
||||
#ifndef _ENTITYTYPES_H_
|
||||
#include "map2difPlus/entityTypes.h"
|
||||
#endif
|
||||
#ifndef _EDITGEOMETRY_H_
|
||||
#include "map2difPlus/editGeometry.h"
|
||||
#endif
|
||||
#ifndef _CSGBRUSH_H_
|
||||
#include "map2difPlus/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;
|
||||
|
||||
U32 sgLightingScale;
|
||||
|
||||
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
|
536
tools/map2difPlus/csgBrush.cc
Executable file
536
tools/map2difPlus/csgBrush.cc
Executable file
@ -0,0 +1,536 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
//
|
||||
// Copyright (c) 2003 GarageGames.Com
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "dgl/gBitmap.h"
|
||||
#include "map2difPlus/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);
|
||||
|
||||
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());
|
||||
|
||||
// convert tex name to upper case
|
||||
char *str = (char *) rPlane.pTextureName;
|
||||
while( *str )
|
||||
{
|
||||
*str = dToupper( (const char) *str );
|
||||
str++;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
sgLightingScale = pCopy->sgLightingScale;
|
||||
sgSelfIllumination = pCopy->sgSelfIllumination;
|
||||
|
||||
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;
|
||||
}
|
188
tools/map2difPlus/csgBrush.h
Executable file
188
tools/map2difPlus/csgBrush.h
Executable file
@ -0,0 +1,188 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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 "map2difPlus/morianBasics.h"
|
||||
#endif
|
||||
#ifndef _EDITGEOMETRY_H_
|
||||
#include "map2difPlus/editGeometry.h"
|
||||
#endif
|
||||
#ifndef _MORIANUTIL_H_
|
||||
#include "map2difPlus/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),
|
||||
sgLightingScale(32.0f),
|
||||
sgSelfIllumination(0.0f, 0.0f, 0.0f),
|
||||
pNext( NULL )
|
||||
{ }
|
||||
|
||||
Vector<CSGPlane> mPlanes;
|
||||
Point3D mMinBound;
|
||||
Point3D mMaxBound;
|
||||
|
||||
bool mIsAmbiguous;
|
||||
BrushType mBrushType;
|
||||
U32 brushId;
|
||||
U32 materialType;
|
||||
|
||||
U32 sgLightingScale;
|
||||
ColorI sgSelfIllumination;
|
||||
|
||||
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_
|
76
tools/map2difPlus/editFloorPlanRes.cc
Executable file
76
tools/map2difPlus/editFloorPlanRes.cc
Executable file
@ -0,0 +1,76 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "map2difPlus/editGeometry.h"
|
||||
#include "map2difPlus/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] ] );
|
||||
}
|
||||
}
|
30
tools/map2difPlus/editFloorPlanRes.h
Executable file
30
tools/map2difPlus/editFloorPlanRes.h
Executable 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_
|
1938
tools/map2difPlus/editGeometry.cc
Executable file
1938
tools/map2difPlus/editGeometry.cc
Executable file
File diff suppressed because it is too large
Load Diff
600
tools/map2difPlus/editGeometry.h
Executable file
600
tools/map2difPlus/editGeometry.h
Executable file
@ -0,0 +1,600 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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 "map2difPlus/morianBasics.h"
|
||||
#endif
|
||||
#ifndef _MORIANUTIL_H_
|
||||
#include "map2difPlus/morianUtil.h"
|
||||
#endif
|
||||
#ifndef _BSPNODE_H_
|
||||
#include "map2difPlus/bspNode.h"
|
||||
#endif
|
||||
#ifndef _MPLANE_H_
|
||||
#include "math/mPlane.h"
|
||||
#endif
|
||||
#ifndef _COLOR_H_
|
||||
#include "core/color.h"
|
||||
#endif
|
||||
#ifndef _EDITFLOORPLANRES_H_
|
||||
#include "map2difPlus/editFloorPlanRes.h"
|
||||
#endif
|
||||
#ifndef _INTERIOR_H_
|
||||
#include "interior/interior.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;
|
||||
|
||||
U32 sgLightingScale;
|
||||
ColorI sgSelfIllumination;
|
||||
};
|
||||
struct NullSurface {
|
||||
U32 planeIndex;
|
||||
Winding winding;
|
||||
U32 flags;
|
||||
};
|
||||
|
||||
class Entity {
|
||||
public:
|
||||
Entity() { }
|
||||
virtual ~Entity() { };
|
||||
InteriorDict mDictionary;
|
||||
Vector<CSGBrush*> mBrushes;
|
||||
|
||||
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_
|
83
tools/map2difPlus/editInteriorRes.cc
Executable file
83
tools/map2difPlus/editInteriorRes.cc
Executable file
@ -0,0 +1,83 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "dgl/gBitmap.h"
|
||||
#include "interior/interior.h"
|
||||
#include "map2difPlus/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;
|
||||
}
|
30
tools/map2difPlus/editInteriorRes.h
Executable file
30
tools/map2difPlus/editInteriorRes.h
Executable 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_
|
1537
tools/map2difPlus/entityTypes.cc
Executable file
1537
tools/map2difPlus/entityTypes.cc
Executable file
File diff suppressed because it is too large
Load Diff
568
tools/map2difPlus/entityTypes.h
Executable file
568
tools/map2difPlus/entityTypes.h
Executable file
@ -0,0 +1,568 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _ENTITYTYPES_H_
|
||||
#define _ENTITYTYPES_H_
|
||||
|
||||
//Includes
|
||||
#ifndef _MORIANBASICS_H_
|
||||
#include "map2difPlus/morianBasics.h"
|
||||
#endif
|
||||
#ifndef _EDITGEOMETRY_H_
|
||||
#include "map2difPlus/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
|
||||
#ifndef _CSGBRUSH_H_
|
||||
#include "csgBrush.h"
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//-------------------------------------- Brush based entities
|
||||
class WorldSpawnEntity : public EditGeometry::Entity
|
||||
{
|
||||
public:
|
||||
U32 mDetailNumber;
|
||||
U32 mMinPixels;
|
||||
|
||||
F32 mGeometryScale;
|
||||
|
||||
F32 mLumelScale;
|
||||
|
||||
U32 sgGetLightingScale() {return 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 sgLightingScaleEntity : public EditGeometry::Entity
|
||||
{
|
||||
public:
|
||||
F32 sgLightingScale;
|
||||
U32 sgGetLightingScale() {return sgLightingScale;}
|
||||
|
||||
ColorI sgSelfIllumination;
|
||||
ColorI sgGetSelfIllumination() {return sgSelfIllumination;}
|
||||
|
||||
public:
|
||||
sgLightingScaleEntity()
|
||||
{
|
||||
sgLightingScale = 32.0;
|
||||
sgSelfIllumination = ColorI(0, 0, 0);
|
||||
}
|
||||
~sgLightingScaleEntity() {}
|
||||
|
||||
bool parseEntityDescription(InteriorMapResource::Entity* ent);
|
||||
BrushType getBrushType() {return StructuralBrush;}
|
||||
bool isPointClass() const {return false;}
|
||||
const char* getName() const
|
||||
{
|
||||
static char bogoChar = '\0';
|
||||
return &bogoChar;
|
||||
}
|
||||
const Point3D& getOrigin() const
|
||||
{
|
||||
static Point3D bogoPoint(0, 0, 0);
|
||||
return bogoPoint;
|
||||
}
|
||||
static const char* getClassName() {return "sgLightingScaleEntity";}
|
||||
};
|
||||
|
||||
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&);
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//-------------------------------------- PATH TYPES
|
||||
//
|
||||
class PathNodeEntity : public EditGeometry::Entity
|
||||
{
|
||||
public:
|
||||
Point3D mOrigin;
|
||||
|
||||
S32 mNumMSToNextNode;
|
||||
U32 mSmoothingType;
|
||||
|
||||
public:
|
||||
PathNodeEntity();
|
||||
~PathNodeEntity();
|
||||
BrushType getBrushType();
|
||||
bool parseEntityDescription(InteriorMapResource::Entity* ent);
|
||||
|
||||
static const char* getClassName() { return "path_node"; }
|
||||
const char* getName() const { return("a_path_node"); }
|
||||
const Point3D& getOrigin() const { return mOrigin; }
|
||||
bool isPointClass() const { return true; }
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//-------------------------------------- Trigger types
|
||||
//
|
||||
class TriggerEntity : public EditGeometry::Entity
|
||||
{
|
||||
public:
|
||||
char mName[256];
|
||||
char mDataBlock[256];
|
||||
Point3D mOrigin;
|
||||
|
||||
bool mValid;
|
||||
|
||||
Polyhedron triggerPolyhedron;
|
||||
|
||||
U32 mCurrBrushId;
|
||||
|
||||
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; }
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//-------------------------------------- REALLY REALLY SPECIAL TYPES
|
||||
//
|
||||
static Point3D gOrigin(0, 0, 0);
|
||||
|
||||
class DoorEntity : public EditGeometry::Entity
|
||||
{
|
||||
public:
|
||||
Point3D mOrigin;
|
||||
char mName[256];
|
||||
char mPath[256];
|
||||
char mDataBlock[256];
|
||||
Vector<U32> mTriggerIds;
|
||||
VectorPtr<InteriorPathFollower::WayPoint*> mWayPoints;
|
||||
U32 mTotalMS;
|
||||
|
||||
U32 mCurrBrushId;
|
||||
|
||||
Interior* mInterior;
|
||||
|
||||
void grabOrigin();
|
||||
|
||||
public:
|
||||
DoorEntity();
|
||||
~DoorEntity();
|
||||
void process();
|
||||
|
||||
void addPathNode(PathNodeEntity *ent);
|
||||
static const char* getClassName() { return("Door_Elevator"); }
|
||||
bool parseEntityDescription(InteriorMapResource::Entity* ent);
|
||||
const char* getName() const { return mName; }
|
||||
const Point3D& getOrigin() const { return gOrigin; }
|
||||
BrushType getBrushType();
|
||||
|
||||
// ok, not really, but as far as the parser is concered, yes.
|
||||
bool isPointClass() const { return true; }
|
||||
};
|
||||
|
||||
class GameEntity : public EditGeometry::Entity
|
||||
{
|
||||
public:
|
||||
Point3D mOrigin;
|
||||
|
||||
char mDataBlock[1024];
|
||||
char mGameClass[1024];
|
||||
|
||||
public:
|
||||
GameEntity(const char *gameClassName);
|
||||
~GameEntity();
|
||||
BrushType getBrushType();
|
||||
bool parseEntityDescription(InteriorMapResource::Entity* ent);
|
||||
|
||||
static const char* getClassName() { return "game_entity_unused"; }
|
||||
const char* getName() const { return NULL; }
|
||||
const Point3D& getOrigin() const { return mOrigin; }
|
||||
bool isPointClass() const { return true; }
|
||||
};
|
||||
|
||||
#endif //_ENTITYTYPES_H_
|
2426
tools/map2difPlus/exportGeometry.cc
Executable file
2426
tools/map2difPlus/exportGeometry.cc
Executable file
File diff suppressed because it is too large
Load Diff
498
tools/map2difPlus/lmapPacker.cc
Executable file
498
tools/map2difPlus/lmapPacker.cc
Executable file
@ -0,0 +1,498 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "map2difPlus/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);
|
||||
|
||||
|
||||
// Better border color, so we can remove the border size! - John Kabus
|
||||
/*if (overflow == false)
|
||||
{
|
||||
pDst[0] = 0xFF;
|
||||
pDst[1] = 0x00;
|
||||
pDst[2] = 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
pDst[0] = 0x00;
|
||||
pDst[1] = 0xFF;
|
||||
pDst[2] = 0x00;
|
||||
}*/
|
||||
|
||||
pDst[0] = 63;
|
||||
pDst[1] = 63;
|
||||
pDst[2] = 63;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
75
tools/map2difPlus/lmapPacker.h
Executable file
75
tools/map2difPlus/lmapPacker.h
Executable 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 2
|
||||
|
||||
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_
|
528
tools/map2difPlus/main.cc
Executable file
528
tools/map2difPlus/main.cc
Executable file
@ -0,0 +1,528 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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 "map2difPlus/editGeometry.h"
|
||||
#include "interior/interior.h"
|
||||
#include "map2difPlus/editInteriorRes.h"
|
||||
#include "interior/floorPlanRes.h"
|
||||
#include "map2difPlus/morianGame.h"
|
||||
#include "core/frameAllocator.h"
|
||||
#include "gui/core/guiCanvas.h"
|
||||
#include "map2difPlus/lmapPacker.h"
|
||||
#include "map2difPlus/convert.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
MorianGame GameObject;
|
||||
|
||||
// FOR SILLY LINK DEPENDANCY
|
||||
bool gEditingMission = false;
|
||||
bool gDedicatedServer = 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)
|
||||
{
|
||||
Interior::smFileVersion = 0;
|
||||
|
||||
// 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();
|
||||
|
||||
// Process any special entitys...
|
||||
for (U32 i = 0; i < gWorkingGeometry->mEntities.size(); i++)
|
||||
{
|
||||
DoorEntity* pDoor = dynamic_cast<DoorEntity*>(gWorkingGeometry->mEntities[i]);
|
||||
if (pDoor != NULL)
|
||||
pDoor->process();
|
||||
}
|
||||
|
||||
// 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 )
|
||||
{
|
||||
|
||||
}
|
105
tools/map2difPlus/morianBasics.h
Executable file
105
tools/map2difPlus/morianBasics.h
Executable 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_
|
19
tools/map2difPlus/morianGame.h
Executable file
19
tools/map2difPlus/morianGame.h
Executable 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_
|
1062
tools/map2difPlus/morianUtil.cc
Executable file
1062
tools/map2difPlus/morianUtil.cc
Executable file
File diff suppressed because it is too large
Load Diff
80
tools/map2difPlus/morianUtil.h
Executable file
80
tools/map2difPlus/morianUtil.h
Executable 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 "map2difPlus/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_
|
||||
|
165
tools/map2difPlus/navGraph.cc
Executable file
165
tools/map2difPlus/navGraph.cc
Executable 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 "map2difPlus/editGeometry.h"
|
||||
#include "map2difPlus/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();
|
||||
}
|
||||
|
336
tools/map2difPlus/torque.fgd
Executable file
336
tools/map2difPlus/torque.fgd
Executable file
@ -0,0 +1,336 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 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"
|
||||
]
|
||||
|
||||
@SolidClass = sgLightingScaleEntity : "Synapse Gaming Lighting Scale Entity"
|
||||
[
|
||||
light_geometry_scale(string) : "Lighting scale (must be a power of 2)" : "32.0"
|
||||
self_illumination_color(color255) : "Self-Illumination 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"
|
||||
datablock(string) : "Datablock" : ""
|
||||
]
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Doors, elevators, etc...
|
||||
// --------------------------------------------------------------------------
|
||||
@SolidClass = Door_Elevator : "Door or Elevator"
|
||||
[
|
||||
name(string) : "Name" : "MustChange"
|
||||
path_name(string) : "Path Name" : ""
|
||||
datablock(string) : "Datablock" : ""
|
||||
]
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Paths, etc...
|
||||
// --------------------------------------------------------------------------
|
||||
@PointClass = path_node : "Path Node"
|
||||
[
|
||||
next_time(integer) : "MS to next node" : 1000
|
||||
smoothing(integer) : "Smoothing Mode" : 2
|
||||
]
|
||||
|
||||
//@PointClass = path_start : "Path Start"
|
||||
//[
|
||||
// name(target_source) : "Name"
|
||||
// next_node(target_destination) : "Next Node"
|
||||
// next_time(integer) : "MS to next node" : 1000
|
||||
//]
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// GameEntities
|
||||
// --------------------------------------------------------------------------
|
||||
@PointClass = game_entity : "Game Entity"
|
||||
[
|
||||
game_class(string) : "Game Class" : ""
|
||||
datablock(string) : "Datablock" : ""
|
||||
]
|
Reference in New Issue
Block a user