added everything
This commit is contained in:
121
engine/interior/floorPlanRes.cc
Executable file
121
engine/interior/floorPlanRes.cc
Executable file
@ -0,0 +1,121 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "core/stream.h"
|
||||
#include "interior/floorPlanRes.h"
|
||||
#include "math/mathIO.h"
|
||||
|
||||
const U32 FloorPlanResource::smFileVersion = 0;
|
||||
|
||||
FloorPlanResource::FloorPlanResource()
|
||||
{
|
||||
}
|
||||
FloorPlanResource::~FloorPlanResource()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Define these so we can just write two vector IO functions
|
||||
|
||||
static bool mathRead(Stream & S, FloorPlanResource::Area * a){
|
||||
return S.read(&a->pointCount) && S.read(&a->pointStart) && S.read(&a->plane);
|
||||
}
|
||||
static bool mathWrite(Stream & S, const FloorPlanResource::Area & a){
|
||||
return S.write(a.pointCount) && S.write(a.pointStart) && S.write(a.plane);
|
||||
}
|
||||
inline bool mathRead(Stream & S, S32 * s) { return S.read(s); }
|
||||
inline bool mathWrite(Stream & S, S32 s) { return S.write(s); }
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Read a vector of items which define mathRead().
|
||||
template <class T>
|
||||
bool mathReadVector(Vector<T> & vec, Stream & stream, const char * msg)
|
||||
{
|
||||
U32 num, i;
|
||||
bool Ok = true;
|
||||
stream.read( & num );
|
||||
vec.setSize( num );
|
||||
for( i = 0; i < num && Ok; i++ ){
|
||||
Ok = mathRead(stream, & vec[i]);
|
||||
AssertISV( Ok, avar("math vec read error (%s) on elem %d", msg, i) );
|
||||
}
|
||||
return Ok;
|
||||
}
|
||||
// Write a vector of items which define mathWrite().
|
||||
template <class T>
|
||||
bool mathWriteVector(const Vector<T> & vec, Stream & stream, const char * msg)
|
||||
{
|
||||
bool Ok = true;
|
||||
stream.write( vec.size() );
|
||||
for( U32 i = 0; i < vec.size() && Ok; i++ ) {
|
||||
Ok = mathWrite(stream, vec[i]);
|
||||
AssertISV( Ok, avar("math vec write error (%s) on elem %d", msg, i) );
|
||||
}
|
||||
return Ok;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
bool FloorPlanResource::read(Stream& stream)
|
||||
{
|
||||
AssertFatal(stream.hasCapability(Stream::StreamRead), "FLR::read: non-readable stream");
|
||||
AssertFatal(stream.getStatus() == Stream::Ok, "FLR::read: Error, weird stream state");
|
||||
|
||||
// Version this stream
|
||||
U32 fileVersion, DohVal;
|
||||
stream.read(&fileVersion);
|
||||
if (fileVersion != smFileVersion) {
|
||||
AssertFatal(false, "FLR::read: incompatible file version found.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// For expansion purposes
|
||||
stream.read(&DohVal); stream.read(&DohVal); stream.read(&DohVal);
|
||||
|
||||
// Read the vectors
|
||||
mathReadVector( mPlaneTable, stream, "FLR: mPlaneTable" );
|
||||
mathReadVector( mPointTable, stream, "FLR: mPointTable" );
|
||||
mathReadVector( mPointLists, stream, "FLR: mPointLists" );
|
||||
mathReadVector( mAreas, stream, "FLR: mAreas" );
|
||||
|
||||
return (stream.getStatus() == Stream::Ok);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
bool FloorPlanResource::write(Stream& stream) const
|
||||
{
|
||||
AssertFatal(stream.hasCapability(Stream::StreamWrite), "FLR::write: non-writeable stream");
|
||||
AssertFatal(stream.getStatus() == Stream::Ok, "FLR::write: Error, weird stream state");
|
||||
|
||||
// Version the stream
|
||||
stream.write(smFileVersion);
|
||||
|
||||
U32 Doh = 0xD0bD0b; // So we don't later say Doh!
|
||||
stream.write(Doh); stream.write(Doh); stream.write(Doh);
|
||||
|
||||
// Write the vectors
|
||||
mathWriteVector( mPlaneTable, stream, "FLR: mPlaneTable" );
|
||||
mathWriteVector( mPointTable, stream, "FLR: mPointTable" );
|
||||
mathWriteVector( mPointLists, stream, "FLR: mPointLists" );
|
||||
mathWriteVector( mAreas, stream, "FLR: mAreas" );
|
||||
|
||||
return( stream.getStatus() == Stream::Ok );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// FloorPlan Resource constructor
|
||||
//
|
||||
ResourceInstance * constructFloorPlanFLR(Stream& stream)
|
||||
{
|
||||
FloorPlanResource * pResource = new FloorPlanResource;
|
||||
|
||||
if (pResource->read(stream) == true)
|
||||
return pResource;
|
||||
else {
|
||||
delete pResource;
|
||||
return NULL;
|
||||
}
|
||||
}
|
50
engine/interior/floorPlanRes.h
Executable file
50
engine/interior/floorPlanRes.h
Executable file
@ -0,0 +1,50 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _FLOORPLANRES_H_
|
||||
#define _FLOORPLANRES_H_
|
||||
|
||||
#ifndef _RESMANAGER_H_
|
||||
#include "core/resManager.h"
|
||||
#endif
|
||||
#ifndef _MPOINT_H_
|
||||
#include "math/mPoint.h"
|
||||
#endif
|
||||
#ifndef _MPLANE_H_
|
||||
#include "math/mPlane.h"
|
||||
#endif
|
||||
class Stream;
|
||||
|
||||
class FloorPlanResource : public ResourceInstance
|
||||
{
|
||||
typedef ResourceInstance Parent;
|
||||
static const U32 smFileVersion;
|
||||
|
||||
public:
|
||||
struct Area // basically a Winding, the info we need from it
|
||||
{
|
||||
S16 pointCount;
|
||||
S32 pointStart;
|
||||
S32 plane;
|
||||
Area(S16 C, S32 S, S32 P) { pointCount=C; pointStart=S; plane=P; }
|
||||
};
|
||||
|
||||
protected:
|
||||
Vector<PlaneF> mPlaneTable;
|
||||
Vector<Point3F> mPointTable;
|
||||
Vector<S32> mPointLists;
|
||||
Vector<Area> mAreas;
|
||||
|
||||
public:
|
||||
FloorPlanResource();
|
||||
~FloorPlanResource();
|
||||
|
||||
bool read(Stream& stream);
|
||||
bool write(Stream& stream) const;
|
||||
};
|
||||
|
||||
extern ResourceInstance * constructFloorPlanFLR(Stream& stream);
|
||||
|
||||
#endif // _H_FLOORPLANRES_
|
72
engine/interior/fogCalc.h
Executable file
72
engine/interior/fogCalc.h
Executable file
@ -0,0 +1,72 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef __FOG_CALC_H__
|
||||
#define __FOG_CALC_H__
|
||||
|
||||
#include "sceneGraph/sceneState.h"
|
||||
#include "sceneGraph/sceneGraph.h"
|
||||
|
||||
|
||||
// This class is a fancy inlined implementation of the fog calculations with all invariants moved
|
||||
// into the constructor.
|
||||
class FogCalc
|
||||
{
|
||||
public:
|
||||
FogCalc::FogCalc( const PlaneF &dPlane, F32 distOffset, const Point3F &zVec, F32 worldZ, F32 worldPz, const SceneState *state )
|
||||
: fc_distOffset( distOffset ),
|
||||
fc_newWorldZ( worldZ - worldPz ),
|
||||
fc_fogDistance( state->getFogDistance() ),
|
||||
fc_visibleDistance( state->getVisibleDistance() ),
|
||||
fc_fogScale( state->getFogScale() ),
|
||||
fc_PosFogBands( state->getPosFogBands() ),
|
||||
fc_NegFogBands( state->getNegFogBands() ),
|
||||
distPlane( dPlane ),
|
||||
osZVec( zVec ),
|
||||
sState( state )
|
||||
{
|
||||
// For Textured
|
||||
F32 heightOffset;
|
||||
|
||||
gClientSceneGraph->getFogCoordData( tex_invVisibleDistance, heightOffset, tex_invHeightRange );
|
||||
|
||||
tex_visibleDistanceMod = gClientSceneGraph->getVisibleDistanceMod() - distOffset - distPlane.d;
|
||||
tex_newWorldZ = worldZ - heightOffset;
|
||||
}
|
||||
|
||||
inline F32 calcFC( const Point3F &point ) const
|
||||
{
|
||||
return( sState->getHazeAndFog(mFabs(distPlane.distToPlane(point)) + fc_distOffset, (mDot(point, osZVec) + fc_newWorldZ) ) );
|
||||
}
|
||||
|
||||
inline const Point2F calcTextured( const Point3F &point ) const
|
||||
{
|
||||
// inline version of SceneGraph::getFogCoordPair
|
||||
return( Point2F(
|
||||
(tex_visibleDistanceMod - (point.x * distPlane.x + point.y * distPlane.y + point.z * distPlane.z)) * tex_invVisibleDistance,
|
||||
(tex_newWorldZ + point.x * osZVec.x + point.y * osZVec.y + point.z * osZVec.z) * tex_invHeightRange
|
||||
) );
|
||||
}
|
||||
|
||||
private:
|
||||
const F32 fc_distOffset;
|
||||
const F32 fc_newWorldZ;
|
||||
const F32 fc_fogDistance;
|
||||
const F32 fc_visibleDistance;
|
||||
const F32 fc_fogScale;
|
||||
const Vector<SceneState::FogBand> *fc_PosFogBands;
|
||||
const Vector<SceneState::FogBand> *fc_NegFogBands;
|
||||
|
||||
F32 tex_invVisibleDistance;
|
||||
F32 tex_invHeightRange;
|
||||
F32 tex_visibleDistanceMod;
|
||||
F32 tex_newWorldZ;
|
||||
|
||||
const PlaneF distPlane;
|
||||
const Point3F osZVec;
|
||||
const SceneState *sState;
|
||||
};
|
||||
|
||||
#endif //__OK_FOG_CALC_H__
|
469
engine/interior/forceField.cc
Executable file
469
engine/interior/forceField.cc
Executable file
@ -0,0 +1,469 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "interior/forceField.h"
|
||||
#include "core/stream.h"
|
||||
#include "math/mathIO.h"
|
||||
#include "console/console.h"
|
||||
#include "dgl/gTexManager.h"
|
||||
#include "dgl/dgl.h"
|
||||
#include "collision/abstractPolyList.h"
|
||||
#include "sim/sceneObject.h"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ForceField::ForceField()
|
||||
{
|
||||
mPreppedForRender = false;
|
||||
mWhite = NULL;
|
||||
}
|
||||
|
||||
ForceField::~ForceField()
|
||||
{
|
||||
mPreppedForRender = false;
|
||||
|
||||
delete mWhite;
|
||||
mWhite = NULL;
|
||||
}
|
||||
|
||||
|
||||
bool ForceField::prepForRendering()
|
||||
{
|
||||
if (mPreppedForRender == true)
|
||||
return true;
|
||||
|
||||
mPreppedForRender = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void ForceField::render(const ColorF& rColor, const F32 fade)
|
||||
{
|
||||
// All our transform what not has already been specified...
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Point3F), mPoints.address());
|
||||
glEnable(GL_VERTEX_ARRAY);
|
||||
|
||||
for (U32 i = 0; i < mSurfaces.size(); i++) {
|
||||
Surface& rSurface = mSurfaces[i];
|
||||
|
||||
glColor4f(rColor.red, rColor.green, rColor.blue, fade);
|
||||
glBegin(GL_TRIANGLE_STRIP);
|
||||
for (U32 j = rSurface.windingStart; j < rSurface.windingStart + rSurface.windingCount; j++)
|
||||
glArrayElement(mWindings[j]);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
glDisable(GL_VERTEX_ARRAY);
|
||||
glDisable(GL_CULL_FACE);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//-------------------------------------- Persistence interfaces
|
||||
//
|
||||
const U32 ForceField::smFileVersion = 0;
|
||||
|
||||
bool ForceField::read(Stream& stream)
|
||||
{
|
||||
AssertFatal(stream.hasCapability(Stream::StreamRead), "ForceField::read: non-read capable stream passed");
|
||||
AssertFatal(stream.getStatus() == Stream::Ok, "ForceField::read: Error, stream in inconsistent state");
|
||||
|
||||
U32 i;
|
||||
|
||||
// Version this stream
|
||||
U32 fileVersion;
|
||||
stream.read(&fileVersion);
|
||||
if (fileVersion != smFileVersion) {
|
||||
Con::errorf(ConsoleLogEntry::General, "ForceField::read: incompatible file version found.");
|
||||
return false;
|
||||
}
|
||||
|
||||
mName = stream.readSTString();
|
||||
U32 numTriggers;
|
||||
stream.read(&numTriggers);
|
||||
mTriggers.setSize(numTriggers);
|
||||
for (i = 0; i < mTriggers.size(); i++)
|
||||
mTriggers[i] = stream.readSTString();
|
||||
|
||||
// Geometry factors...
|
||||
mathRead(stream, &mBoundingBox);
|
||||
mathRead(stream, &mBoundingSphere);
|
||||
|
||||
// Now read in our data vectors.
|
||||
U32 vectorSize;
|
||||
// mPlanes
|
||||
readPlaneVector(stream);
|
||||
|
||||
// mPoints
|
||||
stream.read(&vectorSize);
|
||||
mPoints.setSize(vectorSize);
|
||||
for (i = 0; i < mPoints.size(); i++)
|
||||
mathRead(stream, &mPoints[i]);
|
||||
|
||||
// mBSPNodes;
|
||||
stream.read(&vectorSize);
|
||||
mBSPNodes.setSize(vectorSize);
|
||||
for (i = 0; i < mBSPNodes.size(); i++) {
|
||||
stream.read(&mBSPNodes[i].planeIndex);
|
||||
stream.read(&mBSPNodes[i].frontIndex);
|
||||
stream.read(&mBSPNodes[i].backIndex);
|
||||
}
|
||||
|
||||
// mBSPSolidLeaves
|
||||
stream.read(&vectorSize);
|
||||
mBSPSolidLeaves.setSize(vectorSize);
|
||||
for (i = 0; i < mBSPSolidLeaves.size(); i++) {
|
||||
stream.read(&mBSPSolidLeaves[i].surfaceIndex);
|
||||
stream.read(&mBSPSolidLeaves[i].surfaceCount);
|
||||
}
|
||||
|
||||
// mWindings
|
||||
stream.read(&vectorSize);
|
||||
mWindings.setSize(vectorSize);
|
||||
for (i = 0; i < mWindings.size(); i++) {
|
||||
stream.read(&mWindings[i]);
|
||||
}
|
||||
|
||||
// mSurfaces
|
||||
stream.read(&vectorSize);
|
||||
mSurfaces.setSize(vectorSize);
|
||||
for (i = 0; i < mSurfaces.size(); i++) {
|
||||
stream.read(&mSurfaces[i].windingStart);
|
||||
stream.read(&mSurfaces[i].windingCount);
|
||||
stream.read(&mSurfaces[i].planeIndex);
|
||||
stream.read(&mSurfaces[i].surfaceFlags);
|
||||
stream.read(&mSurfaces[i].fanMask);
|
||||
}
|
||||
|
||||
// mSolidLeafSurfaces
|
||||
stream.read(&vectorSize);
|
||||
mSolidLeafSurfaces.setSize(vectorSize);
|
||||
for (i = 0; i < mSolidLeafSurfaces.size(); i++) {
|
||||
stream.read(&mSolidLeafSurfaces[i]);
|
||||
}
|
||||
|
||||
stream.read(&mColor);
|
||||
|
||||
return stream.getStatus() == Stream::Ok;
|
||||
}
|
||||
|
||||
bool ForceField::write(Stream& stream) const
|
||||
{
|
||||
AssertFatal(stream.hasCapability(Stream::StreamWrite), "Interior::write: non-write capable stream passed");
|
||||
AssertFatal(stream.getStatus() == Stream::Ok, "Interior::write: Error, stream in inconsistent state");
|
||||
|
||||
U32 i;
|
||||
|
||||
// Version this stream
|
||||
stream.write(smFileVersion);
|
||||
|
||||
stream.writeString(mName);
|
||||
stream.write(mTriggers.size());
|
||||
for (i = 0; i < mTriggers.size(); i++)
|
||||
stream.writeString(mTriggers[i]);
|
||||
|
||||
mathWrite(stream, mBoundingBox);
|
||||
mathWrite(stream, mBoundingSphere);
|
||||
|
||||
// Now write out our data vectors. Remember, for cross-platform capability, no
|
||||
// structure writing is allowed...
|
||||
|
||||
// mPlanes
|
||||
writePlaneVector(stream);
|
||||
|
||||
// mPoints
|
||||
stream.write(mPoints.size());
|
||||
for (i = 0; i < mPoints.size(); i++)
|
||||
mathWrite(stream, mPoints[i]);
|
||||
|
||||
// mBSPNodes;
|
||||
stream.write(mBSPNodes.size());
|
||||
for (i = 0; i < mBSPNodes.size(); i++) {
|
||||
stream.write(mBSPNodes[i].planeIndex);
|
||||
stream.write(mBSPNodes[i].frontIndex);
|
||||
stream.write(mBSPNodes[i].backIndex);
|
||||
}
|
||||
|
||||
// mBSPSolidLeaves
|
||||
stream.write(mBSPSolidLeaves.size());
|
||||
for (i = 0; i < mBSPSolidLeaves.size(); i++) {
|
||||
stream.write(mBSPSolidLeaves[i].surfaceIndex);
|
||||
stream.write(mBSPSolidLeaves[i].surfaceCount);
|
||||
}
|
||||
|
||||
// mWindings
|
||||
stream.write(mWindings.size());
|
||||
for (i = 0; i < mWindings.size(); i++) {
|
||||
stream.write(mWindings[i]);
|
||||
}
|
||||
|
||||
// mSurfaces
|
||||
stream.write(mSurfaces.size());
|
||||
for (i = 0; i < mSurfaces.size(); i++) {
|
||||
stream.write(mSurfaces[i].windingStart);
|
||||
stream.write(mSurfaces[i].windingCount);
|
||||
stream.write(mSurfaces[i].planeIndex);
|
||||
stream.write(mSurfaces[i].surfaceFlags);
|
||||
stream.write(mSurfaces[i].fanMask);
|
||||
}
|
||||
|
||||
// mSolidLeafSurfaces
|
||||
stream.write(mSolidLeafSurfaces.size());
|
||||
for (i = 0; i < mSolidLeafSurfaces.size(); i++) {
|
||||
stream.write(mSolidLeafSurfaces[i]);
|
||||
}
|
||||
|
||||
stream.write(mColor);
|
||||
|
||||
return stream.getStatus() == Stream::Ok;
|
||||
}
|
||||
|
||||
bool ForceField::writePlaneVector(Stream& stream) const
|
||||
{
|
||||
// This is pretty slow, but who cares?
|
||||
//
|
||||
Vector<Point3F> uniqueNormals(mPlanes.size());
|
||||
Vector<U16> uniqueIndices(mPlanes.size());
|
||||
|
||||
U32 i;
|
||||
|
||||
for (i = 0; i < mPlanes.size(); i++) {
|
||||
bool inserted = false;
|
||||
for (U32 j = 0; j < uniqueNormals.size(); j++) {
|
||||
if (mPlanes[i] == uniqueNormals[j]) {
|
||||
// Hah! Already have this one...
|
||||
uniqueIndices.push_back(j);
|
||||
inserted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (inserted == false) {
|
||||
// Gotta do it ourselves...
|
||||
uniqueIndices.push_back(uniqueNormals.size());
|
||||
uniqueNormals.push_back(Point3F(mPlanes[i].x, mPlanes[i].y, mPlanes[i].z));
|
||||
}
|
||||
}
|
||||
|
||||
// Ok, what we have now, is a list of unique normals, a set of indices into
|
||||
// that vector, and the distances that we still have to write out by hand.
|
||||
// Hop to it!
|
||||
stream.write(uniqueNormals.size());
|
||||
for (i = 0; i < uniqueNormals.size(); i++)
|
||||
mathWrite(stream, uniqueNormals[i]);
|
||||
|
||||
stream.write(mPlanes.size());
|
||||
for (i = 0; i < mPlanes.size(); i++) {
|
||||
stream.write(uniqueIndices[i]);
|
||||
stream.write(mPlanes[i].d);
|
||||
}
|
||||
|
||||
return (stream.getStatus() == Stream::Ok);
|
||||
}
|
||||
|
||||
bool ForceField::readPlaneVector(Stream& stream)
|
||||
{
|
||||
Vector<Point3F> normals;
|
||||
U32 vectorSize;
|
||||
|
||||
stream.read(&vectorSize);
|
||||
normals.setSize(vectorSize);
|
||||
U32 i;
|
||||
for (i = 0; i < normals.size(); i++)
|
||||
mathRead(stream, &normals[i]);
|
||||
|
||||
U16 index;
|
||||
stream.read(&vectorSize);
|
||||
mPlanes.setSize(vectorSize);
|
||||
for (i = 0; i < mPlanes.size(); i++) {
|
||||
stream.read(&index);
|
||||
stream.read(&mPlanes[i].d);
|
||||
mPlanes[i].x = normals[index].x;
|
||||
mPlanes[i].y = normals[index].y;
|
||||
mPlanes[i].z = normals[index].z;
|
||||
}
|
||||
|
||||
return (stream.getStatus() == Stream::Ok);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//-------------------------------------- Collision support. Essentially
|
||||
// copied from the interiorCollision
|
||||
//
|
||||
void ForceField::collisionFanFromSurface(const Surface& rSurface, U32* fanIndices, U32* numIndices) const
|
||||
{
|
||||
U32 tempIndices[32];
|
||||
|
||||
tempIndices[0] = 0;
|
||||
U32 idx = 1;
|
||||
U32 i;
|
||||
for (i = 1; i < rSurface.windingCount; i += 2)
|
||||
tempIndices[idx++] = i;
|
||||
for (i = ((rSurface.windingCount - 1) & (~0x1)); i > 0; i -= 2)
|
||||
tempIndices[idx++] = i;
|
||||
|
||||
idx = 0;
|
||||
for (i = 0; i < rSurface.windingCount; i++) {
|
||||
if (rSurface.fanMask & (1 << i)) {
|
||||
fanIndices[idx++] = mWindings[rSurface.windingStart + tempIndices[i]];
|
||||
}
|
||||
}
|
||||
*numIndices = idx;
|
||||
}
|
||||
|
||||
bool ForceField::castRay(const Point3F& s, const Point3F& e, RayInfo* info)
|
||||
{
|
||||
bool hit = castRay_r(0, s, e, info);
|
||||
if (hit) {
|
||||
Point3F vec = e - s;
|
||||
F32 len = vec.len();
|
||||
vec /= len;
|
||||
info->t = mDot(info->point - s, vec) / len;
|
||||
}
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
||||
bool ForceField::castRay_r(const U16 node,
|
||||
const Point3F& s,
|
||||
const Point3F& e,
|
||||
RayInfo* info)
|
||||
{
|
||||
if (isBSPLeafIndex(node) == false) {
|
||||
const IBSPNode& rNode = mBSPNodes[node];
|
||||
const PlaneF& rPlane = getPlane(rNode.planeIndex);
|
||||
|
||||
PlaneF::Side sSide = rPlane.whichSide(s);
|
||||
PlaneF::Side eSide = rPlane.whichSide(e);
|
||||
|
||||
switch (PlaneSwitchCode(sSide, eSide)) {
|
||||
case PlaneSwitchCode(PlaneF::Front, PlaneF::Front):
|
||||
case PlaneSwitchCode(PlaneF::Front, PlaneF::On):
|
||||
case PlaneSwitchCode(PlaneF::On, PlaneF::Front):
|
||||
return castRay_r(rNode.frontIndex, s, e, info);
|
||||
break;
|
||||
|
||||
case PlaneSwitchCode(PlaneF::On, PlaneF::Back):
|
||||
case PlaneSwitchCode(PlaneF::Back, PlaneF::On):
|
||||
case PlaneSwitchCode(PlaneF::Back, PlaneF::Back):
|
||||
return castRay_r(rNode.backIndex, s, e, info);
|
||||
break;
|
||||
|
||||
case PlaneSwitchCode(PlaneF::On, PlaneF::On):
|
||||
// Line lies on the plane
|
||||
if (isBSPLeafIndex(rNode.backIndex) == false) {
|
||||
if (castRay_r(rNode.backIndex, s, e, info))
|
||||
return true;
|
||||
}
|
||||
if (isBSPLeafIndex(rNode.frontIndex) == false) {
|
||||
if (castRay_r(rNode.frontIndex, s, e, info))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
break;
|
||||
|
||||
case PlaneSwitchCode(PlaneF::Front, PlaneF::Back): {
|
||||
Point3F ip;
|
||||
F32 intersectT = rPlane.intersect(s, e);
|
||||
AssertFatal(intersectT != PARALLEL_PLANE, "Error, this should never happen in this case!");
|
||||
ip.interpolate(s, e, intersectT);
|
||||
if (castRay_r(rNode.frontIndex, s, ip, info))
|
||||
return true;
|
||||
return castRay_r(rNode.backIndex, ip, e, info);
|
||||
}
|
||||
break;
|
||||
|
||||
case PlaneSwitchCode(PlaneF::Back, PlaneF::Front): {
|
||||
Point3F ip;
|
||||
F32 intersectT = rPlane.intersect(s, e);
|
||||
AssertFatal(intersectT != PARALLEL_PLANE, "Error, this should never happen in this case!");
|
||||
ip.interpolate(s, e, intersectT);
|
||||
if (castRay_r(rNode.backIndex, s, ip, info))
|
||||
return true;
|
||||
return castRay_r(rNode.frontIndex, ip, e, info);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
AssertFatal(false, "Misunderstood switchCode in ForceField::castRay_r");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isBSPSolidLeaf(node)) {
|
||||
// DMM: Set material info here
|
||||
info->point = s;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ForceField::buildPolyList_r(const U16 node, Vector<U16>& collPlanes, AbstractPolyList* list, SphereF& s)
|
||||
{
|
||||
if (isBSPLeafIndex(node) == false) {
|
||||
const IBSPNode& rNode = mBSPNodes[node];
|
||||
const PlaneF& rPlane = getPlane(rNode.planeIndex);
|
||||
|
||||
F32 dist = rPlane.distToPlane(s.center);
|
||||
if (mFabs(dist) <= s.radius) {
|
||||
// Have to do both, and push the plane back on the list...
|
||||
collPlanes.push_back(rNode.planeIndex);
|
||||
buildPolyList_r(rNode.frontIndex, collPlanes, list, s);
|
||||
buildPolyList_r(rNode.backIndex, collPlanes, list, s);
|
||||
collPlanes.pop_back();
|
||||
} else if (dist > 0.0f) {
|
||||
buildPolyList_r(rNode.frontIndex, collPlanes, list, s);
|
||||
} else {
|
||||
buildPolyList_r(rNode.backIndex, collPlanes, list, s);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (isBSPSolidLeaf(node)) {
|
||||
const IBSPLeafSolid& rLeaf = mBSPSolidLeaves[getBSPSolidLeafIndex(node)];
|
||||
for (U32 i = 0; i < rLeaf.surfaceCount; i++) {
|
||||
U32 surfaceIndex = mSolidLeafSurfaces[rLeaf.surfaceIndex + i];
|
||||
const Surface& rSurface = mSurfaces[surfaceIndex];
|
||||
for (U32 j = 0; j < collPlanes.size(); j++) {
|
||||
if (areEqualPlanes(rSurface.planeIndex, collPlanes[j]) == true) {
|
||||
|
||||
U32 fanVerts[32];
|
||||
U32 numVerts;
|
||||
collisionFanFromSurface(rSurface, fanVerts, &numVerts);
|
||||
|
||||
// DMM: Material here
|
||||
list->begin(0, rSurface.planeIndex);
|
||||
|
||||
U32 vertStart = list->addPoint(mPoints[fanVerts[0]]);
|
||||
list->vertex(vertStart);
|
||||
for (U32 k = 1; k < numVerts; k++) {
|
||||
list->addPoint(mPoints[fanVerts[k]]);
|
||||
list->vertex(vertStart + k);
|
||||
}
|
||||
list->plane(vertStart, vertStart + 1, vertStart + 2);
|
||||
list->end();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ForceField::buildPolyList(AbstractPolyList* list, SphereF& sphere)
|
||||
{
|
||||
Vector<U16> planes;
|
||||
buildPolyList_r(0, planes, list, sphere);
|
||||
AssertFatal(planes.size() == 0, "Error, unbalanced plane stack!");
|
||||
|
||||
return !list->isEmpty();
|
||||
}
|
180
engine/interior/forceField.h
Executable file
180
engine/interior/forceField.h
Executable file
@ -0,0 +1,180 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _FORCEFIELD_H_
|
||||
#define _FORCEFIELD_H_
|
||||
|
||||
#ifndef _PLATFORM_H_
|
||||
#include "platform/platform.h"
|
||||
#endif
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/tVector.h"
|
||||
#endif
|
||||
#ifndef _MBOX_H_
|
||||
#include "math/mBox.h"
|
||||
#endif
|
||||
#ifndef _MSPHERE_H_
|
||||
#include "math/mSphere.h"
|
||||
#endif
|
||||
#ifndef _MPLANE_H_
|
||||
#include "math/mPlane.h"
|
||||
#endif
|
||||
#ifndef _MPOINT_H_
|
||||
#include "math/mPoint.h"
|
||||
#endif
|
||||
#ifndef _COLOR_H_
|
||||
#include "core/color.h"
|
||||
#endif
|
||||
|
||||
//-------------------------------------- forward decls.
|
||||
class EditGeometry;
|
||||
class InteriorInstance;
|
||||
class Stream;
|
||||
class TextureHandle;
|
||||
class AbstractPolyList;
|
||||
struct RayInfo;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class ForceField
|
||||
{
|
||||
static const U32 smFileVersion;
|
||||
friend class EditGeometry;
|
||||
friend class InteriorInstance;
|
||||
|
||||
//-------------------------------------- Public interfaces
|
||||
public:
|
||||
ForceField();
|
||||
~ForceField();
|
||||
|
||||
bool prepForRendering();
|
||||
void render(const ColorF& color, const F32 fadeLevel);
|
||||
const Box3F& getBoundingBox() const;
|
||||
|
||||
bool castRay(const Point3F&, const Point3F&, RayInfo*);
|
||||
bool buildPolyList(AbstractPolyList*, SphereF&);
|
||||
//-------------------------------------- Persistence interface
|
||||
public:
|
||||
bool read(Stream& stream);
|
||||
bool write(Stream& stream) const;
|
||||
|
||||
public:
|
||||
static U16 getPlaneIndex(U16 index);
|
||||
static bool planeIsFlipped(U16 index);
|
||||
|
||||
//-------------------------------------- BSP Structures
|
||||
private:
|
||||
struct IBSPNode {
|
||||
U16 planeIndex;
|
||||
U16 frontIndex;
|
||||
U16 backIndex;
|
||||
U16 __padding__;
|
||||
};
|
||||
struct IBSPLeafSolid {
|
||||
U32 surfaceIndex;
|
||||
U16 surfaceCount;
|
||||
U16 __padding__;
|
||||
};
|
||||
|
||||
bool isBSPLeafIndex(U16 index) const;
|
||||
bool isBSPSolidLeaf(U16 index) const;
|
||||
bool isBSPEmptyLeaf(U16 index) const;
|
||||
U16 getBSPSolidLeafIndex(U16 index) const;
|
||||
|
||||
bool writePlaneVector(Stream&) const;
|
||||
bool readPlaneVector(Stream&);
|
||||
|
||||
private:
|
||||
const PlaneF& getPlane(U16 index) const;
|
||||
bool areEqualPlanes(U16, U16) const;
|
||||
|
||||
struct Surface {
|
||||
U32 windingStart;
|
||||
U32 fanMask;
|
||||
|
||||
U16 planeIndex;
|
||||
U8 windingCount;
|
||||
U8 surfaceFlags;
|
||||
};
|
||||
|
||||
protected:
|
||||
StringTableEntry mName;
|
||||
ColorF mColor;
|
||||
Vector<StringTableEntry> mTriggers;
|
||||
|
||||
Box3F mBoundingBox;
|
||||
SphereF mBoundingSphere;
|
||||
Vector<PlaneF> mPlanes;
|
||||
Vector<Point3F> mPoints;
|
||||
|
||||
Vector<IBSPNode> mBSPNodes;
|
||||
Vector<IBSPLeafSolid> mBSPSolidLeaves;
|
||||
Vector<U32> mSolidLeafSurfaces;
|
||||
|
||||
bool mPreppedForRender;
|
||||
TextureHandle* mWhite;
|
||||
|
||||
Vector<U32> mWindings;
|
||||
Vector<Surface> mSurfaces;
|
||||
|
||||
protected:
|
||||
bool castRay_r(const U16, const Point3F&, const Point3F&, RayInfo*);
|
||||
void buildPolyList_r(const U16, Vector<U16>&, AbstractPolyList*, SphereF&);
|
||||
void collisionFanFromSurface(const Surface&, U32* fan, U32* numIndices) const;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
inline bool ForceField::isBSPLeafIndex(U16 index) const
|
||||
{
|
||||
return (index & 0x8000) != 0;
|
||||
}
|
||||
|
||||
inline bool ForceField::isBSPSolidLeaf(U16 index) const
|
||||
{
|
||||
AssertFatal(isBSPLeafIndex(index) == true, "Error, only call for leaves!");
|
||||
return (index & 0x4000) != 0;
|
||||
}
|
||||
|
||||
inline bool ForceField::isBSPEmptyLeaf(U16 index) const
|
||||
{
|
||||
AssertFatal(isBSPLeafIndex(index) == true, "Error, only call for leaves!");
|
||||
return (index & 0x4000) == 0;
|
||||
}
|
||||
|
||||
inline U16 ForceField::getBSPSolidLeafIndex(U16 index) const
|
||||
{
|
||||
AssertFatal(isBSPSolidLeaf(index) == true, "Error, only call for leaves!");
|
||||
return (index & ~0xC000);
|
||||
}
|
||||
|
||||
inline const PlaneF& ForceField::getPlane(U16 index) const
|
||||
{
|
||||
AssertFatal(U32(index & ~0x8000) < mPlanes.size(),
|
||||
"ForceField::getPlane: planeIndex out of range");
|
||||
|
||||
return mPlanes[index & ~0x8000];
|
||||
}
|
||||
|
||||
inline U16 ForceField::getPlaneIndex(U16 index)
|
||||
{
|
||||
return index & ~0x8000;
|
||||
}
|
||||
|
||||
inline bool ForceField::planeIsFlipped(U16 index)
|
||||
{
|
||||
return (index & 0x8000) != 0;
|
||||
}
|
||||
|
||||
inline bool ForceField::areEqualPlanes(U16 o, U16 t) const
|
||||
{
|
||||
return (o & ~0x8000) == (t & ~0x8000);
|
||||
}
|
||||
|
||||
inline const Box3F& ForceField::getBoundingBox() const
|
||||
{
|
||||
return mBoundingBox;
|
||||
}
|
||||
|
||||
#endif // _H_FORCEFIELD_
|
||||
|
2221
engine/interior/interior.cc
Executable file
2221
engine/interior/interior.cc
Executable file
File diff suppressed because it is too large
Load Diff
994
engine/interior/interior.h
Executable file
994
engine/interior/interior.h
Executable file
@ -0,0 +1,994 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _INTERIOR_H_
|
||||
#define _INTERIOR_H_
|
||||
|
||||
//Includes
|
||||
#ifndef _PLATFORM_H_
|
||||
#include "platform/platform.h"
|
||||
#endif
|
||||
#ifndef _COLOR_H_
|
||||
#include "core/color.h"
|
||||
#endif
|
||||
#ifndef _COLLISION_H_
|
||||
#include "collision/collision.h"
|
||||
#endif
|
||||
#ifndef _RESMANAGER_H_
|
||||
#include "core/resManager.h"
|
||||
#endif
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/tVector.h"
|
||||
#endif
|
||||
#ifndef _MPOINT_H_
|
||||
#include "math/mPoint.h"
|
||||
#endif
|
||||
#ifndef _MPLANE_H_
|
||||
#include "math/mPlane.h"
|
||||
#endif
|
||||
#ifndef _MBOX_H_
|
||||
#include "math/mBox.h"
|
||||
#endif
|
||||
#ifndef _MSPHERE_H_
|
||||
#include "math/mSphere.h"
|
||||
#endif
|
||||
#ifndef _CONVEX_H_
|
||||
#include "collision/convex.h"
|
||||
#endif
|
||||
#ifndef _INTERIORLMMANAGER_H_
|
||||
#include "interior/interiorLMManager.h"
|
||||
#endif
|
||||
#ifndef _CONSTRUCTORSIMPLEMESH_H_
|
||||
#include "constructor/constructorSimpleMesh.h"
|
||||
#endif
|
||||
|
||||
#include "lightingSystem/sgDetailMapping.h"
|
||||
|
||||
|
||||
//-------------------------------------- Forward declarations
|
||||
class Stream;
|
||||
class EditGeometry;
|
||||
class InteriorInstance;
|
||||
class GBitmap;
|
||||
class TextureHandle;
|
||||
class RectD;
|
||||
class SphereF;
|
||||
class MatrixF;
|
||||
class SceneState;
|
||||
class MaterialList;
|
||||
class AbstractPolyList;
|
||||
class InteriorSubObject;
|
||||
class TranslucentSubObject;
|
||||
class BitVector;
|
||||
struct RayInfo;
|
||||
struct EdgeList;
|
||||
class SurfaceHash;
|
||||
class InteriorPolytope;
|
||||
class FloorPlan;
|
||||
class LightInfo;
|
||||
class PlaneRange;
|
||||
class EditInteriorResource;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class InteriorConvex : public Convex
|
||||
{
|
||||
typedef Convex Parent;
|
||||
friend class Interior;
|
||||
friend class InteriorInstance;
|
||||
|
||||
protected:
|
||||
Interior* pInterior;
|
||||
|
||||
public:
|
||||
S32 hullId;
|
||||
Box3F box;
|
||||
|
||||
InteriorConvex() { mType = InteriorConvexType; }
|
||||
InteriorConvex(const InteriorConvex& cv)
|
||||
{
|
||||
mObject = cv.mObject;
|
||||
pInterior = cv.pInterior;
|
||||
hullId = cv.hullId;
|
||||
box = box;
|
||||
}
|
||||
|
||||
Box3F getBoundingBox() const;
|
||||
Box3F getBoundingBox(const MatrixF& mat, const Point3F& scale) const;
|
||||
Point3F support(const VectorF& v) const;
|
||||
void getFeatures(const MatrixF& mat,const VectorF& n, ConvexFeature* cf);
|
||||
void getPolyList(AbstractPolyList* list);
|
||||
};
|
||||
|
||||
class ZoneVisDeterminer
|
||||
{
|
||||
enum Mode
|
||||
{
|
||||
FromState,
|
||||
FromRects
|
||||
};
|
||||
|
||||
Mode mMode;
|
||||
|
||||
SceneState* mState;
|
||||
U32 mZoneRangeOffset;
|
||||
U32 mParentZone;
|
||||
|
||||
public:
|
||||
ZoneVisDeterminer() : mMode(FromRects), mState(NULL) { }
|
||||
|
||||
void runFromState(SceneState*, U32, U32);
|
||||
void runFromRects(SceneState*, U32, U32);
|
||||
|
||||
bool isZoneVisible(const U32) const;
|
||||
};
|
||||
|
||||
|
||||
struct ItrPaddedPoint
|
||||
{
|
||||
Point3F point;
|
||||
union
|
||||
{
|
||||
F32 fogCoord;
|
||||
U8 fogColor[4];
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//-------------------------------------- CLASS NOTES
|
||||
// Interior: Base for all interior geometries. Contains all lighting, poly,
|
||||
// portal zone, bsp info, etc. to render an interior.
|
||||
//
|
||||
// Internal Structure Notes:
|
||||
// IBSPNode:
|
||||
// planeIndex: Obv.
|
||||
// frontIndex/backIndex: Top bit indicates if children are leaves.
|
||||
// Next bit indicates if leaf children are solid.
|
||||
//
|
||||
// IBSPLeafSolid:
|
||||
// planeIndex: obv.
|
||||
// surfaceIndex/surfaceCount: Polys that are on the faces of this leaf. Only
|
||||
// used for collision/surface info detection.
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
class Interior
|
||||
{
|
||||
friend class FloorPlan;
|
||||
friend class EditGeometry;
|
||||
friend class InteriorInstance;
|
||||
friend class SceneLighting;
|
||||
friend class InteriorProxy;
|
||||
friend class TranslucentSubObject;
|
||||
friend class MirrorSubObject;
|
||||
friend class InteriorConvex;
|
||||
friend class InteriorLMManager;
|
||||
friend class EditInteriorResource;
|
||||
|
||||
public:
|
||||
Interior();
|
||||
~Interior();
|
||||
|
||||
// Support for interior light map border sizes.
|
||||
private:
|
||||
U32 mLightMapBorderSize;
|
||||
|
||||
public:
|
||||
sgDetailMapping detailMapping;
|
||||
U32 getLightMapBorderSize() const {return mLightMapBorderSize;}
|
||||
void setLightMapBorderSize(U32 value) {mLightMapBorderSize = value;}
|
||||
void buildSurfaceZones();
|
||||
//void sgSetupLighting(InteriorInstance *intInst, SceneGraphData &sgData);
|
||||
//bool sgRenderLights(InteriorInstance *intInst, SceneGraphData &sgData);
|
||||
|
||||
|
||||
// Misc
|
||||
U32 getDetailLevel() const;
|
||||
U32 getMinPixels() const;
|
||||
const Box3F& getBoundingBox() const;
|
||||
S32 getNumZones() const;
|
||||
|
||||
// Rendering
|
||||
bool prepForRendering(const char* path);
|
||||
void rebuildVertexColors(LM_HANDLE instanceHandle,
|
||||
Vector<ColorI>* normal,
|
||||
Vector<ColorI>* alarm);
|
||||
|
||||
bool prepRender(SceneState* state,
|
||||
S32 containingZone,
|
||||
S32 baseZone,
|
||||
U32 zoneOffset,
|
||||
const MatrixF& OSToWS,
|
||||
const Point3F& objScale,
|
||||
const bool modifyBaseState,
|
||||
const bool dontRestrictOutside,
|
||||
const bool flipClipPlanes);
|
||||
void prepTempRender(SceneState* state,
|
||||
S32 containingZone,
|
||||
S32 baseZone,
|
||||
const MatrixF& OSToWS,
|
||||
const Point3F& objScale,
|
||||
const bool flipClipPlanes);
|
||||
|
||||
void render(const bool useAlarmLighting, MaterialList* pMaterials,
|
||||
const LM_HANDLE instanceHandle,
|
||||
const Vector<ColorI>* normalVLights,
|
||||
const Vector<ColorI>* alarmVLights);
|
||||
void render_vc_tf(const bool useAlarmLighting, MaterialList* pMaterials, const LM_HANDLE instanceHandle,
|
||||
const Vector<ColorI>* normalVLights,
|
||||
const Vector<ColorI>* alarmVLights);
|
||||
void render_vc_fc(const bool useAlarmLighting, MaterialList* pMaterials, const LM_HANDLE instanceHandle,
|
||||
const Vector<ColorI>* normalVLights,
|
||||
const Vector<ColorI>* alarmVLights);
|
||||
void renderARB_vc_tf(const bool useAlarmLighting, MaterialList* pMaterials, const LM_HANDLE instanceHandle,
|
||||
const Vector<ColorI>* normalVLights,
|
||||
const Vector<ColorI>* alarmVLights);
|
||||
void renderARB(const bool useAlarmLighting, MaterialList* pMaterials, const LM_HANDLE instanceHandle);
|
||||
void renderARB_FC(const bool useAlarmLighting, MaterialList* pMaterials, const LM_HANDLE instanceHandle);
|
||||
void renderLights(LightInfo* pInfo,
|
||||
const MatrixF& transform,
|
||||
const Point3F& scale,
|
||||
Vector<U32> surfaces);
|
||||
|
||||
void renderAsShape();
|
||||
void renderStaticMeshes(bool texture, bool lightmap, LM_HANDLE instancelmhandle);
|
||||
bool useFogCoord();
|
||||
|
||||
bool scopeZones(const S32 baseZone,
|
||||
const Point3F& interiorRoot,
|
||||
bool* interiorScopingState);
|
||||
|
||||
//-------------------------------------- Collision Interface and zone scans
|
||||
bool scanZones(const Box3F&, const MatrixF&, U16* zones, U32* numZones);
|
||||
bool castRay(const Point3F&, const Point3F&, RayInfo*);
|
||||
bool buildPolyList(AbstractPolyList*, const Box3F&, const MatrixF&, const Point3F&);
|
||||
bool buildLightPolyList(U32* lightSurfaces, U32* numLightSurfaces,
|
||||
const Box3F&, const MatrixF&, const Point3F&);
|
||||
|
||||
bool getIntersectingHulls(const Box3F&, U16* hulls, U32* numHulls);
|
||||
bool getIntersectingVehicleHulls(const Box3F&, U16* hulls, U32* numHulls);
|
||||
|
||||
protected:
|
||||
bool castRay_r(const U16, const U16, const Point3F&, const Point3F&, RayInfo*);
|
||||
void buildPolyList_r(InteriorPolytope& polytope,
|
||||
SurfaceHash& hash);
|
||||
void scanZone_r(const U16 node,
|
||||
const Point3F& center,
|
||||
const Point3F& axisx,
|
||||
const Point3F& axisy,
|
||||
const Point3F& axisz,
|
||||
U16* zones,
|
||||
U32* numZones);
|
||||
void scanZoneNew(InteriorPolytope& polytope,
|
||||
U16* zones,
|
||||
U32* numZones);
|
||||
|
||||
void scopeZone(const U32 currZone,
|
||||
bool* interiorScopingState,
|
||||
const Point3F& interiorRoot,
|
||||
Vector<U32>& zoneStack,
|
||||
Vector<PlaneF>& planeStack,
|
||||
Vector<PlaneRange>& planeRangeStack);
|
||||
|
||||
//-------------------------------------- Global rendering control
|
||||
public:
|
||||
enum RenderModes
|
||||
{
|
||||
NormalRender = 0,
|
||||
NormalRenderLines = 1,
|
||||
ShowDetail = 2,
|
||||
ShowAmbiguous = 3,
|
||||
ShowOrphan = 4,
|
||||
ShowLightmaps = 5,
|
||||
ShowTexturesOnly = 6,
|
||||
ShowPortalZones = 7,
|
||||
ShowOutsideVisible = 8,
|
||||
ShowCollisionFans = 9,
|
||||
ShowStrips = 10,
|
||||
ShowNullSurfaces = 11,
|
||||
ShowLargeTextures = 12,
|
||||
ShowHullSurfaces = 13,
|
||||
ShowVehicleHullSurfaces = 14,
|
||||
ShowVertexColors = 15,
|
||||
ShowDetailLevel = 16
|
||||
};
|
||||
|
||||
enum Constants
|
||||
{
|
||||
NumCoordBins = 16,
|
||||
|
||||
BinsXY = 0,
|
||||
BinsXZ = 1,
|
||||
BinsYZ = 2
|
||||
};
|
||||
|
||||
static U32 smRenderMode;
|
||||
static bool smFocusedDebug;
|
||||
static bool smRenderEnvironmentMaps;
|
||||
static bool smUseVertexLighting;
|
||||
static bool smUseTexturedFog;
|
||||
static bool smLockArrays;
|
||||
static U32 smFileVersion;
|
||||
static bool smLightingCastRays;
|
||||
|
||||
//-------------------------------------- Persistence interface
|
||||
bool read(Stream& stream);
|
||||
bool write(Stream& stream) const;
|
||||
|
||||
bool readVehicleCollision(Stream& stream);
|
||||
bool writeVehicleCollision(Stream& stream) const;
|
||||
|
||||
protected:
|
||||
bool writePlaneVector(Stream&) const;
|
||||
bool readPlaneVector(Stream&);
|
||||
bool readLMapTexGen(Stream&, PlaneF&, PlaneF&);
|
||||
bool writeLMapTexGen(Stream&, const PlaneF&, const PlaneF&) const;
|
||||
void setupTexCoords();
|
||||
void setupZonePlanes();
|
||||
|
||||
//-------------------------------------- For morian only...
|
||||
public:
|
||||
void processHullPolyLists();
|
||||
void processVehicleHullPolyLists();
|
||||
|
||||
//-------------------------------------- BSP Structures
|
||||
protected:
|
||||
struct IBSPNode
|
||||
{
|
||||
U16 planeIndex;
|
||||
U16 frontIndex;
|
||||
U16 backIndex;
|
||||
|
||||
U16 terminalZone; // if high bit set, then the lower 15 bits are the zone
|
||||
// of any of the subsidiary nodes. Note that this is
|
||||
// going to overestimate some, since an object could be
|
||||
// completely contained in solid, but it's probably
|
||||
// going to turn out alright.
|
||||
};
|
||||
struct IBSPLeafSolid
|
||||
{
|
||||
U32 surfaceIndex;
|
||||
U16 surfaceCount;
|
||||
};
|
||||
|
||||
bool isBSPLeafIndex(U16 index) const;
|
||||
bool isBSPSolidLeaf(U16 index) const;
|
||||
bool isBSPEmptyLeaf(U16 index) const;
|
||||
U16 getBSPSolidLeafIndex(U16 index) const;
|
||||
U16 getBSPEmptyLeafZone(U16 index) const;
|
||||
|
||||
void setupAveTexGenLength();
|
||||
|
||||
void truncateZoneTree();
|
||||
void truncateZoneNode(const U16);
|
||||
bool getUnifiedZone(const U16, S32*);
|
||||
|
||||
public:
|
||||
static U16 getPlaneIndex(const U16 index);
|
||||
static bool planeIsFlipped(const U16 index);
|
||||
const PlaneF& getPlane(const U16 index) const;
|
||||
PlaneF getFlippedPlane(const U16 index) const;
|
||||
|
||||
const Point3F getPointNormal(const U32 surfaceIndex, const U32 pointOffset) const;
|
||||
|
||||
protected:
|
||||
bool areEqualPlanes(U16, U16) const;
|
||||
bool isNullSurfaceIndex(const U32 index) const;
|
||||
bool isVehicleNullSurfaceIndex(const U32 index) const;
|
||||
U32 getNullSurfaceIndex(const U32 index) const;
|
||||
U32 getVehicleNullSurfaceIndex(const U32 index) const;
|
||||
|
||||
//-------------------------------------- Portals and Zone structures
|
||||
struct Zone
|
||||
{
|
||||
U16 portalStart;
|
||||
U16 portalCount;
|
||||
|
||||
U32 surfaceStart;
|
||||
U32 planeStart;
|
||||
|
||||
U16 surfaceCount;
|
||||
U16 planeCount;
|
||||
|
||||
U32 staticMeshStart;
|
||||
U32 staticMeshCount;
|
||||
|
||||
U16 flags;
|
||||
U16 zoneId; // This is ephemeral, not persisted out.
|
||||
};
|
||||
|
||||
struct Portal
|
||||
{
|
||||
U16 planeIndex;
|
||||
|
||||
U16 triFanCount;
|
||||
U32 triFanStart; // portals can have multiple windings
|
||||
|
||||
U16 zoneFront;
|
||||
U16 zoneBack;
|
||||
};
|
||||
|
||||
//-------------------------------------- Poly/Surface structures
|
||||
public:
|
||||
enum SurfaceFlags
|
||||
{
|
||||
SurfaceDetail = BIT(0),
|
||||
SurfaceAmbiguous = BIT(1),
|
||||
SurfaceOrphan = BIT(2),
|
||||
SurfaceSharedLMaps = BIT(3), // Indicates that the alarm and normal states share a lightmap (for mission lighter)
|
||||
SurfaceOutsideVisible = BIT(4),
|
||||
SurfaceStaticMesh = BIT(5), // This surface belongs to a static mesh collision hull
|
||||
SurfaceFlagMask = (SurfaceDetail |
|
||||
SurfaceAmbiguous |
|
||||
SurfaceOrphan |
|
||||
SurfaceSharedLMaps |
|
||||
SurfaceOutsideVisible |
|
||||
SurfaceStaticMesh)
|
||||
};
|
||||
enum ZoneFlags
|
||||
{
|
||||
ZoneInside = BIT(0)
|
||||
};
|
||||
|
||||
const bool isSurfaceOutsideVisible(U32 surface) const;
|
||||
|
||||
struct TexMatrix
|
||||
{
|
||||
S32 T;
|
||||
S32 N;
|
||||
S32 B;
|
||||
|
||||
TexMatrix::TexMatrix() { T = -1; N = -1; B = -1; };
|
||||
};
|
||||
|
||||
struct Edge
|
||||
{
|
||||
S32 vertexes[2];
|
||||
S32 faces[2];
|
||||
};
|
||||
|
||||
struct TexGenPlanes
|
||||
{
|
||||
PlaneF planeX;
|
||||
PlaneF planeY;
|
||||
};
|
||||
|
||||
struct TriFan
|
||||
{
|
||||
U32 windingStart;
|
||||
U32 windingCount;
|
||||
};
|
||||
|
||||
struct Surface
|
||||
{
|
||||
U32 windingStart; // 1
|
||||
|
||||
U16 planeIndex; // 2
|
||||
U16 textureIndex;
|
||||
|
||||
U32 texGenIndex; // 3
|
||||
|
||||
U16 lightCount; // 4
|
||||
U8 surfaceFlags;
|
||||
U32 windingCount;
|
||||
|
||||
U32 fanMask; // 5
|
||||
|
||||
U32 lightStateInfoStart; // 6
|
||||
|
||||
U32 mapOffsetX; // 7
|
||||
U32 mapOffsetY;
|
||||
U32 mapSizeX;
|
||||
U32 mapSizeY;
|
||||
bool unused;
|
||||
};
|
||||
|
||||
struct NullSurface
|
||||
{
|
||||
U32 windingStart;
|
||||
|
||||
U16 planeIndex;
|
||||
U8 surfaceFlags;
|
||||
U32 windingCount;
|
||||
};
|
||||
|
||||
//-------------------------------------- Animated lighting structures
|
||||
enum LightFlags
|
||||
{
|
||||
AnimationAmbient = BIT(0),
|
||||
AnimationLoop = BIT(1),
|
||||
AnimationFlicker = BIT(2),
|
||||
AnimationTypeMask = BIT(3) - 1,
|
||||
|
||||
AlarmLight = BIT(3)
|
||||
};
|
||||
|
||||
enum LightType
|
||||
{
|
||||
AmbientLooping = AnimationAmbient | AnimationLoop,
|
||||
AmbientFlicker = AnimationAmbient | AnimationFlicker,
|
||||
|
||||
TriggerableLoop = AnimationLoop,
|
||||
TriggerableFlicker = AnimationFlicker,
|
||||
TriggerableRamp = 0
|
||||
};
|
||||
|
||||
struct AnimatedLight
|
||||
{
|
||||
U32 nameIndex; ///< Light's name
|
||||
U32 stateIndex; ///< start point in the state list
|
||||
|
||||
U16 stateCount; ///< number of states in this light
|
||||
U16 flags; ///< flags (Apply AnimationTypeMask to get type)
|
||||
|
||||
U32 duration; ///< total duration of animation (ms)
|
||||
};
|
||||
|
||||
protected:
|
||||
struct LightState
|
||||
{
|
||||
U8 red; ///< state's color
|
||||
U8 green;
|
||||
U8 blue;
|
||||
U8 _color_padding_;
|
||||
|
||||
U32 activeTime; ///< Time (ms) at which this state becomes active
|
||||
|
||||
U32 dataIndex; ///< StateData count and index for this state
|
||||
U16 dataCount;
|
||||
|
||||
U16 __32bit_padding__;
|
||||
};
|
||||
|
||||
struct LightStateData
|
||||
{
|
||||
U32 surfaceIndex; ///< Surface affected by this data
|
||||
U32 mapIndex; ///< Index into StateDataBuffer (0xFFFFFFFF indicates none)
|
||||
U16 lightStateIndex; ///< Entry to modify in InteriorInstance
|
||||
U16 __32bit_padding__;
|
||||
};
|
||||
|
||||
// convex hull collision structures...
|
||||
protected:
|
||||
struct ConvexHull
|
||||
{
|
||||
F32 minX;
|
||||
F32 maxX;
|
||||
F32 minY;
|
||||
F32 maxY;
|
||||
|
||||
F32 minZ;
|
||||
F32 maxZ;
|
||||
U32 hullStart;
|
||||
U32 surfaceStart;
|
||||
|
||||
U32 planeStart;
|
||||
U16 hullCount;
|
||||
U16 surfaceCount;
|
||||
U32 polyListPlaneStart;
|
||||
|
||||
U32 polyListPointStart;
|
||||
U32 polyListStringStart;
|
||||
U16 searchTag;
|
||||
bool staticMesh;
|
||||
};
|
||||
|
||||
struct CoordBin
|
||||
{
|
||||
U32 binStart;
|
||||
U32 binCount;
|
||||
};
|
||||
|
||||
protected:
|
||||
LM_HANDLE mLMHandle;
|
||||
|
||||
public:
|
||||
LM_HANDLE getLMHandle() {return(mLMHandle);}
|
||||
|
||||
// SceneLighting::InteriorProxy interface
|
||||
const Surface & getSurface(const U32 surface) const;
|
||||
const U32 getSurfaceCount() const;
|
||||
const U32 getNormalLMapIndex(const U32 surface) const;
|
||||
const U32 getAlarmLMapIndex(const U32 surface) const;
|
||||
const U32 getStaticMeshCount() const;
|
||||
const ConstructorSimpleMesh *getStaticMesh(const U32 index) const;
|
||||
const U32 getWinding(const U32 index) const;
|
||||
const Point3F & getPoint(const U32 index) const;
|
||||
const TexGenPlanes & getLMTexGenEQ(const U32 index) const;
|
||||
bool hasAlarmState() const;
|
||||
const U32 getWindingCount() const;
|
||||
|
||||
//-------------------------------------- Instance Data Members
|
||||
protected:
|
||||
U32 mFileVersion;
|
||||
U32 mDetailLevel;
|
||||
U32 mMinPixels;
|
||||
F32 mAveTexGenLength; // Set in Interior::read after loading the texgen planes.
|
||||
Box3F mBoundingBox;
|
||||
SphereF mBoundingSphere;
|
||||
|
||||
Vector<PlaneF> mPlanes;
|
||||
Vector<ItrPaddedPoint> mPoints;
|
||||
Vector<U8> mPointVisibility;
|
||||
|
||||
Vector<Point3F> mNormals;
|
||||
Vector<TexMatrix> mTexMatrices;
|
||||
Vector<U32> mTexMatIndices;
|
||||
|
||||
ColorF mBaseAmbient;
|
||||
ColorF mAlarmAmbient;
|
||||
|
||||
Vector<IBSPNode> mBSPNodes;
|
||||
Vector<IBSPLeafSolid> mBSPSolidLeaves;
|
||||
|
||||
bool mPreppedForRender;
|
||||
MaterialList* mMaterialList;
|
||||
TextureHandle* mWhite;
|
||||
TextureHandle* mWhiteRGB;
|
||||
|
||||
TextureHandle* mLightFalloff;
|
||||
|
||||
Vector<TextureHandle*> mEnvironMaps;
|
||||
Vector<F32> mEnvironFactors;
|
||||
U32 mValidEnvironMaps;
|
||||
|
||||
Vector<U32> mWindings;
|
||||
|
||||
Vector<TexGenPlanes> mTexGenEQs;
|
||||
Vector<TexGenPlanes> mLMTexGenEQs;
|
||||
|
||||
Vector<TriFan> mWindingIndices;
|
||||
Vector<Surface> mSurfaces;
|
||||
Vector<NullSurface> mNullSurfaces;
|
||||
Vector<U32> mSolidLeafSurfaces;
|
||||
|
||||
Vector<Edge> mEdges;
|
||||
|
||||
// Portals and zones
|
||||
Vector<Zone> mZones;
|
||||
Vector<U16> mZonePlanes;
|
||||
Vector<U16> mZoneSurfaces;
|
||||
Vector<U16> mZonePortalList;
|
||||
Vector<Portal> mPortals;
|
||||
Vector<U32> mZoneStaticMeshes;
|
||||
|
||||
Vector<S32> mSurfaceZone;
|
||||
|
||||
// Subobjects: Doors, translucencies, mirrors, etc.
|
||||
Vector<InteriorSubObject*> mSubObjects;
|
||||
|
||||
// Lighting info
|
||||
bool mHasAlarmState;
|
||||
U32 mNumLightStateEntries;
|
||||
|
||||
//Vector<TextureHandle> mLightDirMapsTex;
|
||||
Vector<GBitmap*> mLightDirMaps;
|
||||
|
||||
Vector<GBitmap*> mLightmaps;
|
||||
Vector<bool> mLightmapKeep;
|
||||
Vector<U32> mNormalLMapIndices;
|
||||
Vector<U32> mAlarmLMapIndices;
|
||||
|
||||
U32 mNumTriggerableLights; // Note: not persisted
|
||||
|
||||
// Persistent animated light structures
|
||||
Vector<AnimatedLight> mAnimatedLights;
|
||||
Vector<LightState> mLightStates;
|
||||
Vector<LightStateData> mStateData;
|
||||
Vector<U8> mStateDataBuffer;
|
||||
|
||||
Vector<char> mNameBuffer;
|
||||
|
||||
Vector<ConvexHull> mConvexHulls;
|
||||
Vector<U8> mConvexHullEmitStrings;
|
||||
Vector<U32> mHullIndices;
|
||||
Vector<U32> mHullEmitStringIndices;
|
||||
Vector<U32> mHullSurfaceIndices;
|
||||
Vector<U16> mHullPlaneIndices;
|
||||
Vector<U16> mPolyListPlanes;
|
||||
Vector<U32> mPolyListPoints;
|
||||
Vector<U8> mPolyListStrings;
|
||||
CoordBin mCoordBins[NumCoordBins * NumCoordBins];
|
||||
Vector<U16> mCoordBinIndices;
|
||||
U32 mCoordBinMode;
|
||||
|
||||
Vector<ConvexHull> mVehicleConvexHulls;
|
||||
Vector<U8> mVehicleConvexHullEmitStrings;
|
||||
Vector<U32> mVehicleHullIndices;
|
||||
Vector<U32> mVehicleHullEmitStringIndices;
|
||||
Vector<U32> mVehicleHullSurfaceIndices;
|
||||
Vector<U16> mVehicleHullPlaneIndices;
|
||||
Vector<U16> mVehiclePolyListPlanes;
|
||||
Vector<U32> mVehiclePolyListPoints;
|
||||
Vector<U8> mVehiclePolyListStrings;
|
||||
Vector<ItrPaddedPoint> mVehiclePoints;
|
||||
Vector<NullSurface> mVehicleNullSurfaces;
|
||||
Vector<PlaneF> mVehiclePlanes;
|
||||
Vector<U32> mVehicleWindings;
|
||||
Vector<TriFan> mVehicleWindingIndices;
|
||||
|
||||
VectorPtr<ConstructorSimpleMesh*> mStaticMeshes;
|
||||
|
||||
// Some data used only by Constructor during export
|
||||
Vector<U32> mBspNodeList;
|
||||
|
||||
U16 mSearchTag;
|
||||
|
||||
//-------------------------------------- Private interface
|
||||
protected:
|
||||
const char* getName(const U32 nameIndex) const;
|
||||
static const char* getLightTypeString(const LightType);
|
||||
S32 getZoneForPoint(const Point3F&) const;
|
||||
|
||||
void debugRender(MaterialList* pMaterials, LM_HANDLE instanceHandle);
|
||||
void debugRenderPortals();
|
||||
void debugNormalRenderLines();
|
||||
void debugShowDetail();
|
||||
void debugShowAmbiguous();
|
||||
void debugShowLightmaps(LM_HANDLE instanceHandle);
|
||||
void debugShowPortalZones();
|
||||
void debugShowCollisionFans();
|
||||
void debugShowOrphan();
|
||||
void debugShowStrips();
|
||||
void debugShowTexturesOnly(MaterialList* pMaterials);
|
||||
void debugShowLargeTextures(MaterialList* pMaterials);
|
||||
void debugShowNullSurfaces(MaterialList* pMaterials);
|
||||
void debugShowOutsideVisible();
|
||||
void debugShowHullSurfaces();
|
||||
void debugShowVehicleHullSurfaces(MaterialList* pMaterials);
|
||||
// void debugShowVertexColors(MaterialList* pMaterials);
|
||||
void debugShowDetailLevel();
|
||||
|
||||
void debugShowOrphansFinish();
|
||||
|
||||
public:
|
||||
void collisionFanFromSurface(const Surface&, U32* fan, U32* numIndices) const;
|
||||
private:
|
||||
void fullWindingFromSurface(const Surface&, U32* fan, U32* numIndices) const;
|
||||
bool projectClipAndBoundFan(U32 fanIndex, F64* pResult);
|
||||
void zoneTraversal(S32 baseZone, const bool flipClipPlanes);
|
||||
void createZoneRectVectors();
|
||||
void destroyZoneRectVectors();
|
||||
void traverseZone(const RectD* inRects, const U32 numInputRects, U32 currZone, Vector<U32>& zoneStack);
|
||||
void doFogActive( const bool environmentActive,
|
||||
const SceneState* state,
|
||||
const U32 mergeArrayCount, const U16* mergeArray,
|
||||
const PlaneF &distPlane,
|
||||
const F32 distOffset,
|
||||
const Point3F &worldP,
|
||||
const Point3F &osZVec,
|
||||
const F32 worldZ );
|
||||
void setupActivePolyList(ZoneVisDeterminer&, SceneState*,
|
||||
const Point3F&, const Point3F& rViewVector,
|
||||
const Point3F&,
|
||||
const F32 worldz, const Point3F& scale);
|
||||
|
||||
void setupFog(SceneState* state);
|
||||
void clearFog();
|
||||
void setOSCamPosition(const Point3F&);
|
||||
|
||||
public:
|
||||
void purgeLODData();
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
inline bool Interior::isBSPLeafIndex(U16 index) const
|
||||
{
|
||||
return (index & 0x8000) != 0;
|
||||
}
|
||||
|
||||
inline bool Interior::isBSPSolidLeaf(U16 index) const
|
||||
{
|
||||
AssertFatal(isBSPLeafIndex(index) == true, "Error, only call for leaves!");
|
||||
return (index & 0x4000) != 0;
|
||||
}
|
||||
|
||||
inline bool Interior::isBSPEmptyLeaf(U16 index) const
|
||||
{
|
||||
AssertFatal(isBSPLeafIndex(index) == true, "Error, only call for leaves!");
|
||||
return (index & 0x4000) == 0;
|
||||
}
|
||||
|
||||
inline U16 Interior::getBSPSolidLeafIndex(U16 index) const
|
||||
{
|
||||
AssertFatal(isBSPSolidLeaf(index) == true, "Error, only call for leaves!");
|
||||
return U16(index & ~0xC000);
|
||||
}
|
||||
|
||||
inline U16 Interior::getBSPEmptyLeafZone(U16 index) const
|
||||
{
|
||||
AssertFatal(isBSPEmptyLeaf(index) == true, "Error, only call for leaves!");
|
||||
return U16(index & ~0xC000);
|
||||
}
|
||||
|
||||
inline const PlaneF& Interior::getPlane(const U16 index) const
|
||||
{
|
||||
AssertFatal(U32(index & ~0x8000) < mPlanes.size(),
|
||||
"Interior::getPlane: planeIndex out of range");
|
||||
|
||||
return mPlanes[index & ~0x8000];
|
||||
}
|
||||
|
||||
inline PlaneF Interior::getFlippedPlane(const U16 index) const
|
||||
{
|
||||
PlaneF plane = getPlane(index);
|
||||
if(Interior::planeIsFlipped(index))
|
||||
plane.neg();
|
||||
|
||||
return plane;
|
||||
}
|
||||
|
||||
inline U16 Interior::getPlaneIndex(const U16 index)
|
||||
{
|
||||
return U16(index & ~0x8000);
|
||||
}
|
||||
|
||||
inline bool Interior::planeIsFlipped(const U16 index)
|
||||
{
|
||||
return (index >> 15)!=0;
|
||||
}
|
||||
|
||||
inline bool Interior::areEqualPlanes(U16 o, U16 t) const
|
||||
{
|
||||
return (o & ~0x8000) == (t & ~0x8000);
|
||||
}
|
||||
|
||||
inline const Point3F Interior::getPointNormal(const U32 surfaceIndex, const U32 pointOffset) const
|
||||
{
|
||||
Surface rSurface = mSurfaces[surfaceIndex];
|
||||
|
||||
Point3F normal(0.0f, 0.0f, 0.0f);
|
||||
|
||||
if (mFileVersion >= 11)
|
||||
{
|
||||
U32 texMatIndex = mTexMatIndices[rSurface.windingStart + pointOffset];
|
||||
TexMatrix texMat = mTexMatrices[texMatIndex];
|
||||
|
||||
if (texMat.N > -1)
|
||||
normal = mNormals[texMat.N];
|
||||
}
|
||||
else
|
||||
normal = getPlane(rSurface.planeIndex);
|
||||
|
||||
return normal;
|
||||
}
|
||||
|
||||
inline U32 Interior::getDetailLevel() const
|
||||
{
|
||||
return mDetailLevel;
|
||||
}
|
||||
|
||||
inline U32 Interior::getMinPixels() const
|
||||
{
|
||||
return mMinPixels;
|
||||
}
|
||||
|
||||
inline const Box3F& Interior::getBoundingBox() const
|
||||
{
|
||||
return mBoundingBox;
|
||||
}
|
||||
|
||||
inline S32 Interior::getNumZones() const
|
||||
{
|
||||
return mZones.size();
|
||||
}
|
||||
|
||||
inline bool Interior::isNullSurfaceIndex(const U32 index) const
|
||||
{
|
||||
return (index & 0x80000000) != 0;
|
||||
}
|
||||
|
||||
inline bool Interior::isVehicleNullSurfaceIndex(const U32 index) const
|
||||
{
|
||||
return (index & 0x40000000) != 0;
|
||||
}
|
||||
|
||||
inline U32 Interior::getNullSurfaceIndex(const U32 index) const
|
||||
{
|
||||
AssertFatal(isNullSurfaceIndex(index), "Not a proper index!");
|
||||
AssertFatal(!isVehicleNullSurfaceIndex(index), "Not a proper index");
|
||||
return (index & ~0x80000000);
|
||||
}
|
||||
|
||||
inline U32 Interior::getVehicleNullSurfaceIndex(const U32 index) const
|
||||
{
|
||||
AssertFatal(isVehicleNullSurfaceIndex(index), "Not a proper index!");
|
||||
return (index & ~(0x80000000 | 0x40000000));
|
||||
}
|
||||
|
||||
inline const char* Interior::getLightTypeString(const LightType type)
|
||||
{
|
||||
switch (type) {
|
||||
case AmbientLooping:
|
||||
return "AmbientLooping";
|
||||
case AmbientFlicker:
|
||||
return "AmbientFlicker";
|
||||
case TriggerableLoop:
|
||||
return "TriggerableLoop";
|
||||
case TriggerableFlicker:
|
||||
return "TriggerableFlicker";
|
||||
case TriggerableRamp:
|
||||
return "TriggerableRamp";
|
||||
|
||||
default:
|
||||
return "<UNKNOWN>";
|
||||
}
|
||||
}
|
||||
|
||||
inline const char* Interior::getName(const U32 nameIndex) const
|
||||
{
|
||||
return &mNameBuffer[nameIndex];
|
||||
}
|
||||
|
||||
inline const U32 Interior::getSurfaceCount() const
|
||||
{
|
||||
return(mSurfaces.size());
|
||||
}
|
||||
|
||||
inline const Interior::Surface & Interior::getSurface(const U32 surface) const
|
||||
{
|
||||
AssertFatal(surface < mSurfaces.size(), "invalid index");
|
||||
return(mSurfaces[surface]);
|
||||
}
|
||||
|
||||
inline const U32 Interior::getStaticMeshCount() const
|
||||
{
|
||||
return mStaticMeshes.size();
|
||||
}
|
||||
|
||||
inline const ConstructorSimpleMesh *Interior::getStaticMesh(const U32 index) const
|
||||
{
|
||||
AssertFatal(index < mStaticMeshes.size(), "invalid index");
|
||||
return mStaticMeshes[index];
|
||||
}
|
||||
|
||||
inline const U32 Interior::getNormalLMapIndex(const U32 surface) const
|
||||
{
|
||||
AssertFatal(surface < mNormalLMapIndices.size(), "invalid index");
|
||||
return(mNormalLMapIndices[surface]);
|
||||
}
|
||||
|
||||
inline const U32 Interior::getAlarmLMapIndex(const U32 surface) const
|
||||
{
|
||||
AssertFatal(surface < mAlarmLMapIndices.size(), "invalid index");
|
||||
return(mAlarmLMapIndices[surface]);
|
||||
}
|
||||
|
||||
inline const U32 Interior::getWinding(const U32 index) const
|
||||
{
|
||||
AssertFatal(index < mWindings.size(), "invalid index");
|
||||
return(mWindings[index]);
|
||||
}
|
||||
|
||||
inline const Point3F & Interior::getPoint(const U32 index) const
|
||||
{
|
||||
AssertFatal(index < mPoints.size(), "invalid index");
|
||||
return(mPoints[index].point);
|
||||
}
|
||||
|
||||
inline const Interior::TexGenPlanes & Interior::getLMTexGenEQ(const U32 index) const
|
||||
{
|
||||
AssertFatal(index < mLMTexGenEQs.size(), "invalid index");
|
||||
return(mLMTexGenEQs[index]);
|
||||
}
|
||||
|
||||
inline bool Interior::hasAlarmState() const
|
||||
{
|
||||
return(mHasAlarmState);
|
||||
}
|
||||
|
||||
inline const bool Interior::isSurfaceOutsideVisible(U32 surface) const
|
||||
{
|
||||
AssertFatal(surface < mSurfaces.size(), "Interior::isSurfaceOutsideVisible: Invalid surface index");
|
||||
return ((mSurfaces[surface].surfaceFlags & SurfaceOutsideVisible)!=0);
|
||||
}
|
||||
|
||||
inline const U32 Interior::getWindingCount() const
|
||||
{
|
||||
return(mWindings.size());
|
||||
}
|
||||
|
||||
#endif //_INTERIOR_H_
|
1785
engine/interior/interiorCollision.cc
Executable file
1785
engine/interior/interiorCollision.cc
Executable file
File diff suppressed because it is too large
Load Diff
802
engine/interior/interiorDebug.cc
Executable file
802
engine/interior/interiorDebug.cc
Executable file
@ -0,0 +1,802 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "interior/interior.h"
|
||||
#include "console/console.h"
|
||||
#include "core/color.h"
|
||||
#include "dgl/gTexManager.h"
|
||||
#include "dgl/dgl.h"
|
||||
#include "math/mMatrix.h"
|
||||
#include "dgl/materialList.h"
|
||||
#include "dgl/gBitmap.h"
|
||||
|
||||
extern U16* sgActivePolyList;
|
||||
extern U32 sgActivePolyListSize;
|
||||
|
||||
namespace {
|
||||
|
||||
void lineLoopFromStrip(Vector<ItrPaddedPoint>& points,
|
||||
Vector<U32>& windings,
|
||||
U32 windingStart,
|
||||
U32 windingCount)
|
||||
{
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glVertex3fv(points[windings[windingStart]].point);
|
||||
|
||||
S32 skip = windingStart + 1;
|
||||
while (skip < (windingStart + windingCount)) {
|
||||
glVertex3fv(points[windings[skip]].point);
|
||||
skip += 2;
|
||||
}
|
||||
|
||||
skip -= 1;
|
||||
while (skip > windingStart) {
|
||||
if (skip < (windingStart + windingCount))
|
||||
glVertex3fv(points[windings[skip]].point);
|
||||
skip -= 2;
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void lineStrip(Vector<ItrPaddedPoint>& points,
|
||||
Vector<U32>& windings,
|
||||
U32 windingStart,
|
||||
U32 windingCount)
|
||||
{
|
||||
U32 end = 2;
|
||||
|
||||
while (end < windingCount) {
|
||||
// Even
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glVertex3fv(points[windings[windingStart + end - 2]].point);
|
||||
glVertex3fv(points[windings[windingStart + end - 1]].point);
|
||||
glVertex3fv(points[windings[windingStart + end - 0]].point);
|
||||
glEnd();
|
||||
|
||||
end++;
|
||||
if (end >= windingCount)
|
||||
break;
|
||||
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glVertex3fv(points[windings[windingStart + end - 1]].point);
|
||||
glVertex3fv(points[windings[windingStart + end - 2]].point);
|
||||
glVertex3fv(points[windings[windingStart + end - 0]].point);
|
||||
glEnd();
|
||||
end++;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace {}
|
||||
|
||||
|
||||
void Interior::debugRender(MaterialList* pMaterials, LM_HANDLE instanceHandle)
|
||||
{
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(ItrPaddedPoint), mPoints.address());
|
||||
|
||||
switch (smRenderMode) {
|
||||
case NormalRenderLines:
|
||||
debugNormalRenderLines();
|
||||
break;
|
||||
|
||||
case ShowDetail:
|
||||
debugShowDetail();
|
||||
break;
|
||||
|
||||
case ShowAmbiguous:
|
||||
debugShowAmbiguous();
|
||||
break;
|
||||
|
||||
case ShowLightmaps:
|
||||
debugShowLightmaps(instanceHandle);
|
||||
break;
|
||||
|
||||
case ShowPortalZones:
|
||||
debugShowPortalZones();
|
||||
break;
|
||||
|
||||
case ShowCollisionFans:
|
||||
debugShowCollisionFans();
|
||||
break;
|
||||
|
||||
case ShowOrphan:
|
||||
debugShowOrphan();
|
||||
break;
|
||||
|
||||
case ShowStrips:
|
||||
debugShowStrips();
|
||||
break;
|
||||
|
||||
case ShowTexturesOnly:
|
||||
debugShowTexturesOnly(pMaterials);
|
||||
break;
|
||||
|
||||
case ShowNullSurfaces:
|
||||
debugShowNullSurfaces(pMaterials);
|
||||
break;
|
||||
|
||||
case ShowLargeTextures:
|
||||
debugShowLargeTextures(pMaterials);
|
||||
break;
|
||||
|
||||
case ShowOutsideVisible:
|
||||
debugShowOutsideVisible();
|
||||
break;
|
||||
|
||||
case ShowHullSurfaces:
|
||||
debugShowHullSurfaces();
|
||||
break;
|
||||
|
||||
case ShowVehicleHullSurfaces:
|
||||
debugShowVehicleHullSurfaces(pMaterials);
|
||||
break;
|
||||
|
||||
case ShowVertexColors:
|
||||
// debugShowVertexColors(pMaterials);
|
||||
break;
|
||||
|
||||
case ShowDetailLevel:
|
||||
debugShowDetailLevel();
|
||||
break;
|
||||
|
||||
default:
|
||||
AssertWarn(false, "Warning! Misunderstood debug render mode. Defaulting to ShowDetail");
|
||||
debugShowDetail();
|
||||
break;
|
||||
}
|
||||
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
}
|
||||
|
||||
void Interior::debugNormalRenderLines()
|
||||
{
|
||||
// Ok, our verts are set up, draw our polys.
|
||||
U32 currentlyBound = U32(-1);
|
||||
U32 currentTexGen = U32(-1);
|
||||
|
||||
// Base textures
|
||||
glBlendFunc(GL_ONE, GL_ZERO);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glColor3f(1, 0, 1);
|
||||
for (U32 i = 0; i < sgActivePolyListSize; i++) {
|
||||
const Surface& rSurface = mSurfaces[sgActivePolyList[i]];
|
||||
lineLoopFromStrip(mPoints, mWindings, rSurface.windingStart, rSurface.windingCount);
|
||||
}
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
|
||||
void Interior::debugShowDetail()
|
||||
{
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
glBlendFunc(GL_ONE, GL_ZERO);
|
||||
for (U32 i = 0; i < sgActivePolyListSize; i++) {
|
||||
const Surface& rSurface = mSurfaces[sgActivePolyList[i]];
|
||||
|
||||
if (rSurface.surfaceFlags & SurfaceDetail)
|
||||
glColor3f(1.0f, 0, 0);
|
||||
else {
|
||||
if (smFocusedDebug == true)
|
||||
continue;
|
||||
else
|
||||
glColor3f(1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
glDrawElements(GL_TRIANGLE_STRIP, rSurface.windingCount, GL_UNSIGNED_INT, &mWindings[rSurface.windingStart]);
|
||||
}
|
||||
|
||||
if (smFocusedDebug == false) {
|
||||
glColor3f(0, 0, 0);
|
||||
for (U32 i = 0; i < sgActivePolyListSize; i++) {
|
||||
const Surface& rSurface = mSurfaces[sgActivePolyList[i]];
|
||||
lineLoopFromStrip(mPoints, mWindings, rSurface.windingStart, rSurface.windingCount);
|
||||
}
|
||||
}
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
|
||||
void Interior::debugShowAmbiguous()
|
||||
{
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glBlendFunc(GL_ONE, GL_ZERO);
|
||||
|
||||
for (U32 i = 0; i < sgActivePolyListSize; i++) {
|
||||
const Surface& rSurface = mSurfaces[sgActivePolyList[i]];
|
||||
|
||||
if (rSurface.surfaceFlags & SurfaceAmbiguous)
|
||||
glColor3f(0, 1.0f, 0);
|
||||
else {
|
||||
if (smFocusedDebug == true)
|
||||
continue;
|
||||
else
|
||||
glColor3f(1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
glDrawElements(GL_TRIANGLE_STRIP, rSurface.windingCount, GL_UNSIGNED_INT, &mWindings[rSurface.windingStart]);
|
||||
}
|
||||
|
||||
if (smFocusedDebug == false) {
|
||||
glColor3f(0, 0, 0);
|
||||
for (U32 i = 0; i < sgActivePolyListSize; i++) {
|
||||
const Surface& rSurface = mSurfaces[sgActivePolyList[i]];
|
||||
lineLoopFromStrip(mPoints, mWindings, rSurface.windingStart, rSurface.windingCount);
|
||||
}
|
||||
}
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
|
||||
void Interior::debugShowLightmaps(LM_HANDLE instanceHandle)
|
||||
{
|
||||
glBlendFunc(GL_ONE, GL_ZERO);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
|
||||
U32 currentlyBound = U32(-1);
|
||||
|
||||
U32 i;
|
||||
for (i = 0; i < sgActivePolyListSize; i++) {
|
||||
const Surface& rSurface = mSurfaces[sgActivePolyList[i]];
|
||||
|
||||
if (mNormalLMapIndices[sgActivePolyList[i]] != currentlyBound) {
|
||||
glBindTexture(GL_TEXTURE_2D, gInteriorLMManager.getHandle(mLMHandle, instanceHandle, mNormalLMapIndices[sgActivePolyList[i]])->getGLName());
|
||||
currentlyBound = mNormalLMapIndices[sgActivePolyList[i]];
|
||||
}
|
||||
|
||||
// Draw the poly
|
||||
glBegin(GL_TRIANGLE_STRIP);
|
||||
for (U32 j = rSurface.windingStart; j < rSurface.windingStart + rSurface.windingCount; j++) {
|
||||
glTexCoord2f(mLMTexGenEQs[sgActivePolyList[i]].planeX.distToPlane(mPoints[mWindings[j]].point),
|
||||
mLMTexGenEQs[sgActivePolyList[i]].planeY.distToPlane(mPoints[mWindings[j]].point));
|
||||
glVertex3fv(mPoints[mWindings[j]].point);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glColor3f(0, 0, 0);
|
||||
for (i = 0; i < sgActivePolyListSize; i++) {
|
||||
const Surface& rSurface = mSurfaces[sgActivePolyList[i]];
|
||||
|
||||
lineLoopFromStrip(mPoints, mWindings, rSurface.windingStart, rSurface.windingCount);
|
||||
}
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
renderStaticMeshes(false, true, instanceHandle);
|
||||
}
|
||||
|
||||
|
||||
void Interior::debugShowPortalZones()
|
||||
{
|
||||
static U8 colors[14][3] = {
|
||||
{ 0xFF, 0xFF, 0xFF },
|
||||
{ 0x00, 0x00, 0xFF },
|
||||
{ 0x00, 0xFF, 0x00 },
|
||||
{ 0xFF, 0x00, 0x00 },
|
||||
{ 0xFF, 0xFF, 0x00 },
|
||||
{ 0xFF, 0x00, 0xFF },
|
||||
{ 0x00, 0xFF, 0xFF },
|
||||
{ 0x80, 0x80, 0x80 },
|
||||
{ 0xFF, 0x80, 0x80 },
|
||||
{ 0x80, 0xFF, 0x80 },
|
||||
{ 0x80, 0x80, 0xFF },
|
||||
{ 0x80, 0xFF, 0xFF },
|
||||
{ 0xFF, 0x80, 0xFF },
|
||||
{ 0xFF, 0x80, 0x80 }
|
||||
};
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glBlendFunc(GL_ONE, GL_ZERO);
|
||||
|
||||
for (U32 i = 0; i < mZones.size(); i++) {
|
||||
U8* color;
|
||||
if (i == 0)
|
||||
color = colors[0];
|
||||
else
|
||||
color = colors[(i % 13) + 1];
|
||||
|
||||
for (U32 j = mZones[i].surfaceStart; j < mZones[i].surfaceStart + mZones[i].surfaceCount; j++) {
|
||||
const Surface& rSurface = mSurfaces[mZoneSurfaces[j]];
|
||||
|
||||
glColor3ub(color[0], color[1], color[2]);
|
||||
glDrawElements(GL_TRIANGLE_STRIP, rSurface.windingCount, GL_UNSIGNED_INT, &mWindings[rSurface.windingStart]);
|
||||
glColor3ub(0, 0, 0);
|
||||
lineLoopFromStrip(mPoints, mWindings, rSurface.windingStart, rSurface.windingCount);
|
||||
}
|
||||
}
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
debugRenderPortals();
|
||||
}
|
||||
|
||||
void Interior::debugRenderPortals()
|
||||
{
|
||||
//-------------------------------------- Render portals...
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
for (U32 i = 0; i < mPortals.size(); i++) {
|
||||
const Portal& rPortal = mPortals[i];
|
||||
|
||||
for (U16 j = 0; j < rPortal.triFanCount; j++) {
|
||||
const TriFan& rFan = mWindingIndices[rPortal.triFanStart + j];
|
||||
U32 k;
|
||||
|
||||
glColor4f(0.75, 0.5, 0.75, 0.45);
|
||||
glBegin(GL_TRIANGLE_FAN);
|
||||
for (k = 0; k < rFan.windingCount; k++)
|
||||
glVertex3fv(mPoints[mWindings[rFan.windingStart + k]].point);
|
||||
glEnd();
|
||||
glColor4f(0, 0, 1, 1);
|
||||
glBegin(GL_LINE_LOOP);
|
||||
for (k = 0; k < rFan.windingCount; k++)
|
||||
glVertex3fv(mPoints[mWindings[rFan.windingStart + k]].point);
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Interior::debugShowCollisionFans()
|
||||
{
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glBlendFunc(GL_ONE, GL_ZERO);
|
||||
|
||||
U32 i;
|
||||
for (i = 0; i < sgActivePolyListSize; i++) {
|
||||
const Surface& rSurface = mSurfaces[sgActivePolyList[i]];
|
||||
|
||||
U32 numIndices;
|
||||
U32 fanIndices[32];
|
||||
collisionFanFromSurface(rSurface, fanIndices, &numIndices);
|
||||
|
||||
glColor3f(1.0f, 1.0f, 1.0f);
|
||||
glDrawElements(GL_TRIANGLE_FAN, numIndices, GL_UNSIGNED_INT, fanIndices);
|
||||
}
|
||||
|
||||
glColor3f(0, 0, 0);
|
||||
for (i = 0; i < sgActivePolyListSize; i++) {
|
||||
const Surface& rSurface = mSurfaces[sgActivePolyList[i]];
|
||||
|
||||
U32 numIndices;
|
||||
U32 fanIndices[32];
|
||||
collisionFanFromSurface(rSurface, fanIndices, &numIndices);
|
||||
glBegin(GL_LINE_LOOP);
|
||||
for (U32 j = 0; j < numIndices; j++)
|
||||
glVertex3fv(mPoints[fanIndices[j]].point);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
for (i = 0; i < sgActivePolyListSize; i++) {
|
||||
const Surface& rSurface = mSurfaces[sgActivePolyList[i]];
|
||||
|
||||
U32 numIndices;
|
||||
U32 fanIndices[32];
|
||||
collisionFanFromSurface(rSurface, fanIndices, &numIndices);
|
||||
|
||||
glColor3f(1, 0, 0);
|
||||
glBegin(GL_LINES);
|
||||
for (U32 j = 0; j < numIndices; j++) {
|
||||
Point3F up = mPoints[fanIndices[j]].point;
|
||||
Point3F norm = getPlane(rSurface.planeIndex);
|
||||
if (planeIsFlipped(rSurface.planeIndex))
|
||||
up -= norm * 0.4;
|
||||
else
|
||||
up += norm * 0.4;
|
||||
|
||||
glVertex3fv(mPoints[fanIndices[j]].point);
|
||||
glVertex3fv(up);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
void Interior::debugShowOrphan()
|
||||
{
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glBlendFunc(GL_ONE, GL_ZERO);
|
||||
|
||||
U32 i;
|
||||
for (i = 0; i < sgActivePolyListSize; i++) {
|
||||
const Surface& rSurface = mSurfaces[sgActivePolyList[i]];
|
||||
|
||||
if (rSurface.surfaceFlags & SurfaceOrphan)
|
||||
glColor3f(0.0f, 0.0f, 1.0f);
|
||||
else {
|
||||
if (smFocusedDebug == true)
|
||||
continue;
|
||||
else
|
||||
glColor3f(1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
glDrawElements(GL_TRIANGLE_STRIP, rSurface.windingCount, GL_UNSIGNED_INT, &mWindings[rSurface.windingStart]);
|
||||
}
|
||||
|
||||
if (smFocusedDebug == false) {
|
||||
glColor3f(0, 0, 0);
|
||||
for (i = 0; i < sgActivePolyListSize; i++) {
|
||||
const Surface& rSurface = mSurfaces[sgActivePolyList[i]];
|
||||
lineLoopFromStrip(mPoints, mWindings, rSurface.windingStart, rSurface.windingCount);
|
||||
}
|
||||
}
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
void Interior::debugShowOrphansFinish()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Interior::debugShowStrips()
|
||||
{
|
||||
static U8 colors[14][3] = {
|
||||
{ 0xFF, 0xFF, 0xFF },
|
||||
{ 0x00, 0x00, 0xFF },
|
||||
{ 0x00, 0xFF, 0x00 },
|
||||
{ 0xFF, 0x00, 0x00 },
|
||||
{ 0xFF, 0xFF, 0x00 },
|
||||
{ 0xFF, 0x00, 0xFF },
|
||||
{ 0x00, 0xFF, 0xFF },
|
||||
{ 0x80, 0x80, 0x80 },
|
||||
{ 0xFF, 0x80, 0x80 },
|
||||
{ 0x80, 0xFF, 0x80 },
|
||||
{ 0x80, 0x80, 0xFF },
|
||||
{ 0x80, 0xFF, 0xFF },
|
||||
{ 0xFF, 0x80, 0xFF },
|
||||
{ 0xFF, 0x80, 0x80 }
|
||||
};
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glBlendFunc(GL_ONE, GL_ZERO);
|
||||
|
||||
U32 color = 0;
|
||||
U32 i;
|
||||
for (i = 0; i < sgActivePolyListSize; i++) {
|
||||
const Surface& rSurface = mSurfaces[sgActivePolyList[i]];
|
||||
|
||||
glColor3ub(colors[sgActivePolyList[i]%14][0],
|
||||
colors[sgActivePolyList[i]%14][1],
|
||||
colors[sgActivePolyList[i]%14][2]);
|
||||
color++;
|
||||
glDrawElements(GL_TRIANGLE_STRIP, rSurface.windingCount, GL_UNSIGNED_INT, &mWindings[rSurface.windingStart]);
|
||||
}
|
||||
|
||||
glColor3f(0, 0, 0);
|
||||
for (i = 0; i < sgActivePolyListSize; i++) {
|
||||
const Surface& rSurface = mSurfaces[sgActivePolyList[i]];
|
||||
lineStrip(mPoints, mWindings, rSurface.windingStart, rSurface.windingCount);
|
||||
}
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
|
||||
void Interior::debugShowNullSurfaces(MaterialList* pMaterials)
|
||||
{
|
||||
glBlendFunc(GL_ONE, GL_ZERO);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
|
||||
// Base textures
|
||||
U32 currentlyBound = U32(-1);
|
||||
U32 i;
|
||||
for (i = 0; i < sgActivePolyListSize; i++) {
|
||||
const Surface& rSurface = mSurfaces[sgActivePolyList[i]];
|
||||
|
||||
U32 baseName = pMaterials->getMaterial(rSurface.textureIndex).getGLName();
|
||||
if (baseName != currentlyBound) {
|
||||
glBindTexture(GL_TEXTURE_2D, baseName);
|
||||
currentlyBound = baseName;
|
||||
}
|
||||
|
||||
// Draw the poly
|
||||
glBegin(GL_TRIANGLE_STRIP);
|
||||
for (U32 j = rSurface.windingStart; j < rSurface.windingStart + rSurface.windingCount; j++) {
|
||||
glTexCoord2f(mTexGenEQs[rSurface.texGenIndex].planeX.distToPlane(mPoints[mWindings[j]].point),
|
||||
mTexGenEQs[rSurface.texGenIndex].planeY.distToPlane(mPoints[mWindings[j]].point));
|
||||
glVertex3fv(mPoints[mWindings[j]].point);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glBlendFunc(GL_ONE, GL_ZERO);
|
||||
|
||||
glColor3f(1, 0, 0);
|
||||
for (i = 0; i < mNullSurfaces.size(); i++) {
|
||||
const NullSurface& rSurface = mNullSurfaces[i];
|
||||
|
||||
glDrawElements(GL_TRIANGLE_FAN, rSurface.windingCount, GL_UNSIGNED_INT, &mWindings[rSurface.windingStart]);
|
||||
}
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
void Interior::debugShowTexturesOnly(MaterialList* pMaterials)
|
||||
{
|
||||
glBlendFunc(GL_ONE, GL_ZERO);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
|
||||
// Base textures
|
||||
U32 currentlyBound = U32(-1);
|
||||
U32 i;
|
||||
|
||||
for (i = 0; i < sgActivePolyListSize; i++) {
|
||||
const Surface& rSurface = mSurfaces[sgActivePolyList[i]];
|
||||
|
||||
if (pMaterials->getMaterial(rSurface.textureIndex).getGLName() != currentlyBound) {
|
||||
glBindTexture(GL_TEXTURE_2D, pMaterials->getMaterial(rSurface.textureIndex).getGLName());
|
||||
currentlyBound = mMaterialList->getMaterial(rSurface.textureIndex).getGLName();
|
||||
}
|
||||
|
||||
// Draw the poly
|
||||
glBegin(GL_TRIANGLE_STRIP);
|
||||
for (U32 j = rSurface.windingStart; j < rSurface.windingStart + rSurface.windingCount; j++) {
|
||||
glTexCoord2f(mTexGenEQs[rSurface.texGenIndex].planeX.distToPlane(mPoints[mWindings[j]].point),
|
||||
mTexGenEQs[rSurface.texGenIndex].planeY.distToPlane(mPoints[mWindings[j]].point));
|
||||
glVertex3fv(mPoints[mWindings[j]].point);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
|
||||
void Interior::debugShowLargeTextures(MaterialList* pMaterials)
|
||||
{
|
||||
glBlendFunc(GL_ONE, GL_ZERO);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
|
||||
// Base textures
|
||||
U32 currentlyBound = U32(-1);
|
||||
U32 currentTexGen = U32(-1);
|
||||
U32 i;
|
||||
|
||||
for (i = 0; i < sgActivePolyListSize; i++) {
|
||||
const Surface& rSurface = mSurfaces[sgActivePolyList[i]];
|
||||
|
||||
U32 baseName = pMaterials->getMaterial(rSurface.textureIndex).getGLName();
|
||||
if (baseName != currentlyBound) {
|
||||
glBindTexture(GL_TEXTURE_2D, baseName);
|
||||
currentlyBound = baseName;
|
||||
|
||||
U32 width = pMaterials->getMaterial(rSurface.textureIndex).getWidth();
|
||||
U32 height = pMaterials->getMaterial(rSurface.textureIndex).getHeight();
|
||||
if (width >= 256 || height >= 256) {
|
||||
if (width == 256 && height == 256) {
|
||||
// small large
|
||||
glColor3f(0.25, 0.25, 1);
|
||||
} else if (width != 512 || height != 512) {
|
||||
// thin large
|
||||
glColor3f(0.25, 1, 0.25);
|
||||
} else {
|
||||
// oh god.
|
||||
glColor3f(1, 0.25, 0.25);
|
||||
}
|
||||
} else {
|
||||
glColor3f(0.35, 0.35, 0.35);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the poly
|
||||
glBegin(GL_TRIANGLE_STRIP);
|
||||
for (U32 j = rSurface.windingStart; j < rSurface.windingStart + rSurface.windingCount; j++) {
|
||||
glTexCoord2f(mTexGenEQs[rSurface.texGenIndex].planeX.distToPlane(mPoints[mWindings[j]].point),
|
||||
mTexGenEQs[rSurface.texGenIndex].planeY.distToPlane(mPoints[mWindings[j]].point));
|
||||
glVertex3fv(mPoints[mWindings[j]].point);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Interior::debugShowOutsideVisible()
|
||||
{
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
glBlendFunc(GL_ONE, GL_ZERO);
|
||||
for (U32 i = 0; i < sgActivePolyListSize; i++) {
|
||||
const Surface& rSurface = mSurfaces[sgActivePolyList[i]];
|
||||
|
||||
if (rSurface.surfaceFlags & SurfaceOutsideVisible)
|
||||
glColor3f(1.0f, 0, 0);
|
||||
else {
|
||||
if (smFocusedDebug == true)
|
||||
continue;
|
||||
else
|
||||
glColor3f(1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
glDrawElements(GL_TRIANGLE_STRIP, rSurface.windingCount, GL_UNSIGNED_INT, &mWindings[rSurface.windingStart]);
|
||||
}
|
||||
|
||||
if (smFocusedDebug == false) {
|
||||
glColor3f(0, 0, 0);
|
||||
for (U32 i = 0; i < sgActivePolyListSize; i++) {
|
||||
const Surface& rSurface = mSurfaces[sgActivePolyList[i]];
|
||||
lineLoopFromStrip(mPoints, mWindings, rSurface.windingStart, rSurface.windingCount);
|
||||
}
|
||||
}
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
void Interior::debugShowHullSurfaces()
|
||||
{
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
static U8 colors[14][3] = {
|
||||
{ 0xFF, 0xFF, 0xFF },
|
||||
{ 0x00, 0x00, 0xFF },
|
||||
{ 0x00, 0xFF, 0x00 },
|
||||
{ 0xFF, 0x00, 0x00 },
|
||||
{ 0xFF, 0xFF, 0x00 },
|
||||
{ 0xFF, 0x00, 0xFF },
|
||||
{ 0x00, 0xFF, 0xFF },
|
||||
{ 0x80, 0x80, 0x80 },
|
||||
{ 0xFF, 0x80, 0x80 },
|
||||
{ 0x80, 0xFF, 0x80 },
|
||||
{ 0x80, 0x80, 0xFF },
|
||||
{ 0x80, 0xFF, 0xFF },
|
||||
{ 0xFF, 0x80, 0xFF },
|
||||
{ 0xFF, 0x80, 0x80 }
|
||||
};
|
||||
U32 color = 0;
|
||||
|
||||
glBlendFunc(GL_ONE, GL_ZERO);
|
||||
for (U32 i = 0; i < mConvexHulls.size(); i++) {
|
||||
const ConvexHull& rHull = mConvexHulls[i];
|
||||
for (U32 j = rHull.surfaceStart; j < rHull.surfaceCount + rHull.surfaceStart; j++) {
|
||||
U32 index = mHullSurfaceIndices[j];
|
||||
if (isNullSurfaceIndex(index)) {
|
||||
} else {
|
||||
const Interior::Surface& rSurface = mSurfaces[index];
|
||||
U32 fanVerts[32];
|
||||
U32 numVerts;
|
||||
collisionFanFromSurface(rSurface, fanVerts, &numVerts);
|
||||
|
||||
glColor3ub(colors[(i%13)+1][0], colors[(i%13)+1][1], colors[(i%13)+1][2]);
|
||||
color++;
|
||||
Point3F center(0, 0, 0);
|
||||
glBegin(GL_TRIANGLE_FAN);
|
||||
for (U32 k = 0; k < numVerts; k++) {
|
||||
glVertex3fv(mPoints[fanVerts[k]].point);
|
||||
center += mPoints[fanVerts[k]].point;
|
||||
}
|
||||
glEnd();
|
||||
center /= F32(numVerts);
|
||||
glColor3f(0, 0, 0);
|
||||
lineLoopFromStrip(mPoints, mWindings, rSurface.windingStart, rSurface.windingCount);
|
||||
|
||||
PlaneF plane;
|
||||
plane.set(mPoints[fanVerts[0]].point, mPoints[fanVerts[1]].point, mPoints[fanVerts[2]].point);
|
||||
glBegin(GL_LINES);
|
||||
glVertex3fv(center);
|
||||
glVertex3fv(center + (plane * 0.25));
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
void Interior::debugShowVehicleHullSurfaces(MaterialList* pMaterials)
|
||||
{
|
||||
glBlendFunc(GL_ONE, GL_ZERO);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
|
||||
// Base textures
|
||||
U32 currentlyBound = U32(-1);
|
||||
U32 i;
|
||||
for (i = 0; i < sgActivePolyListSize; i++) {
|
||||
const Surface& rSurface = mSurfaces[sgActivePolyList[i]];
|
||||
|
||||
U32 baseName = pMaterials->getMaterial(rSurface.textureIndex).getGLName();
|
||||
if (baseName != currentlyBound) {
|
||||
glBindTexture(GL_TEXTURE_2D, baseName);
|
||||
currentlyBound = baseName;
|
||||
}
|
||||
|
||||
// Draw the poly
|
||||
glBegin(GL_TRIANGLE_STRIP);
|
||||
for (U32 j = rSurface.windingStart; j < rSurface.windingStart + rSurface.windingCount; j++) {
|
||||
glTexCoord2f(mTexGenEQs[rSurface.texGenIndex].planeX.distToPlane(mPoints[mWindings[j]].point),
|
||||
mTexGenEQs[rSurface.texGenIndex].planeY.distToPlane(mPoints[mWindings[j]].point));
|
||||
glVertex3fv(mPoints[mWindings[j]].point);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glBlendFunc(GL_ONE, GL_ZERO);
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(ItrPaddedPoint), mVehiclePoints.address());
|
||||
|
||||
glColor3f(1, 0, 0);
|
||||
for (i = 0; i < mVehicleNullSurfaces.size(); i++) {
|
||||
const NullSurface& rSurface = mNullSurfaces[i];
|
||||
|
||||
glDrawElements(GL_TRIANGLE_FAN, rSurface.windingCount, GL_UNSIGNED_INT, &mVehicleWindings[rSurface.windingStart]);
|
||||
}
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
|
||||
// void Interior::debugShowVertexColors(MaterialList* /*pMaterials*/)
|
||||
// {
|
||||
// glDisable(GL_TEXTURE_2D);
|
||||
// glBlendFunc(GL_ONE, GL_ZERO);
|
||||
|
||||
// for (U32 i = 0; i < sgActivePolyListSize; i++) {
|
||||
// const Surface& rSurface = mSurfaces[sgActivePolyList[i]];
|
||||
|
||||
// glBegin(GL_TRIANGLE_STRIP);
|
||||
// for (U32 j = rSurface.windingStart; j < rSurface.windingStart + rSurface.windingCount; j++)
|
||||
// {
|
||||
// const ItrPaddedPoint& rPoint = mPoints[mWindings[j]];
|
||||
// glColor3ub(mVertexColorsNormal[j].red,
|
||||
// mVertexColorsNormal[j].green,
|
||||
// mVertexColorsNormal[j].blue);
|
||||
// glVertex3fv(rPoint.point);
|
||||
// }
|
||||
// glEnd();
|
||||
// }
|
||||
|
||||
// if (smFocusedDebug == false) {
|
||||
// glColor3f(0, 0, 0);
|
||||
// for (U32 i = 0; i < sgActivePolyListSize; i++) {
|
||||
// const Surface& rSurface = mSurfaces[sgActivePolyList[i]];
|
||||
// lineLoopFromStrip(mPoints, mWindings, rSurface.windingStart, rSurface.windingCount);
|
||||
// }
|
||||
// }
|
||||
|
||||
// glEnable(GL_TEXTURE_2D);
|
||||
// }
|
||||
|
||||
|
||||
void Interior::debugShowDetailLevel()
|
||||
{
|
||||
static U8 colors[14][3] = {
|
||||
{ 0xFF, 0xFF, 0xFF },
|
||||
{ 0x00, 0x00, 0xFF },
|
||||
{ 0x00, 0xFF, 0x00 },
|
||||
{ 0xFF, 0x00, 0x00 },
|
||||
{ 0xFF, 0xFF, 0x00 },
|
||||
{ 0xFF, 0x00, 0xFF },
|
||||
{ 0x00, 0xFF, 0xFF },
|
||||
{ 0x80, 0x80, 0x80 },
|
||||
{ 0xFF, 0x80, 0x80 },
|
||||
{ 0x80, 0xFF, 0x80 },
|
||||
{ 0x80, 0x80, 0xFF },
|
||||
{ 0x80, 0xFF, 0xFF },
|
||||
{ 0xFF, 0x80, 0xFF },
|
||||
{ 0xFF, 0x80, 0x80 }
|
||||
};
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
glBlendFunc(GL_ONE, GL_ZERO);
|
||||
for (U32 i = 0; i < sgActivePolyListSize; i++) {
|
||||
const Surface& rSurface = mSurfaces[sgActivePolyList[i]];
|
||||
|
||||
glColor3ubv(colors[getDetailLevel()]);
|
||||
glDrawElements(GL_TRIANGLE_STRIP, rSurface.windingCount, GL_UNSIGNED_INT, &mWindings[rSurface.windingStart]);
|
||||
}
|
||||
|
||||
if (smFocusedDebug == false) {
|
||||
glColor3f(0, 0, 0);
|
||||
for (U32 i = 0; i < sgActivePolyListSize; i++) {
|
||||
const Surface& rSurface = mSurfaces[sgActivePolyList[i]];
|
||||
lineLoopFromStrip(mPoints, mWindings, rSurface.windingStart, rSurface.windingCount);
|
||||
}
|
||||
}
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
|
1501
engine/interior/interiorIO.cc
Executable file
1501
engine/interior/interiorIO.cc
Executable file
File diff suppressed because it is too large
Load Diff
2215
engine/interior/interiorInstance.cc
Executable file
2215
engine/interior/interiorInstance.cc
Executable file
File diff suppressed because it is too large
Load Diff
465
engine/interior/interiorInstance.h
Executable file
465
engine/interior/interiorInstance.h
Executable file
@ -0,0 +1,465 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _INTERIORINSTANCE_H_
|
||||
#define _INTERIORINSTANCE_H_
|
||||
|
||||
//Includes
|
||||
#ifndef _PLATFORM_H_
|
||||
#include "platform/platform.h"
|
||||
#endif
|
||||
#ifndef _SCENEOBJECT_H_
|
||||
#include "sim/sceneObject.h"
|
||||
#endif
|
||||
#ifndef _RESMANAGER_H_
|
||||
#include "core/resManager.h"
|
||||
#endif
|
||||
#ifndef _INTERIORRES_H_
|
||||
#include "interior/interiorRes.h"
|
||||
#endif
|
||||
#ifndef _INTERIORLMMANAGER_H_
|
||||
#include "interior/interiorLMManager.h"
|
||||
#endif
|
||||
|
||||
#ifndef _BITVECTOR_H_
|
||||
#include "core/bitVector.h"
|
||||
#endif
|
||||
#ifndef _COLOR_H_
|
||||
#include "core/color.h"
|
||||
#endif
|
||||
|
||||
class AbstractPolyList;
|
||||
class LightUpdateGrouper;
|
||||
class InteriorSubObject;
|
||||
class InteriorResTrigger;
|
||||
class MaterialList;
|
||||
class TextureObject;
|
||||
class FloorPlan;
|
||||
class Convex;
|
||||
class AudioProfile;
|
||||
class AudioEnvironment;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class InteriorInstance : public SceneObject
|
||||
{
|
||||
typedef SceneObject Parent;
|
||||
friend class SceneLighting;
|
||||
friend class FloorPlan;
|
||||
|
||||
public:
|
||||
InteriorInstance();
|
||||
~InteriorInstance();
|
||||
|
||||
|
||||
S32 getSurfaceZone(U32 surfaceindex, Interior *detail);
|
||||
void processLightSurfaceList(U32 *lightSurfaces, U32 *numLightSurfaces,
|
||||
InteriorInstance *interiorinstance, Interior *detail, ::LightInfo *light);
|
||||
|
||||
|
||||
static void init();
|
||||
static void destroy();
|
||||
|
||||
// Collision
|
||||
public:
|
||||
bool buildPolyList(AbstractPolyList *polyList, const Box3F &box, const SphereF &sphere);
|
||||
bool castRay(const Point3F &start, const Point3F &end, RayInfo *info);
|
||||
virtual void setTransform(const MatrixF &mat);
|
||||
|
||||
void buildConvex(const Box3F& box,Convex* convex);
|
||||
private:
|
||||
Convex* mConvexList;
|
||||
|
||||
public:
|
||||
|
||||
/// @name Lighting control
|
||||
/// @{
|
||||
|
||||
/// This returns true if the interior is in an alarm state. Alarm state
|
||||
/// will put different lighting into the interior and also possibly
|
||||
/// have an audio element also.
|
||||
bool inAlarmState() {return(mAlarmState);}
|
||||
|
||||
/// This sets the alarm mode of the interior.
|
||||
/// @param alarm If true the interior will be in an alarm state next frame
|
||||
void setAlarmMode(const bool alarm);
|
||||
|
||||
/// Activates a light with the given name on all detail levels of the interior
|
||||
/// @param pLightName Name of the light
|
||||
void activateLight(const char* pLightName);
|
||||
|
||||
/// Deactivates a light with the given name on all detail levels of the interior
|
||||
/// @param pLightName Name of the light
|
||||
void deactivateLight(const char* pLightName);
|
||||
|
||||
/// Echos out all the lights in the interior, starting with triggerable then
|
||||
/// animated lights
|
||||
void echoTriggerableLights();
|
||||
|
||||
/// @}
|
||||
|
||||
public:
|
||||
/// @name Subobject access interface
|
||||
/// @{
|
||||
|
||||
/// Returns the number of detail levels for an object
|
||||
U32 getNumDetailLevels();
|
||||
|
||||
/// Gets the interior associated with a particular detail level
|
||||
/// @param level Detail level
|
||||
Interior* getDetailLevel(const U32 level);
|
||||
|
||||
/// Sets the detail level to render manually
|
||||
/// @param level Detail level to force
|
||||
void setDetailLevel(S32 level = -1) { mForcedDetailLevel = level; }
|
||||
/// @}
|
||||
|
||||
// Material management for overlays
|
||||
public:
|
||||
|
||||
/// Reloads material information if the interior skin changes
|
||||
void renewOverlays();
|
||||
|
||||
/// Sets the interior skin to something different
|
||||
/// @param newBase New base skin
|
||||
void setSkinBase(const char *newBase);
|
||||
|
||||
public:
|
||||
static bool smDontRestrictOutside;
|
||||
static F32 smDetailModification;
|
||||
|
||||
|
||||
DECLARE_CONOBJECT(InteriorInstance);
|
||||
static void initPersistFields();
|
||||
static void consoleInit();
|
||||
|
||||
void onStaticModified( const char* slotName );
|
||||
|
||||
/// Reads the lightmaps of the interior into the provided pointer
|
||||
/// @param lightmaps Lightmaps in the interior (out)
|
||||
bool readLightmaps(GBitmap ****lightmaps);
|
||||
|
||||
protected:
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
|
||||
void inspectPreApply();
|
||||
void inspectPostApply();
|
||||
|
||||
static U32 smLightUpdatePeriod;
|
||||
static bool smRenderDynamicLights;
|
||||
|
||||
U32 mLightUpdatedTime;
|
||||
void setLightUpdatedTime(const U32);
|
||||
U32 getLightUpdatedTime() const;
|
||||
|
||||
bool onSceneAdd(SceneGraph *graph);
|
||||
void onSceneRemove();
|
||||
U32 getPointZone(const Point3F& p);
|
||||
bool getOverlappingZones(SceneObject* obj, U32* zones, U32* numZones);
|
||||
|
||||
bool getLightingAmbientColor(ColorF * col)
|
||||
{
|
||||
*col = ColorF(1.0, 1.0, 1.0);
|
||||
return true;
|
||||
}
|
||||
|
||||
U32 calcDetailLevel(SceneState*, const Point3F&);
|
||||
bool prepRenderImage(SceneState *state, const U32 stateKey, const U32 startZone, const bool modifyBaseZoneState);
|
||||
void renderObject(SceneState *state, SceneRenderImage *image);
|
||||
bool scopeObject(const Point3F& rootPosition,
|
||||
const F32 rootDistance,
|
||||
bool* zoneScopeState);
|
||||
|
||||
public:
|
||||
/// This is used to store the preferred lighting method for this interior. It is networked.
|
||||
bool mUseGLLighting;
|
||||
|
||||
/// This indicates what we're actually doing; that way we can bump things to use GL lighting when they are moved.
|
||||
bool mDoSimpleDynamicRender;
|
||||
|
||||
/// Not yet implemented
|
||||
void addChildren();
|
||||
|
||||
/// Returns true if the interiors are rendering dynamic lighting
|
||||
static bool getRenderDynamicLights() { return(smRenderDynamicLights); }
|
||||
|
||||
/// Turns on or off dynamic lighting of interiors
|
||||
/// @param val If true dynamic lighting is enabled
|
||||
static void setRenderDynamicLights(bool val) { smRenderDynamicLights = val; }
|
||||
|
||||
private:
|
||||
/// @name Light utility methods
|
||||
/// These should not be called directly. Use the public activateLight(const char *)
|
||||
/// method instead because unless the detail level is rendering and it's much
|
||||
/// easier to not manage the lights on a per-detail level basis.
|
||||
/// @{
|
||||
|
||||
/// Activates a specific light for a detail level
|
||||
/// @param detail Detail level
|
||||
/// @param lightIndex Index of light in light list
|
||||
void activateLight(const U32 detail, const U32 lightIndex);
|
||||
|
||||
/// Deactivates a specific light for a detail level
|
||||
/// @param detail Detail level
|
||||
/// @param lightIndex Index of light in the light list
|
||||
void deactivateLight(const U32 detail, const U32 lightIndex);
|
||||
|
||||
/// @}
|
||||
|
||||
U32 packUpdate (NetConnection *conn, U32 mask, BitStream *stream);
|
||||
void unpackUpdate(NetConnection *conn, BitStream *stream);
|
||||
|
||||
|
||||
enum UpdateMaskBits {
|
||||
InitMask = BIT(0),
|
||||
TransformMask = BIT(1),
|
||||
AlarmMask = BIT(2),
|
||||
|
||||
// Reserved for light updates (8 bits for now)
|
||||
_lightupdate0 = BIT(3),
|
||||
_lightupdate1 = BIT(4),
|
||||
_lightupdate2 = BIT(5),
|
||||
_lightupdate3 = BIT(6),
|
||||
_lightupdate4 = BIT(7),
|
||||
_lightupdate5 = BIT(8),
|
||||
_lightupdate6 = BIT(9),
|
||||
_lightupdate7 = BIT(10),
|
||||
|
||||
SkinBaseMask = BIT(11),
|
||||
AudioMask = BIT(12),
|
||||
NextFreeMask = BIT(13)
|
||||
};
|
||||
enum Constants {
|
||||
LightUpdateBitStart = 3,
|
||||
LightUpdateBitEnd = 10
|
||||
};
|
||||
|
||||
private:
|
||||
StringTableEntry mInteriorFileName; ///< File name of the interior this instance encapuslates
|
||||
U32 mInteriorFileHash; ///< Hash for interior file name, used for sorting
|
||||
Resource<InteriorResource> mInteriorRes; ///< Interior managed by resource manager
|
||||
Vector<MaterialList*> mMaterialMaps; ///< Materials for this interior
|
||||
StringTableEntry mSkinBase; ///< Skin for this interior
|
||||
|
||||
Vector< Vector<InteriorSubObject*> > mInteriorSubObjects; ///< Sub objects of this interior
|
||||
bool mShowTerrainInside; ///< Enables or disables terrain showing through the interior
|
||||
LM_HANDLE mLMHandle; ///< Handle to the light manager
|
||||
AudioProfile * mAudioProfile; ///< Audio profile
|
||||
AudioEnvironment * mAudioEnvironment; ///< Audio environment
|
||||
S32 mForcedDetailLevel; ///< Forced LOD, if -1 auto LOD
|
||||
U32 mCRC; ///< CRC for the interior
|
||||
|
||||
public:
|
||||
|
||||
/// Returns the Light Manager handle
|
||||
LM_HANDLE getLMHandle() { return(mLMHandle); }
|
||||
|
||||
/// Returns the audio profile
|
||||
AudioProfile * getAudioProfile() { return(mAudioProfile); }
|
||||
|
||||
/// Returns the audio environment
|
||||
AudioEnvironment * getAudioEnvironment() { return(mAudioEnvironment); }
|
||||
|
||||
/// This is used to determine just how 'inside' a point is in an interior.
|
||||
/// This is used by the environmental audio code for audio properties and the
|
||||
/// function always returns true.
|
||||
/// @param pos Point to test
|
||||
/// @param pScale How inside is the point 0 = totally outside, 1 = totally inside (out)
|
||||
bool getPointInsideScale(const Point3F & pos, F32 * pScale); // ~0: outside -> 1: inside
|
||||
|
||||
/// Returns the interior resource
|
||||
Resource<InteriorResource> & getResource() {return(mInteriorRes);} // SceneLighting::InteriorProxy interface
|
||||
|
||||
/// Returns the CRC for validation
|
||||
U32 getCRC() { return(mCRC); }
|
||||
|
||||
/// @name Vertex Lighting
|
||||
/// Vertex lighting is the alternative to lightmapped interiors
|
||||
/// @{
|
||||
|
||||
Vector<Vector<ColorI>*> mVertexColorsNormal; ///< Vertex colors under normal lighting per detail level
|
||||
Vector<Vector<ColorI>*> mVertexColorsAlarm; ///< Vertex colors under alarm lighting per detail level
|
||||
|
||||
/// Rebuilds the vertex colors for alarm and normal states for all detail levels
|
||||
void rebuildVertexColors();
|
||||
|
||||
/// Returns the normal vertex lighting colors for a detail level
|
||||
/// @param detail Detail level
|
||||
Vector<ColorI>* getVertexColorsNormal(U32 detail);
|
||||
|
||||
/// Returns the alarm vertex lighting colors for a detail level
|
||||
/// @param detail Detail level
|
||||
Vector<ColorI>* getVertexColorsAlarm(U32 detail);
|
||||
|
||||
/// @}
|
||||
|
||||
// Alarm state information
|
||||
private:
|
||||
enum AlarmState {
|
||||
Normal = 0,
|
||||
Alarm = 1
|
||||
};
|
||||
|
||||
bool mAlarmState; ///< Alarm state of the interior
|
||||
|
||||
// LightingAnimation information
|
||||
private:
|
||||
struct LightInfo {
|
||||
struct Light {
|
||||
U32 curState;
|
||||
U32 curTime;
|
||||
ColorI curColor;
|
||||
|
||||
bool active;
|
||||
bool alarm;
|
||||
};
|
||||
struct StateDataInfo {
|
||||
ColorI curColor;
|
||||
U8* curMap;
|
||||
bool alarm;
|
||||
};
|
||||
|
||||
Vector<Light> mLights;
|
||||
BitVector mSurfaceInvalid;
|
||||
Vector<StateDataInfo> mStateDataInfo;
|
||||
};
|
||||
Vector<LightInfo> mLightInfo; ///< Light info, one per detail level
|
||||
LightUpdateGrouper* mUpdateGrouper; ///< Designed to group net updates for lights to reduce traffic
|
||||
|
||||
/// @name Light Grouper
|
||||
/// This is for managing light updates across the network
|
||||
/// @{
|
||||
|
||||
/// Creates an update key for the LightGrouper
|
||||
/// @param detail Detail level
|
||||
/// @param lightIndex Index of light in the interior
|
||||
static U32 makeUpdateKey(const U32 detail, const U32 lightIndex);
|
||||
|
||||
/// Takes an update key and returns the detail level part of it
|
||||
/// @param key Update key
|
||||
static U32 detailFromUpdateKey(const U32 key);
|
||||
|
||||
/// Takes an update key and returns the light index part of it
|
||||
/// 2param key Update key
|
||||
static U32 indexFromUpdateKey(const U32 key);
|
||||
/// @}
|
||||
|
||||
/// @name Animated light functions
|
||||
/// @{
|
||||
|
||||
/// Steps the animated light simulation by a delta
|
||||
/// @param detail Detail level of interior
|
||||
/// @param lightIndex Index of light to work on
|
||||
/// @param ms Time delta from last update in miliseconds
|
||||
void updateLightTime(const U32 detail, const U32 lightIndex, const U32 ms);
|
||||
|
||||
/// This loops through all the surfaces in an interior and calls updateLightMap on them
|
||||
/// @param state SceneState - Not used
|
||||
/// @param pInterior Interior to operate on
|
||||
/// @param rLightInfo Light to use
|
||||
void downloadLightmaps(SceneState *state, Interior *pInterior, LightInfo &rLightInfo);
|
||||
|
||||
/// This will set up a particular light in a particular detail level
|
||||
/// @param detail Detail level
|
||||
/// @param lightIndex Light to install
|
||||
void installLight(const U32 detail, const U32 lightIndex);
|
||||
|
||||
/// Called by updateLightTime to update a light with a looping animation
|
||||
/// @param interior Interior to work on
|
||||
/// @param light Light to update
|
||||
/// @param lightIndex Index of animated light
|
||||
/// @param ms Time delta from last update in miliseconds
|
||||
void updateLoopingLight(Interior *interior, LightInfo::Light &light, const U32 lightIndex, const U32 ms);
|
||||
|
||||
/// Called by updateLightTime to update a light with a flicker animation
|
||||
/// @param interior Interior to work on
|
||||
/// @param light Light to update
|
||||
/// @param lightIndex Index of animated light
|
||||
/// @param ms Time delta from last update in miliseconds
|
||||
void updateFlickerLight(Interior *interior, LightInfo::Light &light, const U32 lightIndex, const U32 ms);
|
||||
|
||||
/// Called by updateLightTime to update a light with a fade-up (ramp) animation light
|
||||
/// @param interior Interior to work on
|
||||
/// @param light Light to update
|
||||
/// @param lightIndex Index of animated light
|
||||
/// @param ms Time delta from last update in miliseconds
|
||||
void updateRampLight(Interior *interior, LightInfo::Light &light, const U32 lightIndex, const U32 ms);
|
||||
|
||||
/// Updates the animation for all lights
|
||||
/// @param ms Time delta since last call in ms
|
||||
void updateAllLights(const U32 ms);
|
||||
|
||||
/// Takes the original lightmap and adds the animated lights to it and then
|
||||
/// binds the texture to it
|
||||
/// @param pInterior Interior object to map
|
||||
/// @param rLightInfo Light info to use to update the light map
|
||||
/// @param surfaceIndex The surface to operate on inside the interior
|
||||
void updateLightMap(Interior *pInterior, LightInfo &rLightInfo, const U32 surfaceIndex);
|
||||
|
||||
/// lightMap is a 24-bit RGB texture, intensityMap is an 8 bit intensity map.
|
||||
/// This generates lightmap = [lightmap + (intensityMap * color)]
|
||||
/// @param lightMap Lightmap to operate on (in/out)
|
||||
/// @param width width of the ligth map
|
||||
/// @param height hight of the light map
|
||||
/// @param intensityMap Intensity map
|
||||
/// @param color Color
|
||||
void intensityMapMerge(U8* lightMap,
|
||||
const U32 width, const U32 height,
|
||||
const U8* intensityMap, const ColorI& color);
|
||||
/// @}
|
||||
|
||||
private:
|
||||
|
||||
/// Creates a transform based on an trigger area
|
||||
/// @param trigger Trigger to create a transform for
|
||||
/// @param transform Transform generated (out)
|
||||
void createTriggerTransform(const InteriorResTrigger *trigger, MatrixF *transform);
|
||||
};
|
||||
|
||||
inline void InteriorInstance::setLightUpdatedTime(const U32 now)
|
||||
{
|
||||
mLightUpdatedTime = now;
|
||||
}
|
||||
|
||||
inline U32 InteriorInstance::getLightUpdatedTime() const
|
||||
{
|
||||
return mLightUpdatedTime;
|
||||
}
|
||||
|
||||
inline U32 InteriorInstance::makeUpdateKey(const U32 detail, const U32 lightIndex)
|
||||
{
|
||||
AssertFatal(detail < (1 << 16) && lightIndex < (1 << 16), "Error, out of bounds key params");
|
||||
|
||||
return (detail << 16) | (lightIndex & 0x0000FFFF);
|
||||
}
|
||||
|
||||
inline U32 InteriorInstance::detailFromUpdateKey(const U32 key)
|
||||
{
|
||||
return (key >> 16) & 0xFFFF;
|
||||
}
|
||||
|
||||
inline U32 InteriorInstance::indexFromUpdateKey(const U32 key)
|
||||
{
|
||||
return (key >> 0) & 0xFFFF;
|
||||
}
|
||||
|
||||
inline Vector<ColorI>* InteriorInstance::getVertexColorsNormal(U32 detail)
|
||||
{
|
||||
if (bool(mInteriorRes) == false || detail > mInteriorRes->getNumDetailLevels())
|
||||
return NULL;
|
||||
|
||||
return mVertexColorsNormal[detail];
|
||||
}
|
||||
|
||||
inline Vector<ColorI>* InteriorInstance::getVertexColorsAlarm(U32 detail)
|
||||
{
|
||||
if (bool(mInteriorRes) == false || detail > mInteriorRes->getNumDetailLevels())
|
||||
return NULL;
|
||||
|
||||
return mVertexColorsAlarm[detail];
|
||||
}
|
||||
|
||||
#endif //_INTERIORBLOCK_H_
|
||||
|
570
engine/interior/interiorLMManager.cc
Executable file
570
engine/interior/interiorLMManager.cc
Executable file
@ -0,0 +1,570 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "interior/interiorLMManager.h"
|
||||
#include "dgl/gTexManager.h"
|
||||
#include "dgl/gBitmap.h"
|
||||
#include "platform/platformGL.h"
|
||||
#include "interior/interiorRes.h"
|
||||
#include "interior/interiorInstance.h"
|
||||
#include "interior/interior.h"
|
||||
#include "sceneGraph/sceneLighting.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Globals
|
||||
InteriorLMManager gInteriorLMManager;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
namespace {
|
||||
void interiorLMTextureCallback(const U32 eventCode, void * userData)
|
||||
{
|
||||
AssertFatal(&gInteriorLMManager == reinterpret_cast<InteriorLMManager*>(userData), "Bunk ptr!");
|
||||
gInteriorLMManager.processTextureEvent(eventCode);
|
||||
}
|
||||
|
||||
// '<interior>_<instance index>_lm_<lightmap index>.png'
|
||||
const char * getTextureName(Interior * interior, U32 instance, U32 lightmap)
|
||||
{
|
||||
static char buffer[256];
|
||||
dSprintf(buffer, sizeof(buffer), "%p_%d_lm_%d.png", interior, instance, lightmap);
|
||||
return(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
U32 InteriorLMManager::smTextureCallbackKey = U32(-1);
|
||||
|
||||
// D3D vertex buffers for Interiors are in here so they get dumped/reallocated
|
||||
// along with the lightmaps on the texture events
|
||||
S32 InteriorLMManager::smMTVertexBuffer = -1;
|
||||
S32 InteriorLMManager::smFTVertexBuffer = -1;
|
||||
S32 InteriorLMManager::smFMTVertexBuffer = -1;
|
||||
|
||||
InteriorLMManager::InteriorLMManager()
|
||||
{
|
||||
}
|
||||
|
||||
InteriorLMManager::~InteriorLMManager()
|
||||
{
|
||||
for(U32 i = 0; i < mInteriors.size(); i++)
|
||||
removeInterior(LM_HANDLE(i));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void InteriorLMManager::init()
|
||||
{
|
||||
smTextureCallbackKey = TextureManager::registerEventCallback(interiorLMTextureCallback, &gInteriorLMManager);
|
||||
}
|
||||
|
||||
void InteriorLMManager::destroy()
|
||||
{
|
||||
if(smTextureCallbackKey != U32(-1))
|
||||
{
|
||||
TextureManager::unregisterEventCallback(smTextureCallbackKey);
|
||||
smTextureCallbackKey = U32(-1);
|
||||
}
|
||||
|
||||
if (smMTVertexBuffer != -1)
|
||||
{
|
||||
if (dglDoesSupportVertexBuffer())
|
||||
glFreeVertexBufferEXT(smMTVertexBuffer);
|
||||
else
|
||||
AssertFatal(false,"Vertex buffer should have already been freed!");
|
||||
smMTVertexBuffer = -1;
|
||||
}
|
||||
if (smFTVertexBuffer != -1)
|
||||
{
|
||||
if (dglDoesSupportVertexBuffer())
|
||||
glFreeVertexBufferEXT(smFTVertexBuffer);
|
||||
else
|
||||
AssertFatal(false,"Vertex buffer should have already been freed!");
|
||||
smFTVertexBuffer = -1;
|
||||
}
|
||||
if (smFMTVertexBuffer != -1)
|
||||
{
|
||||
if (dglDoesSupportVertexBuffer())
|
||||
glFreeVertexBufferEXT(smFMTVertexBuffer);
|
||||
else
|
||||
AssertFatal(false,"Vertex buffer should have already been freed!");
|
||||
smFMTVertexBuffer = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void InteriorLMManager::processTextureEvent(U32 eventCode)
|
||||
{
|
||||
switch(eventCode)
|
||||
{
|
||||
case TextureManager::BeginZombification:
|
||||
purgeGLTextures();
|
||||
|
||||
if (smMTVertexBuffer != -1)
|
||||
{
|
||||
if (dglDoesSupportVertexBuffer())
|
||||
glFreeVertexBufferEXT(smMTVertexBuffer);
|
||||
else
|
||||
AssertFatal(false,"Vertex buffer should have already been freed!");
|
||||
smMTVertexBuffer = -1;
|
||||
}
|
||||
if (smFTVertexBuffer != -1)
|
||||
{
|
||||
if (dglDoesSupportVertexBuffer())
|
||||
glFreeVertexBufferEXT(smFTVertexBuffer);
|
||||
else
|
||||
AssertFatal(false,"Vertex buffer should have already been freed!");
|
||||
smFTVertexBuffer = -1;
|
||||
}
|
||||
if (smFMTVertexBuffer != -1)
|
||||
{
|
||||
if (dglDoesSupportVertexBuffer())
|
||||
glFreeVertexBufferEXT(smFMTVertexBuffer);
|
||||
else
|
||||
AssertFatal(false,"Vertex buffer should have already been freed!");
|
||||
smFMTVertexBuffer = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case TextureManager::CacheResurrected:
|
||||
// relighting the scene will take care of things for us
|
||||
if(mInteriors.size())
|
||||
SceneLighting::lightScene(0, SceneLighting::LoadOnly);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void InteriorLMManager::addInterior(LM_HANDLE & interiorHandle, U32 numLightmaps, Interior * interior)
|
||||
{
|
||||
interiorHandle = mInteriors.size();
|
||||
mInteriors.increment();
|
||||
mInteriors.last() = new InteriorLMInfo;
|
||||
|
||||
mInteriors.last()->mInterior = interior;
|
||||
mInteriors.last()->mHandlePtr = &interiorHandle;
|
||||
mInteriors.last()->mNumLightmaps = numLightmaps;
|
||||
|
||||
// create base instance
|
||||
addInstance(interiorHandle, mInteriors.last()->mBaseInstanceHandle, 0);
|
||||
AssertFatal(mInteriors.last()->mBaseInstanceHandle == LM_HANDLE(0), "InteriorLMManager::addInterior: invalid base instance handle");
|
||||
|
||||
// steal the lightmaps from the interior
|
||||
Vector<TextureHandle*>& texHandles = getHandles(interiorHandle, 0);
|
||||
for(U32 i = 0; i < interior->mLightmaps.size(); i++)
|
||||
{
|
||||
AssertFatal(interior->mLightmaps[i], "InteriorLMManager::addInterior: interior missing lightmap");
|
||||
texHandles[i] = new TextureHandle(getTextureName(interior, 0, i), interior->mLightmaps[i], BitmapNoDownloadTexture);
|
||||
}
|
||||
|
||||
interior->mLightmaps.clear();
|
||||
}
|
||||
|
||||
void InteriorLMManager::removeInterior(LM_HANDLE interiorHandle)
|
||||
{
|
||||
AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::removeInterior: invalid interior handle");
|
||||
AssertFatal(mInteriors[interiorHandle]->mInstances.size() == 1, "InteriorLMManager::removeInterior: cannot remove base interior");
|
||||
|
||||
// remove base instance
|
||||
removeInstance(interiorHandle, 0);
|
||||
|
||||
*mInteriors[interiorHandle]->mHandlePtr = LM_HANDLE(-1);
|
||||
|
||||
delete mInteriors[interiorHandle];
|
||||
|
||||
// last one? otherwise move it
|
||||
if((mInteriors.size()-1) != interiorHandle)
|
||||
{
|
||||
mInteriors[interiorHandle] = mInteriors.last();
|
||||
*(mInteriors[interiorHandle]->mHandlePtr) = interiorHandle;
|
||||
}
|
||||
|
||||
mInteriors.decrement();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void InteriorLMManager::addInstance(LM_HANDLE interiorHandle, LM_HANDLE & instanceHandle, InteriorInstance * instance)
|
||||
{
|
||||
AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::addInstance: invalid interior handle");
|
||||
AssertFatal(interiorHandle == *(mInteriors[interiorHandle]->mHandlePtr), "InteriorLMManager::addInstance: invalid handle value");
|
||||
|
||||
InteriorLMInfo * interiorInfo = mInteriors[interiorHandle];
|
||||
|
||||
// create the instance info and fill
|
||||
InstanceLMInfo * instanceInfo = new InstanceLMInfo;
|
||||
|
||||
instanceInfo->mInstance = instance;
|
||||
instanceInfo->mHandlePtr = &instanceHandle;
|
||||
instanceHandle = interiorInfo->mInstances.size();
|
||||
|
||||
interiorInfo->mInstances.push_back(instanceInfo);
|
||||
|
||||
// create/clear list
|
||||
instanceInfo->mLightmapHandles.setSize(interiorInfo->mNumLightmaps);
|
||||
dMemset(instanceInfo->mLightmapHandles.address(), 0, sizeof(TextureHandle*) * instanceInfo->mLightmapHandles.size());
|
||||
}
|
||||
|
||||
void InteriorLMManager::removeInstance(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle)
|
||||
{
|
||||
AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::removeInstance: invalid interior handle");
|
||||
AssertFatal(instanceHandle < mInteriors[interiorHandle]->mInstances.size(), "InteriorLMManager::removeInstance: invalid instance handle");
|
||||
AssertFatal(!(instanceHandle == mInteriors[interiorHandle]->mBaseInstanceHandle &&
|
||||
mInteriors[interiorHandle]->mInstances.size() > 1), "InteriorLMManager::removeInstance: invalid base instance");
|
||||
|
||||
InteriorLMInfo * itrInfo = mInteriors[interiorHandle];
|
||||
|
||||
// kill it
|
||||
InstanceLMInfo * instInfo = itrInfo->mInstances[instanceHandle];
|
||||
for(U32 i = 0; i < instInfo->mLightmapHandles.size(); i++)
|
||||
delete instInfo->mLightmapHandles[i];
|
||||
|
||||
// reset on last instance removal only (multi detailed shapes share the same instance handle)
|
||||
if(itrInfo->mInstances.size() == 1)
|
||||
*instInfo->mHandlePtr = LM_HANDLE(-1);
|
||||
|
||||
delete instInfo;
|
||||
|
||||
// last one? otherwise move it
|
||||
if((itrInfo->mInstances.size()-1) != instanceHandle)
|
||||
{
|
||||
itrInfo->mInstances[instanceHandle] = itrInfo->mInstances.last();
|
||||
*(itrInfo->mInstances[instanceHandle]->mHandlePtr) = instanceHandle;
|
||||
}
|
||||
|
||||
itrInfo->mInstances.decrement();
|
||||
}
|
||||
|
||||
void InteriorLMManager::useBaseTextures(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle)
|
||||
{
|
||||
AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::useBaseTextures: invalid interior handle");
|
||||
AssertFatal(interiorHandle == *(mInteriors[interiorHandle]->mHandlePtr), "InteriorLMManager::useBaseTextures: invalid handle value");
|
||||
|
||||
// Make sure the base light maps are loaded
|
||||
loadBaseLightmaps(interiorHandle,instanceHandle);
|
||||
|
||||
// Install base lightmaps for this instance...
|
||||
Vector<TextureHandle*>& baseHandles = getHandles(interiorHandle, 0);
|
||||
Vector<TextureHandle*>& texHandles = getHandles(interiorHandle, instanceHandle);
|
||||
for(U32 i = 0; i < baseHandles.size(); i++)
|
||||
texHandles[i] = new TextureHandle(*baseHandles[i]);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void InteriorLMManager::destroyBitmaps()
|
||||
{
|
||||
for(S32 i = mInteriors.size() - 1; i >= 0; i--)
|
||||
{
|
||||
InteriorLMInfo * interiorInfo = mInteriors[i];
|
||||
for(S32 j = interiorInfo->mInstances.size() - 1; j >= 0; j--)
|
||||
{
|
||||
InstanceLMInfo * instanceInfo = interiorInfo->mInstances[j];
|
||||
for(S32 k = instanceInfo->mLightmapHandles.size() - 1; k >= 0; k--)
|
||||
{
|
||||
if(!instanceInfo->mLightmapHandles[k])
|
||||
continue;
|
||||
|
||||
TextureObject * texObj = *instanceInfo->mLightmapHandles[k];
|
||||
if(!texObj || !texObj->bitmap)
|
||||
continue;
|
||||
|
||||
// don't remove 'keep' bitmaps
|
||||
if(!interiorInfo->mInterior->mLightmapKeep[k])
|
||||
{
|
||||
delete texObj->bitmap;
|
||||
texObj->bitmap = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InteriorLMManager::destroyTextures()
|
||||
{
|
||||
for(S32 i = mInteriors.size() - 1; i >= 0; i--)
|
||||
{
|
||||
InteriorLMInfo * interiorInfo = mInteriors[i];
|
||||
for(S32 j = interiorInfo->mInstances.size() - 1; j >= 0; j--)
|
||||
{
|
||||
InstanceLMInfo * instanceInfo = interiorInfo->mInstances[j];
|
||||
for(S32 k = interiorInfo->mNumLightmaps - 1; k >= 0; k--)
|
||||
{
|
||||
// will want to remove the vector here eventually... so don't clear
|
||||
delete instanceInfo->mLightmapHandles[k];
|
||||
instanceInfo->mLightmapHandles[k] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InteriorLMManager::purgeGLTextures()
|
||||
{
|
||||
Vector<GLuint> purgeList(4096);
|
||||
|
||||
for(S32 i = mInteriors.size() - 1; i >= 0; i--)
|
||||
{
|
||||
InteriorLMInfo * interiorInfo = mInteriors[i];
|
||||
for(S32 j = interiorInfo->mInstances.size() - 1; j >= 0; j--)
|
||||
{
|
||||
InstanceLMInfo * instanceInfo = interiorInfo->mInstances[j];
|
||||
for(S32 k = instanceInfo->mLightmapHandles.size() - 1; k >= 0; k--)
|
||||
{
|
||||
if(!instanceInfo->mLightmapHandles[k])
|
||||
continue;
|
||||
|
||||
TextureObject * texObj = *instanceInfo->mLightmapHandles[k];
|
||||
if(!texObj || !texObj->texGLName)
|
||||
continue;
|
||||
|
||||
#ifdef TORQUE_GATHER_METRICS
|
||||
AssertFatal(texObj->textureSpace <= TextureManager::smTextureSpaceLoaded, "Doh!");
|
||||
TextureManager::smTextureSpaceLoaded -= texObj->textureSpace;
|
||||
texObj->textureSpace = 0;
|
||||
#endif
|
||||
|
||||
purgeList.push_back(texObj->texGLName);
|
||||
texObj->texGLName = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glDeleteTextures(purgeList.size(), purgeList.address());
|
||||
}
|
||||
|
||||
void InteriorLMManager::downloadGLTextures()
|
||||
{
|
||||
for(S32 i = mInteriors.size() - 1; i >= 0; i--)
|
||||
downloadGLTextures(i);
|
||||
}
|
||||
|
||||
void InteriorLMManager::downloadGLTextures(LM_HANDLE interiorHandle)
|
||||
{
|
||||
AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::downloadGLTextures: invalid interior handle");
|
||||
InteriorLMInfo * interiorInfo = mInteriors[interiorHandle];
|
||||
|
||||
// The bit vector is used to keep track of which lightmap sets need
|
||||
// to be loaded from the shared "base" instance. Every instance
|
||||
// can have it's own lightmap set due to mission lighting.
|
||||
BitVector needTexture;
|
||||
needTexture.setSize(interiorInfo->mNumLightmaps);
|
||||
needTexture.clear();
|
||||
|
||||
for(S32 j = interiorInfo->mInstances.size() - 1; j >= 0; j--)
|
||||
{
|
||||
InstanceLMInfo * instanceInfo = interiorInfo->mInstances[j];
|
||||
for(S32 k = instanceInfo->mLightmapHandles.size() - 1; k >= 0; k--)
|
||||
{
|
||||
// All instances can share the base instances static lightmaps.
|
||||
// Test here to see if we need to load those lightmaps.
|
||||
if ((j == 0) && !needTexture.test(k))
|
||||
continue;
|
||||
if (!instanceInfo->mLightmapHandles[k]) {
|
||||
needTexture.set(k);
|
||||
continue;
|
||||
}
|
||||
TextureObject * texObj = *instanceInfo->mLightmapHandles[k];
|
||||
if (!texObj || !texObj->bitmap) {
|
||||
needTexture.set(k);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Make sure this one is not already loaded.
|
||||
if (texObj->texGLName)
|
||||
continue;
|
||||
|
||||
// Go ahead and download this set to GL
|
||||
#ifdef TORQUE_GATHER_METRICS
|
||||
texObj->textureSpace = texObj->downloadedWidth * texObj->downloadedHeight;
|
||||
TextureManager::smTextureSpaceLoaded += texObj->textureSpace;
|
||||
#endif
|
||||
TextureManager::createGLName(texObj->bitmap, texObj->clamp, 0, texObj->type, texObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool InteriorLMManager::loadBaseLightmaps(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle)
|
||||
{
|
||||
AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::loadBaseLightmaps: invalid interior handle");
|
||||
AssertFatal(instanceHandle < mInteriors[interiorHandle]->mInstances.size(), "InteriorLMManager::loadBaseLightmaps: invalid instance handle");
|
||||
|
||||
// must use a valid instance handle
|
||||
if(!instanceHandle)
|
||||
return(false);
|
||||
|
||||
InteriorLMInfo * interiorInfo = mInteriors[interiorHandle];
|
||||
if(!interiorInfo->mNumLightmaps)
|
||||
return(false);
|
||||
|
||||
InstanceLMInfo * baseInstanceInfo = interiorInfo->mInstances[0];
|
||||
|
||||
// already loaded? (if any bitmap is present, then assumed that all will be)
|
||||
TextureHandle * texture = baseInstanceInfo->mLightmapHandles[0];
|
||||
if(texture && texture->getBitmap())
|
||||
return(true);
|
||||
|
||||
InstanceLMInfo * instanceInfo = interiorInfo->mInstances[instanceHandle];
|
||||
|
||||
Resource<InteriorResource> & interiorRes = instanceInfo->mInstance->getResource();
|
||||
if(!bool(interiorRes))
|
||||
return(false);
|
||||
|
||||
GBitmap *** pBitmaps = 0;
|
||||
if(!instanceInfo->mInstance->readLightmaps(&pBitmaps))
|
||||
return(false);
|
||||
|
||||
for(U32 i = 0; i < interiorRes->getNumDetailLevels(); i++)
|
||||
{
|
||||
Interior * interior = interiorRes->getDetailLevel(i);
|
||||
AssertFatal(interior, "InteriorLMManager::loadBaseLightmaps: invalid detail level in resource");
|
||||
AssertFatal(interior->getLMHandle() != LM_HANDLE(-1), "InteriorLMManager::loadBaseLightmaps: interior not added to manager");
|
||||
AssertFatal(interior->getLMHandle() < mInteriors.size(), "InteriorLMManager::loadBaseLightmaps: invalid interior");
|
||||
|
||||
InteriorLMInfo * interiorInfo = mInteriors[interior->getLMHandle()];
|
||||
InstanceLMInfo * baseInstanceInfo = interiorInfo->mInstances[0];
|
||||
|
||||
for(U32 j = 0; j < interiorInfo->mNumLightmaps; j++)
|
||||
{
|
||||
AssertFatal(pBitmaps[i][j], "InteriorLMManager::loadBaseLightmaps: invalid bitmap");
|
||||
|
||||
if (baseInstanceInfo->mLightmapHandles[j])
|
||||
{
|
||||
TextureObject * texObj = *baseInstanceInfo->mLightmapHandles[j];
|
||||
texObj->bitmap = pBitmaps[i][j];
|
||||
}
|
||||
else
|
||||
baseInstanceInfo->mLightmapHandles[j] = new TextureHandle(getTextureName(interior, 0, j), pBitmaps[i][j], BitmapNoDownloadTexture);
|
||||
}
|
||||
delete [] pBitmaps[i];
|
||||
}
|
||||
|
||||
delete [] pBitmaps;
|
||||
return(true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
TextureHandle * InteriorLMManager::getHandle(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle, U32 index)
|
||||
{
|
||||
AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::getHandle: invalid interior handle");
|
||||
AssertFatal(instanceHandle < mInteriors[interiorHandle]->mInstances.size(), "InteriorLMManager::getHandle: invalid instance handle");
|
||||
AssertFatal(index < mInteriors[interiorHandle]->mNumLightmaps, "InteriorLMManager::getHandle: invalid texture index");
|
||||
|
||||
// valid? if not, then get base lightmap handle
|
||||
if(!mInteriors[interiorHandle]->mInstances[instanceHandle]->mLightmapHandles[index])
|
||||
{
|
||||
AssertFatal(mInteriors[interiorHandle]->mInstances[0]->mLightmapHandles[index], "InteriorLMManager::getHandle: invalid base texture handle");
|
||||
return(mInteriors[interiorHandle]->mInstances[0]->mLightmapHandles[index]);
|
||||
}
|
||||
return(mInteriors[interiorHandle]->mInstances[instanceHandle]->mLightmapHandles[index]);
|
||||
}
|
||||
|
||||
GBitmap * InteriorLMManager::getBitmap(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle, U32 index)
|
||||
{
|
||||
AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::getBitmap: invalid interior handle");
|
||||
AssertFatal(instanceHandle < mInteriors[interiorHandle]->mInstances.size(), "InteriorLMManager::getBitmap: invalid instance handle");
|
||||
AssertFatal(index < mInteriors[interiorHandle]->mNumLightmaps, "InteriorLMManager::getBitmap: invalid texture index");
|
||||
|
||||
if(!mInteriors[interiorHandle]->mInstances[instanceHandle]->mLightmapHandles[index])
|
||||
{
|
||||
AssertFatal(mInteriors[interiorHandle]->mInstances[0]->mLightmapHandles[index], "InteriorLMManager::getBitmap: invalid base texture handle");
|
||||
return(mInteriors[interiorHandle]->mInstances[0]->mLightmapHandles[index]->getBitmap());
|
||||
}
|
||||
|
||||
return(mInteriors[interiorHandle]->mInstances[instanceHandle]->mLightmapHandles[index]->getBitmap());
|
||||
}
|
||||
|
||||
Vector<TextureHandle*> & InteriorLMManager::getHandles(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle)
|
||||
{
|
||||
AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::getHandles: invalid interior handle");
|
||||
AssertFatal(instanceHandle < mInteriors[interiorHandle]->mInstances.size(), "InteriorLMManager::getHandles: invalid instance handle");
|
||||
return(mInteriors[interiorHandle]->mInstances[instanceHandle]->mLightmapHandles);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
U32 InteriorLMManager::getNumLightmaps(LM_HANDLE interiorHandle)
|
||||
{
|
||||
AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::getNumLightmaps: invalid interior handle");
|
||||
return(mInteriors[interiorHandle]->mNumLightmaps);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void InteriorLMManager::deleteLightmap(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle, U32 index)
|
||||
{
|
||||
AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::deleteLightmap: invalid interior handle");
|
||||
AssertFatal(instanceHandle < mInteriors[interiorHandle]->mInstances.size(), "InteriorLMManager::deleteLightmap: invalid instance handle");
|
||||
AssertFatal(index < mInteriors[interiorHandle]->mNumLightmaps, "InteriorLMManager::deleteLightmap: invalid texture index");
|
||||
|
||||
delete mInteriors[interiorHandle]->mInstances[instanceHandle]->mLightmapHandles[index];
|
||||
mInteriors[interiorHandle]->mInstances[instanceHandle]->mLightmapHandles[index] = 0;
|
||||
}
|
||||
|
||||
void InteriorLMManager::clearLightmaps(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle)
|
||||
{
|
||||
AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::clearLightmaps: invalid interior handle");
|
||||
AssertFatal(instanceHandle < mInteriors[interiorHandle]->mInstances.size(), "InteriorLMManager::clearLightmaps: invalid instance handle");
|
||||
|
||||
for(U32 i = 0; i < mInteriors[interiorHandle]->mNumLightmaps; i++)
|
||||
{
|
||||
delete mInteriors[interiorHandle]->mInstances[instanceHandle]->mLightmapHandles[i];
|
||||
mInteriors[interiorHandle]->mInstances[instanceHandle]->mLightmapHandles[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
TextureHandle * InteriorLMManager::duplicateBaseLightmap(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle, U32 index)
|
||||
{
|
||||
AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::duplicateBaseLightmap: invalid interior handle");
|
||||
AssertFatal(instanceHandle < mInteriors[interiorHandle]->mInstances.size(), "InteriorLMManager::duplicateBaseLightmap: invalid instance handle");
|
||||
AssertFatal(index < mInteriors[interiorHandle]->mNumLightmaps, "InteriorLMManager::duplicateBaseLightmap: invalid texture index");
|
||||
|
||||
// already exists?
|
||||
TextureHandle * texHandle = mInteriors[interiorHandle]->mInstances[instanceHandle]->mLightmapHandles[index];
|
||||
if(texHandle && static_cast<TextureObject*>(*texHandle)->bitmap)
|
||||
return(texHandle);
|
||||
|
||||
AssertFatal(mInteriors[interiorHandle]->mInstances[0]->mLightmapHandles[index], "InteriorLMManager::duplicateBaseLightmap: invalid base handle");
|
||||
|
||||
// copy it
|
||||
GBitmap * src = mInteriors[interiorHandle]->mInstances[0]->mLightmapHandles[index]->getBitmap();
|
||||
GBitmap * dest = new GBitmap(*src);
|
||||
|
||||
// don't want this texture to be downloaded yet (SceneLighting will take care of that)
|
||||
TextureHandle * tHandle = new TextureHandle(getTextureName(mInteriors[interiorHandle]->mInterior, instanceHandle, index), dest, BitmapNoDownloadTexture);
|
||||
mInteriors[interiorHandle]->mInstances[instanceHandle]->mLightmapHandles[index] = tHandle;
|
||||
return(tHandle);
|
||||
}
|
||||
|
||||
S32 InteriorLMManager::getVertexBuffer(S32 format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case GL_V12MTVFMT_EXT:
|
||||
{
|
||||
if (smMTVertexBuffer != -1)
|
||||
return smMTVertexBuffer;
|
||||
|
||||
smMTVertexBuffer = glAllocateVertexBufferEXT(512,GL_V12MTVFMT_EXT,false);
|
||||
|
||||
return smMTVertexBuffer;
|
||||
}
|
||||
case GL_V12FTVFMT_EXT:
|
||||
{
|
||||
if (smFTVertexBuffer != -1)
|
||||
return smFTVertexBuffer;
|
||||
|
||||
smFTVertexBuffer = glAllocateVertexBufferEXT(512,GL_V12FTVFMT_EXT,false);
|
||||
|
||||
return smFTVertexBuffer;
|
||||
}
|
||||
case GL_V12FMTVFMT_EXT:
|
||||
{
|
||||
if (smFMTVertexBuffer != -1)
|
||||
return smFMTVertexBuffer;
|
||||
|
||||
smFMTVertexBuffer = glAllocateVertexBufferEXT(512,GL_V12FMTVFMT_EXT,false);
|
||||
|
||||
return smFMTVertexBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
AssertFatal(false,"InteriorLMManager::getVertexBuffer() What? We should never get here!!!");
|
||||
|
||||
return -1;
|
||||
}
|
92
engine/interior/interiorLMManager.h
Executable file
92
engine/interior/interiorLMManager.h
Executable file
@ -0,0 +1,92 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _INTERIORLMMANAGER_H_
|
||||
#define _INTERIORLMMANAGER_H_
|
||||
|
||||
#ifndef _PLATFORM_H_
|
||||
#include "platform/platform.h"
|
||||
#endif
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/tVector.h"
|
||||
#endif
|
||||
|
||||
class TextureHandle;
|
||||
class GBitmap;
|
||||
class Interior;
|
||||
class InteriorInstance;
|
||||
|
||||
typedef U32 LM_HANDLE;
|
||||
|
||||
class InteriorLMManager
|
||||
{
|
||||
private:
|
||||
|
||||
struct InstanceLMInfo
|
||||
{
|
||||
InteriorInstance * mInstance;
|
||||
LM_HANDLE * mHandlePtr;
|
||||
Vector<TextureHandle*> mLightmapHandles;
|
||||
};
|
||||
|
||||
struct InteriorLMInfo
|
||||
{
|
||||
Interior * mInterior;
|
||||
LM_HANDLE * mHandlePtr;
|
||||
U32 mNumLightmaps;
|
||||
LM_HANDLE mBaseInstanceHandle;
|
||||
Vector<InstanceLMInfo*> mInstances;
|
||||
};
|
||||
|
||||
Vector<InteriorLMInfo*> mInteriors;
|
||||
|
||||
static S32 smMTVertexBuffer;
|
||||
static S32 smFTVertexBuffer;
|
||||
static S32 smFMTVertexBuffer;
|
||||
|
||||
public:
|
||||
|
||||
static U32 smTextureCallbackKey;
|
||||
|
||||
InteriorLMManager();
|
||||
~InteriorLMManager();
|
||||
|
||||
static void init();
|
||||
static void destroy();
|
||||
|
||||
void processTextureEvent(U32 eventCode);
|
||||
|
||||
void destroyBitmaps();
|
||||
void destroyTextures();
|
||||
|
||||
void purgeGLTextures();
|
||||
void downloadGLTextures();
|
||||
void downloadGLTextures(LM_HANDLE interiorHandle);
|
||||
bool loadBaseLightmaps(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle);
|
||||
|
||||
void addInterior(LM_HANDLE & interiorHandle, U32 numLightmaps, Interior * interior);
|
||||
void removeInterior(LM_HANDLE interiorHandle);
|
||||
|
||||
void addInstance(LM_HANDLE interiorHandle, LM_HANDLE & instanceHandle, InteriorInstance * instance);
|
||||
void removeInstance(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle);
|
||||
void useBaseTextures(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle);
|
||||
|
||||
U32 getNumLightmaps(LM_HANDLE interiorHandle);
|
||||
void deleteLightmap(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle, U32 index);
|
||||
void clearLightmaps(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle);
|
||||
|
||||
TextureHandle * getHandle(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle, U32 index);
|
||||
Vector<TextureHandle*> & getHandles(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle);
|
||||
|
||||
// helper's
|
||||
TextureHandle * duplicateBaseLightmap(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle, U32 index);
|
||||
GBitmap * getBitmap(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle, U32 index);
|
||||
|
||||
S32 getVertexBuffer(S32 format);
|
||||
};
|
||||
|
||||
extern InteriorLMManager gInteriorLMManager;
|
||||
|
||||
#endif
|
404
engine/interior/interiorLightAnim.cc
Executable file
404
engine/interior/interiorLightAnim.cc
Executable file
@ -0,0 +1,404 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "interior/interiorInstance.h"
|
||||
#include "interior/lightUpdateGrouper.h"
|
||||
#include "interior/interior.h"
|
||||
#include "math/mRandom.h"
|
||||
|
||||
void InteriorInstance::echoTriggerableLights()
|
||||
{
|
||||
// DMMFIX: Only the first detail for now...
|
||||
Interior* pInterior = mInteriorRes->getDetailLevel(0);
|
||||
|
||||
Con::printf("Interior: %s", mInteriorFileName);
|
||||
Con::printf(" %d Triggerable lights:", pInterior->mNumTriggerableLights);
|
||||
|
||||
// Triggerable lights are always the first in the array...
|
||||
for (U32 i = 0; i < pInterior->mNumTriggerableLights; i++) {
|
||||
const char* pName = pInterior->getName(pInterior->mAnimatedLights[i].nameIndex);
|
||||
U32 type = pInterior->mAnimatedLights[i].flags & Interior::AnimationTypeMask;
|
||||
float duration = pInterior->mAnimatedLights[i].duration;
|
||||
U32 numStates = pInterior->mAnimatedLights[i].stateCount;
|
||||
|
||||
Con::printf(" - %s [%s, Duration: %g, NumStates: %d]",
|
||||
pName, Interior::getLightTypeString(Interior::LightType(type)),
|
||||
duration, numStates);
|
||||
}
|
||||
}
|
||||
|
||||
void InteriorInstance::activateLight(const char* pLightName)
|
||||
{
|
||||
if (bool(mInteriorRes) == false) {
|
||||
AssertWarn(false, "Activating a light on an unloaded interior!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Now, it's a real pain in the ass to try to keep track of light states on detail
|
||||
// changes as we did in tribes 1. There, we analyzed the state on a detail change
|
||||
// and tried to duplicate that state on the detail level we were switching to.
|
||||
// Inspiration: forget that, and just animate the lights on all the details all
|
||||
// the time. Unless the detail is rendering, the lightmap data will never be
|
||||
// downloaded, and the amount of time necessary to keep the lights updated on
|
||||
// a detail level is absolutely miniscule. Much easier.
|
||||
//
|
||||
for (U32 i = 0; i < mInteriorRes->getNumDetailLevels(); i++) {
|
||||
Interior* pInterior = mInteriorRes->getDetailLevel(i);
|
||||
|
||||
for (U32 j = 0; j < pInterior->mNumTriggerableLights; j++) {
|
||||
const char* pILightName = pInterior->getName(pInterior->mAnimatedLights[j].nameIndex);
|
||||
if (dStricmp(pLightName, pILightName) == 0) {
|
||||
activateLight(i, j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InteriorInstance::deactivateLight(const char* pLightName)
|
||||
{
|
||||
if (bool(mInteriorRes) == false) {
|
||||
AssertWarn(false, "Deactivating a light on an unloaded interior!");
|
||||
return;
|
||||
}
|
||||
|
||||
for (U32 i = 0; i < mInteriorRes->getNumDetailLevels(); i++) {
|
||||
Interior* pInterior = mInteriorRes->getDetailLevel(i);
|
||||
|
||||
for (U32 j = 0; j < pInterior->mNumTriggerableLights; j++) {
|
||||
const char* pILightName = pInterior->getName(pInterior->mAnimatedLights[j].nameIndex);
|
||||
if (dStricmp(pLightName, pILightName) == 0) {
|
||||
deactivateLight(i, j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InteriorInstance::updateAllLights(const U32 ms)
|
||||
{
|
||||
if (bool(mInteriorRes) == false)
|
||||
return;
|
||||
|
||||
for (U32 i = 0; i < mInteriorRes->getNumDetailLevels(); i++) {
|
||||
LightInfo& rLightInfo = mLightInfo[i];
|
||||
|
||||
for (U32 j = 0; j < rLightInfo.mLights.size(); j++) {
|
||||
if (mAlarmState == Normal) {
|
||||
if (rLightInfo.mLights[j].active == true && rLightInfo.mLights[j].alarm == false)
|
||||
updateLightTime(i, j, ms);
|
||||
} else {
|
||||
if (rLightInfo.mLights[j].alarm == true)
|
||||
updateLightTime(i, j, ms);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void InteriorInstance::activateLight(const U32 detail, const U32 lightIndex)
|
||||
{
|
||||
AssertFatal(bool(mInteriorRes) && detail < mInteriorRes->getNumDetailLevels(), "Error, no interior resource, or out of range detail level");
|
||||
AssertFatal(lightIndex < mInteriorRes->getDetailLevel(detail)->mAnimatedLights.size(), "Error, out of bounds light index");
|
||||
|
||||
LightInfo& rLightInfo = mLightInfo[detail];
|
||||
LightInfo::Light& rLight = rLightInfo.mLights[lightIndex];
|
||||
|
||||
if (rLight.active == false) {
|
||||
rLight.active = true;
|
||||
rLight.curState = 0;
|
||||
rLight.curTime = 0;
|
||||
|
||||
Interior* pInterior = mInteriorRes->getDetailLevel(detail);
|
||||
Interior::LightState& rState = pInterior->mLightStates[pInterior->mAnimatedLights[lightIndex].stateIndex];
|
||||
rLight.curColor.set(rState.red, rState.green, rState.blue);
|
||||
|
||||
installLight(detail, lightIndex);
|
||||
|
||||
if (isServerObject() && lightIndex < pInterior->mNumTriggerableLights) {
|
||||
U32 key = makeUpdateKey(detail, lightIndex);
|
||||
U32 mask = mUpdateGrouper->getKeyMask(key);
|
||||
setMaskBits(mask);
|
||||
}
|
||||
} else {
|
||||
// Light is already active, no need to play around further...
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void InteriorInstance::deactivateLight(const U32 detail, const U32 lightIndex)
|
||||
{
|
||||
AssertFatal(bool(mInteriorRes) && detail < mInteriorRes->getNumDetailLevels(), "Error, no interior resource, or out of range detail level");
|
||||
AssertFatal(lightIndex < mInteriorRes->getDetailLevel(detail)->mAnimatedLights.size(), "Error, out of bounds light index");
|
||||
|
||||
LightInfo& rLightInfo = mLightInfo[detail];
|
||||
LightInfo::Light& rLight = rLightInfo.mLights[lightIndex];
|
||||
|
||||
if (rLight.active == true) {
|
||||
// DMMFIX
|
||||
|
||||
rLight.active = false;
|
||||
rLight.curState = 0;
|
||||
rLight.curTime = 0;
|
||||
|
||||
Interior* pInterior = mInteriorRes->getDetailLevel(detail);
|
||||
Interior::LightState& rState = pInterior->mLightStates[pInterior->mAnimatedLights[lightIndex].stateIndex];
|
||||
rLight.curColor.set(rState.red, rState.green, rState.blue);
|
||||
|
||||
installLight(detail, lightIndex);
|
||||
|
||||
if (isServerObject() && lightIndex < pInterior->mNumTriggerableLights) {
|
||||
U32 key = makeUpdateKey(detail, lightIndex);
|
||||
U32 mask = mUpdateGrouper->getKeyMask(key);
|
||||
setMaskBits(mask);
|
||||
}
|
||||
} else {
|
||||
// Light is already inactive, no need to play around further...
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void InteriorInstance::updateLightTime(const U32 detail, const U32 lightIndex, const U32 ms)
|
||||
{
|
||||
AssertFatal(bool(mInteriorRes) && detail < mInteriorRes->getNumDetailLevels(), "Error, no interior resource, or out of range detail level");
|
||||
AssertFatal(lightIndex < mInteriorRes->getDetailLevel(detail)->mAnimatedLights.size(), "Error, out of bounds light index");
|
||||
|
||||
LightInfo& rLightInfo = mLightInfo[detail];
|
||||
Interior* pInterior = mInteriorRes->getDetailLevel(detail);
|
||||
|
||||
LightInfo::Light& rLight = rLightInfo.mLights[lightIndex];
|
||||
Interior::AnimatedLight& rILight = pInterior->mAnimatedLights[lightIndex];
|
||||
|
||||
U32 oldState = rLight.curState;
|
||||
ColorI oldColor = rLight.curColor;
|
||||
|
||||
// Ok, now we need to break this down a bit. We pass the update along to
|
||||
// the specialized updating functions based on lightType.
|
||||
switch (rILight.flags & Interior::AnimationTypeMask) {
|
||||
case Interior::AmbientLooping:
|
||||
case Interior::TriggerableLoop:
|
||||
updateLoopingLight(pInterior, rLight, lightIndex, ms);
|
||||
break;
|
||||
|
||||
case Interior::AmbientFlicker:
|
||||
case Interior::TriggerableFlicker:
|
||||
updateFlickerLight(pInterior, rLight, lightIndex, ms);
|
||||
break;
|
||||
|
||||
case Interior::TriggerableRamp:
|
||||
updateRampLight(pInterior, rLight, lightIndex, ms);
|
||||
break;
|
||||
|
||||
default:
|
||||
AssertFatal(false, "Bad light type in updateLightTime");
|
||||
}
|
||||
|
||||
if (rLight.curState != oldState ||
|
||||
rLight.curColor != oldColor) {
|
||||
// Need to reinstall the light
|
||||
installLight(detail, lightIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void InteriorInstance::updateLoopingLight(Interior* interior, LightInfo::Light& light,
|
||||
const U32 lightIndex, const U32 ms)
|
||||
{
|
||||
AssertISV( lightIndex < interior->mAnimatedLights.size( ), "out of bounds array access in InteriorInstance::updateLoopingLight" );
|
||||
Interior::AnimatedLight& rILight = interior->mAnimatedLights[lightIndex];
|
||||
|
||||
light.curTime += ms;
|
||||
light.curTime %= rILight.duration;
|
||||
|
||||
// Find the last state that has a active time below this new time...
|
||||
light.curState = 0;
|
||||
for (U32 i = 1; i < rILight.stateCount; i++) {
|
||||
Interior::LightState& rState = interior->mLightStates[rILight.stateIndex + i];
|
||||
if (rState.activeTime <= light.curTime)
|
||||
light.curState = i;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
// interpolate the color
|
||||
Interior::LightState& rState = interior->mLightStates[rILight.stateIndex + light.curState];
|
||||
Interior::LightState* pNextState;
|
||||
|
||||
U32 msIntoState = light.curTime - rState.activeTime;
|
||||
U32 msTotal;
|
||||
if (light.curState != (rILight.stateCount - 1)) {
|
||||
// Have one more good state
|
||||
pNextState = &interior->mLightStates[rILight.stateIndex + light.curState + 1];
|
||||
msTotal = pNextState->activeTime - rState.activeTime;
|
||||
} else {
|
||||
// Have to interpolate against the first state...
|
||||
pNextState = &interior->mLightStates[rILight.stateIndex];
|
||||
msTotal = rILight.duration - rState.activeTime;
|
||||
}
|
||||
|
||||
F32 interp = F32(msIntoState) / F32(msTotal);
|
||||
F32 red = F32(rState.red) * (1.0f - interp) + F32(pNextState->red) * interp;
|
||||
F32 green = F32(rState.green) * (1.0f - interp) + F32(pNextState->green) * interp;
|
||||
F32 blue = F32(rState.blue) * (1.0f - interp) + F32(pNextState->blue) * interp;
|
||||
|
||||
light.curColor.set(U8(red + 0.5f), U8(green + 0.5f), U8(blue + 0.5f));
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void InteriorInstance::updateFlickerLight(Interior* interior, LightInfo::Light& light,
|
||||
const U32 lightIndex, const U32 ms)
|
||||
{
|
||||
Interior::AnimatedLight& rILight = interior->mAnimatedLights[lightIndex];
|
||||
|
||||
U32 switchPeriod = interior->mLightStates[interior->mAnimatedLights[lightIndex].stateIndex + 1].activeTime;
|
||||
U32 oldTime = light.curTime;
|
||||
light.curTime += ms;
|
||||
if (light.curTime < switchPeriod)
|
||||
return;
|
||||
|
||||
light.curTime = 0;
|
||||
|
||||
// Ok, pick a random number from 0 to the light duration, and find the state that
|
||||
// it falls in.
|
||||
|
||||
static MRandomLCG randomGen;
|
||||
U32 pickedTime = randomGen.randI(0, rILight.duration);
|
||||
|
||||
light.curState = 0;
|
||||
for (U32 i = 1; i < rILight.stateCount; i++) {
|
||||
Interior::LightState& rState = interior->mLightStates[rILight.stateIndex + i];
|
||||
if (rState.activeTime <= pickedTime)
|
||||
light.curState = i;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
Interior::LightState& rState = interior->mLightStates[rILight.stateIndex + light.curState];
|
||||
light.curColor.set(rState.red, rState.green, rState.blue);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void InteriorInstance::updateRampLight(Interior* interior, LightInfo::Light& light,
|
||||
const U32 lightIndex, const U32 ms)
|
||||
{
|
||||
Interior::AnimatedLight& rILight = interior->mAnimatedLights[lightIndex];
|
||||
|
||||
light.curTime += ms;
|
||||
if (light.curTime > rILight.duration)
|
||||
light.curTime = rILight.duration;
|
||||
|
||||
// Find the last state that has a active time below this new time...
|
||||
light.curState = 0;
|
||||
for (U32 i = 1; i < rILight.stateCount; i++) {
|
||||
Interior::LightState& rState = interior->mLightStates[rILight.stateIndex + i];
|
||||
if (rState.activeTime <= light.curTime)
|
||||
light.curState = i;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
// interpolate the color
|
||||
Interior::LightState& rState = interior->mLightStates[rILight.stateIndex + light.curState];
|
||||
Interior::LightState* pNextState;
|
||||
|
||||
U32 msIntoState = light.curTime - rState.activeTime;
|
||||
U32 msTotal;
|
||||
if (light.curState != (rILight.stateCount - 1)) {
|
||||
// Have one more good state
|
||||
pNextState = &interior->mLightStates[rILight.stateIndex + light.curState + 1];
|
||||
msTotal = pNextState->activeTime - rState.activeTime;
|
||||
} else {
|
||||
// A ramp light does NOT NOT NOT interp against the first state
|
||||
pNextState = &rState;
|
||||
msTotal = msIntoState;
|
||||
}
|
||||
|
||||
F32 interp = F32(msIntoState) / F32(msTotal);
|
||||
F32 red = F32(rState.red) * (1.0f - interp) + F32(pNextState->red) * interp;
|
||||
F32 green = F32(rState.green) * (1.0f - interp) + F32(pNextState->green) * interp;
|
||||
F32 blue = F32(rState.blue) * (1.0f - interp) + F32(pNextState->blue) * interp;
|
||||
|
||||
light.curColor.set(U8(red + 0.5f), U8(green + 0.5f), U8(blue + 0.5f));
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void InteriorInstance::installLight(const U32 detail, const U32 lightIndex)
|
||||
{
|
||||
AssertFatal(bool(mInteriorRes) && detail < mInteriorRes->getNumDetailLevels(), "Error, no interior resource, or out of range detail level");
|
||||
AssertFatal(lightIndex < mInteriorRes->getDetailLevel(detail)->mAnimatedLights.size(), "Error, out of bounds light index");
|
||||
|
||||
LightInfo& rLightInfo = mLightInfo[detail];
|
||||
LightInfo::Light& rLight = rLightInfo.mLights[lightIndex];
|
||||
|
||||
// All we are allowed to assume is that the light time, color, and state are
|
||||
// correct here. We must install all statedata, and invalidate all surfaces.
|
||||
// First, let's retrieve the actual light from the Interior
|
||||
//
|
||||
Interior* pInterior = mInteriorRes->getDetailLevel(detail);
|
||||
Interior::AnimatedLight& rILight = pInterior->mAnimatedLights[lightIndex];
|
||||
Interior::LightState& rIState = pInterior->mLightStates[rILight.stateIndex + rLight.curState];
|
||||
|
||||
// Ok. Now, cycle through the light's state data, and install it
|
||||
for (U32 i = rIState.dataIndex; i < (rIState.dataIndex + rIState.dataCount); i++) {
|
||||
Interior::LightStateData& rIData = pInterior->mStateData[i];
|
||||
LightInfo::StateDataInfo& rData = rLightInfo.mStateDataInfo[rIData.lightStateIndex];
|
||||
|
||||
if (rIData.mapIndex != 0xFFFFFFFF) {
|
||||
rData.curMap = &pInterior->mStateDataBuffer[rIData.mapIndex];
|
||||
} else {
|
||||
rData.curMap = NULL;
|
||||
}
|
||||
rData.curColor = rLight.curColor;
|
||||
rData.alarm = (rILight.flags & Interior::AlarmLight) != 0;
|
||||
rLightInfo.mSurfaceInvalid.set(rIData.surfaceIndex);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void InteriorInstance::intensityMapMerge(U8* lightMap,
|
||||
const U32 width,
|
||||
const U32 height,
|
||||
const U8* intensityMap,
|
||||
const ColorI& color)
|
||||
{
|
||||
// lightmap is a 24bit RGB texture, intensitymap is an 8 bit intensity
|
||||
// map. We want lightmap = [lightmap + (intensityMap * color)]
|
||||
|
||||
// DMMFIX: SLOWSLOWSLOW! Need MMX version of this at the very least,
|
||||
// this version is only for clarity;
|
||||
for (U32 y = 0; y < height; y++) {
|
||||
for (U32 x = 0; x < width; x++) {
|
||||
U8* data = &lightMap[(y * width + x) * 3];
|
||||
U32 intensity = intensityMap[(y * width + x)];
|
||||
|
||||
U32 newRed = data[0];
|
||||
U32 newGreen = data[1];
|
||||
U32 newBlue = data[2];
|
||||
|
||||
U32 addRed = (U32(color.red) * intensity + 0x80) >> 8;
|
||||
U32 addGreen = (U32(color.green) * intensity + 0x80) >> 8;
|
||||
U32 addBlue = (U32(color.blue) * intensity + 0x80) >> 8;
|
||||
|
||||
newRed += addRed;
|
||||
newGreen += addGreen;
|
||||
newBlue += addBlue;
|
||||
|
||||
data[0] = (newRed <= 255) ? U8(newRed) : 0xFF;
|
||||
data[1] = (newGreen <= 255) ? U8(newGreen) : 0xFF;
|
||||
data[2] = (newBlue <= 255) ? U8(newBlue) : 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
784
engine/interior/interiorMap.cc
Executable file
784
engine/interior/interiorMap.cc
Executable file
@ -0,0 +1,784 @@
|
||||
#include "interiorMap.h"
|
||||
|
||||
#include "dgl/dgl.h"
|
||||
#include "core/bitStream.h"
|
||||
#include "game/gameConnection.h"
|
||||
#include "math/mathIO.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "collision/concretePolyList.h"
|
||||
#include "dgl/gBitmap.h"
|
||||
#include "math/mPlaneTransformer.h"
|
||||
|
||||
#define FRONTEPSILON 0.00001
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
IMPLEMENT_CO_NETOBJECT_V1(InteriorMap);
|
||||
|
||||
// Return the bounding box transformed into world space
|
||||
Box3F InteriorMapConvex::getBoundingBox() const
|
||||
{
|
||||
return getBoundingBox(mObject->getTransform(), mObject->getScale());
|
||||
}
|
||||
|
||||
// Transform and scale the bounding box by the inputs
|
||||
Box3F InteriorMapConvex::getBoundingBox(const MatrixF& mat, const Point3F& scale) const
|
||||
{
|
||||
Box3F newBox = box;
|
||||
newBox.min.convolve(scale);
|
||||
newBox.max.convolve(scale);
|
||||
mat.mul(newBox);
|
||||
return newBox;
|
||||
}
|
||||
|
||||
// Return the point furthest from the input vector
|
||||
Point3F InteriorMapConvex::support(const VectorF& v) const
|
||||
{
|
||||
Point3F ret(0.0f, 0.0f, 0.0f);
|
||||
F32 dp = 0.0f;
|
||||
F32 tp = 0.0f;
|
||||
|
||||
// Loop through the points and save the furthest one
|
||||
//for (U32 i = 0; i < 8; i++)
|
||||
//{
|
||||
// tp = mDot(v, pOwner->mPoints[i]);
|
||||
|
||||
// if (tp > dp)
|
||||
// {
|
||||
// dp = tp;
|
||||
// ret = pOwner->mPoints[i];
|
||||
// }
|
||||
//}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// This function simply checks to see if the edge already exists on the edgelist
|
||||
// If it doesn't the edge gets added
|
||||
void InteriorMapConvex::addEdge(U32 zero, U32 one, U32 base, ConvexFeature* cf)
|
||||
{
|
||||
U32 newEdge0, newEdge1;
|
||||
|
||||
// Sort the vertex indexes by magnitude (lowest number first, largest second)
|
||||
newEdge0 = getMin(zero, one) + base;
|
||||
newEdge1 = getMax(zero, one) + base;
|
||||
|
||||
// Assume that it isn't found
|
||||
bool found = false;
|
||||
|
||||
// Loop through the edgelist
|
||||
// Start with base so we don't search *all* of the edges if there already are some on the list
|
||||
for (U32 k = base; k < cf->mEdgeList.size(); k++)
|
||||
{
|
||||
// If we find a match flag found and break out (no need to keep searching)
|
||||
if (cf->mEdgeList[k].vertex[0] == newEdge0 && cf->mEdgeList[k].vertex[1] == newEdge1)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't find it then add it
|
||||
// Otherwise we return without doing anything
|
||||
if (!found)
|
||||
{
|
||||
cf->mEdgeList.increment();
|
||||
cf->mEdgeList.last().vertex[0] = newEdge0;
|
||||
cf->mEdgeList.last().vertex[1] = newEdge1;
|
||||
}
|
||||
};
|
||||
|
||||
// Return the vertices, faces, and edges of the convex
|
||||
// Used by the vehicle collisions
|
||||
void InteriorMapConvex::getFeatures(const MatrixF& mat,const VectorF& n, ConvexFeature* cf)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Return list(s) of convex faces
|
||||
// Used by player collisions
|
||||
void InteriorMapConvex::getPolyList(AbstractPolyList* list)
|
||||
{
|
||||
// Be sure to transform the list into model space
|
||||
list->setTransform(&mObject->getTransform(), mObject->getScale());
|
||||
// Set the object
|
||||
list->setObject(mObject);
|
||||
|
||||
// Get the brush
|
||||
ConvexBrush* brush = pOwner->mInteriorRes->mBrushes[brushIndex];
|
||||
|
||||
brush->getPolyList(list);
|
||||
}
|
||||
|
||||
InteriorMap::InteriorMap(void)
|
||||
{
|
||||
// Setup NetObject.
|
||||
// Note that we set this as a TutorialObjectType object
|
||||
// TutorialObjectType is defined in game/objectTypes.h in the SimObjectTypes enum
|
||||
// You should also notify the scripting engine of it existance in game/main.cc in initGame()
|
||||
mTypeMask = StaticObjectType | StaticRenderedObjectType | InteriorMapObjectType;
|
||||
mNetFlags.set(Ghostable);
|
||||
|
||||
// Haven't loaded yet
|
||||
mLoaded = false;
|
||||
|
||||
// Give it a nonexistant bounding box
|
||||
mObjBox.min.set(0, 0, 0);
|
||||
mObjBox.max.set(0, 0, 0);
|
||||
|
||||
mConvexList = new Convex;
|
||||
mTexPath = NULL;
|
||||
mRenderMode = TexShaded;
|
||||
mEnableLights = true;
|
||||
mTexHandles = NULL;
|
||||
}
|
||||
|
||||
InteriorMap::~InteriorMap(void)
|
||||
{
|
||||
delete mConvexList;
|
||||
mConvexList = NULL;
|
||||
}
|
||||
|
||||
void InteriorMap::initPersistFields()
|
||||
{
|
||||
// Initialise parents' persistent fields.
|
||||
Parent::initPersistFields();
|
||||
|
||||
addField( "File", TypeFilename, Offset( mFileName, InteriorMap ) );
|
||||
}
|
||||
|
||||
bool InteriorMap::onAdd()
|
||||
{
|
||||
if(!Parent::onAdd()) return(false);
|
||||
|
||||
// Set our path info
|
||||
setPath(mFileName);
|
||||
|
||||
// Load resource
|
||||
mInteriorRes = ResourceManager->load(mFileName, true);
|
||||
if (bool(mInteriorRes) == false)
|
||||
{
|
||||
Con::errorf(ConsoleLogEntry::General, "Unable to load interior: %s", mFileName);
|
||||
NetConnection::setLastError("Unable to load interior: %s", mFileName);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
mLoaded = true;
|
||||
|
||||
// Scale our brushes
|
||||
if (mInteriorRes->mBrushScale != 1.0f)
|
||||
{
|
||||
for (U32 i = 0; i < mInteriorRes->mBrushes.size(); i++)
|
||||
mInteriorRes->mBrushes[i]->setScale(mInteriorRes->mBrushScale);
|
||||
}
|
||||
|
||||
loadTextures();
|
||||
|
||||
mInteriorRes->mTexGensCalced = calcTexgenDiv();
|
||||
|
||||
// Set the bounds
|
||||
mObjBox.min.set(1e10, 1e10, 1e10);
|
||||
mObjBox.max.set(-1e10, -1e10, -1e10);
|
||||
|
||||
for (U32 i = 0; i < mInteriorRes->mBrushes.size(); i++)
|
||||
{
|
||||
if (mInteriorRes->mBrushes[i]->mStatus == ConvexBrush::Good)
|
||||
{
|
||||
// Transform the bounding boxes
|
||||
MatrixF& mat = mInteriorRes->mBrushes[i]->mTransform;
|
||||
Point3F& scale = mInteriorRes->mBrushes[i]->mScale;
|
||||
|
||||
Point3F min = mInteriorRes->mBrushes[i]->mBounds.min;
|
||||
Point3F max = mInteriorRes->mBrushes[i]->mBounds.max;
|
||||
|
||||
mat.mulP(min);
|
||||
mat.mulP(max);
|
||||
|
||||
min.convolveInverse(scale);
|
||||
max.convolveInverse(scale);
|
||||
|
||||
mObjBox.min.setMin(min);
|
||||
mObjBox.max.setMax(max);
|
||||
}
|
||||
}
|
||||
|
||||
mWhite = new TextureHandle("common/lighting/whiteAlpha255", MeshTexture);
|
||||
|
||||
// Reset the World Box.
|
||||
resetWorldBox();
|
||||
// Set the Render Transform.
|
||||
setRenderTransform(mObjToWorld);
|
||||
|
||||
// Add to Scene.
|
||||
addToScene();
|
||||
|
||||
// Return OK.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InteriorMap::setPath(const char* filename)
|
||||
{
|
||||
// Save our filename just in case it hasn't already been done
|
||||
mFileName = StringTable->insert(filename);
|
||||
|
||||
// Get the directory
|
||||
char dir[4096]; // FIXME: no hardcoded lengths
|
||||
if (dStrrchr(filename, '/'))
|
||||
{
|
||||
dStrncpy(dir, filename, (int)(dStrrchr(filename, '/') - filename + 1));
|
||||
dir[(int)(dStrrchr(filename, '/') - filename + 1)] = 0;
|
||||
}
|
||||
else if (dStrrchr(filename, '\\'))
|
||||
{
|
||||
dStrncpy(dir, filename, (int)(dStrrchr(filename, '\\') - filename + 1));
|
||||
dir[(int)(dStrrchr(filename, '\\') - filename + 1)] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
dSprintf(dir, dStrlen(Platform::getWorkingDirectory()) + 1, "%s/\0", Platform::getWorkingDirectory());
|
||||
}
|
||||
|
||||
mFilePath = StringTable->insert(dir);
|
||||
if (!mTexPath)
|
||||
mTexPath = mFilePath;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InteriorMap::loadTextures()
|
||||
{
|
||||
if (mTexHandles)
|
||||
return true;
|
||||
|
||||
// Load our textures
|
||||
mTexHandles = new TextureHandle[mInteriorRes->mMaterials.size()];
|
||||
|
||||
for (int t = 0; t < mInteriorRes->mMaterials.size(); t++)
|
||||
{
|
||||
mTexHandles[t] = NULL;
|
||||
|
||||
char fullname[8192];
|
||||
|
||||
// First go for standard
|
||||
dSprintf(fullname, 8192, "%s%s\0", mTexPath, mInteriorRes->mMaterials[t]);
|
||||
|
||||
mTexHandles[t] = TextureHandle(fullname, MeshTexture);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InteriorMap::calcTexgenDiv()
|
||||
{
|
||||
// If we have already calculated our texgen scale then we don't need to do it again
|
||||
// This occurs when the client and server are on the same machine (they share Resources)
|
||||
if (mInteriorRes->mTexGensCalced)
|
||||
return true;
|
||||
|
||||
if (mInteriorRes->mBrushFormat != InteriorMapResource::QuakeOld && mInteriorRes->mBrushFormat != InteriorMapResource::Valve220)
|
||||
return false;
|
||||
|
||||
for (U32 i = 0; i < mInteriorRes->mMaterials.size(); i++)
|
||||
{
|
||||
F32 width = 16.0f;
|
||||
F32 height = 16.0f;
|
||||
|
||||
if (mTexHandles[i].getWidth() != 0UL)
|
||||
{
|
||||
width = mTexHandles[i].getWidth();
|
||||
height = mTexHandles[i].getHeight();
|
||||
}
|
||||
|
||||
for (U32 j = 0; j < mInteriorRes->mBrushes.size(); j++)
|
||||
{
|
||||
for (U32 k = 0; k < mInteriorRes->mBrushes[j]->mFaces.mPolyList.size(); k++)
|
||||
{
|
||||
if (i == mInteriorRes->mBrushes[j]->mFaces.mPolyList[k].material)
|
||||
{
|
||||
mInteriorRes->mBrushes[j]->mTexInfos[k].texDiv[0] = width;
|
||||
mInteriorRes->mBrushes[j]->mTexInfos[k].texDiv[1] = height;
|
||||
|
||||
mInteriorRes->mBrushes[j]->mTexInfos[k].texGens[0].x /= width;
|
||||
mInteriorRes->mBrushes[j]->mTexInfos[k].texGens[0].y /= width;
|
||||
mInteriorRes->mBrushes[j]->mTexInfos[k].texGens[0].z /= width;
|
||||
mInteriorRes->mBrushes[j]->mTexInfos[k].texGens[0].d /= width;
|
||||
|
||||
mInteriorRes->mBrushes[j]->mTexInfos[k].texGens[1].x /= height;
|
||||
mInteriorRes->mBrushes[j]->mTexInfos[k].texGens[1].y /= height;
|
||||
mInteriorRes->mBrushes[j]->mTexInfos[k].texGens[1].z /= height;
|
||||
mInteriorRes->mBrushes[j]->mTexInfos[k].texGens[1].d /= height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MDFFIX: Probably should move this to its own function
|
||||
// Scale the texgens by the brushscale
|
||||
for (U32 j = 0; j < mInteriorRes->mBrushes.size(); j++)
|
||||
{
|
||||
for (U32 k = 0; k < mInteriorRes->mBrushes[j]->mFaces.mPolyList.size(); k++)
|
||||
{
|
||||
mInteriorRes->mBrushes[j]->mTexInfos[k].texGens[0] *= mInteriorRes->mBrushScale;
|
||||
mInteriorRes->mBrushes[j]->mTexInfos[k].texGens[1] *= mInteriorRes->mBrushScale;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void InteriorMap::onRemove()
|
||||
{
|
||||
mConvexList->nukeList();
|
||||
|
||||
// Remove from Scene.
|
||||
removeFromScene();
|
||||
|
||||
// Do Parent.
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
void InteriorMap::inspectPostApply()
|
||||
{
|
||||
// Set Parent.
|
||||
Parent::inspectPostApply();
|
||||
|
||||
// Set Move Mask.
|
||||
setMaskBits(MoveMask);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void InteriorMap::onEditorEnable()
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void InteriorMap::onEditorDisable()
|
||||
{
|
||||
}
|
||||
|
||||
bool InteriorMap::prepRenderImage( SceneState* state, const U32 stateKey, const U32 startZone,
|
||||
const bool modifyBaseZoneState)
|
||||
{
|
||||
// Return if last state.
|
||||
if (isLastState(state, stateKey)) return false;
|
||||
// Set Last State.
|
||||
setLastState(state, stateKey);
|
||||
|
||||
// Is Object Rendered?
|
||||
if (state->isObjectRendered(this))
|
||||
{
|
||||
// Yes, so get a SceneRenderImage.
|
||||
SceneRenderImage* image = new SceneRenderImage;
|
||||
// Populate it.
|
||||
image->obj = this;
|
||||
image->isTranslucent = false;
|
||||
image->sortType = SceneRenderImage::Normal;
|
||||
|
||||
// Insert it into the scene images.
|
||||
state->insertRenderImage(image);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void InteriorMap::renderObject(SceneState* state, SceneRenderImage*)
|
||||
{
|
||||
// Check we are in Canonical State.
|
||||
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on entry");
|
||||
|
||||
// Save state.
|
||||
RectI viewport;
|
||||
|
||||
if (mEnableLights && mRenderMode != BrushColors && mRenderMode != FaceColors && mRenderMode != BspPolys && mRenderMode != CollisionHulls)
|
||||
{
|
||||
ColorF oneColor(1,1,1,1);
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, oneColor);
|
||||
//gClientSceneGraph->getLightManager()->sgSetupLights();
|
||||
}
|
||||
|
||||
// Save Projection Matrix so we can restore Canonical state at exit.
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
|
||||
// Save Viewport so we can restore Canonical state at exit.
|
||||
dglGetViewport(&viewport);
|
||||
|
||||
// Setup the projection to the current frustum.
|
||||
//
|
||||
// NOTE:- You should let the SceneGraph drive the frustum as it
|
||||
// determines portal clipping etc.
|
||||
// It also leaves us with the MODELVIEW current.
|
||||
//
|
||||
state->setupBaseProjection();
|
||||
|
||||
// Save ModelView Matrix so we can restore Canonical state at exit.
|
||||
glPushMatrix();
|
||||
|
||||
// Transform by the objects' transform e.g move it.
|
||||
dglMultMatrix(&getTransform());
|
||||
|
||||
glScalef(mObjScale.x, mObjScale.y, mObjScale.z);
|
||||
|
||||
// I separated out the actual render function to make this a little cleaner
|
||||
if (mRenderMode != Edges && mRenderMode != BspPolys && mRenderMode != CollisionHulls)
|
||||
render();
|
||||
|
||||
//if (mEnableLights && mRenderMode != BrushColors && mRenderMode != FaceColors && mRenderMode != BspPolys && mRenderMode != CollisionHulls)
|
||||
// gClientSceneGraph->getLightManager()->sgResetLights();
|
||||
|
||||
// Restore our canonical matrix state.
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
// Restore our canonical viewport state.
|
||||
dglSetViewport(viewport);
|
||||
|
||||
// Check we have restored Canonical State.
|
||||
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on exit");
|
||||
}
|
||||
|
||||
bool InteriorMap::render(void)
|
||||
{
|
||||
gRandGen.setSeed(1978);
|
||||
|
||||
//glEnable(GL_CULL_FACE);
|
||||
|
||||
ColorF oneColor;
|
||||
|
||||
if (mRenderMode == TexShaded || mRenderMode == TexWireframe ||
|
||||
mRenderMode == Lighting || mRenderMode == TexLighting)
|
||||
{
|
||||
glActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, mWhite->getGLName());
|
||||
|
||||
if(mRenderMode == Lighting || mRenderMode == TexLighting)
|
||||
{
|
||||
glActiveTextureARB(GL_TEXTURE1_ARB);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, mWhite->getGLName());
|
||||
|
||||
if(mRenderMode == TexLighting)
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
else
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
|
||||
glActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
}
|
||||
else
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
}
|
||||
|
||||
S32 bound = -2;
|
||||
|
||||
for (U32 i = 0; i < mInteriorRes->mBrushes.size(); i++)
|
||||
{
|
||||
if (mInteriorRes->mBrushes[i]->mType == InteriorMapResource::Portal || mInteriorRes->mBrushes[i]->mType == InteriorMapResource::Trigger)
|
||||
continue;
|
||||
|
||||
if (mInteriorRes->mBrushes[i]->mStatus == ConvexBrush::Deleted)
|
||||
continue;
|
||||
|
||||
if (mRenderMode == BrushColors)
|
||||
{
|
||||
//oneColor = ColorF(gRandGen.randF(0.0f, 1.0f), gRandGen.randF(0.0f, 1.0f), gRandGen.randF(0.0f, 1.0f), 1.0f);
|
||||
//glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, oneColor);
|
||||
glColor4f(gRandGen.randF(0.0f, 1.0f), gRandGen.randF(0.0f, 1.0f), gRandGen.randF(0.0f, 1.0f), 1.0f);
|
||||
}
|
||||
|
||||
// Save ModelView Matrix so we can restore Canonical state at exit.
|
||||
glPushMatrix();
|
||||
|
||||
// Transform by the objects' transform e.g move it.
|
||||
dglMultMatrix(&mInteriorRes->mBrushes[i]->mTransform);
|
||||
|
||||
// Scale
|
||||
//glScalef(mInteriorRes->mBrushes[i]->mScale.x, mInteriorRes->mBrushes[i]->mScale.y, mInteriorRes->mBrushes[i]->mScale.z);
|
||||
|
||||
for (U32 j = 0; j < mInteriorRes->mBrushes[i]->mFaces.mPolyList.size(); j++)
|
||||
{
|
||||
S32 tx = mInteriorRes->mBrushes[i]->mFaces.mPolyList[j].material;
|
||||
|
||||
if (tx == -2)
|
||||
continue;
|
||||
|
||||
if (mRenderMode == TexShaded || mRenderMode == TexWireframe ||
|
||||
mRenderMode == TexLighting)
|
||||
{
|
||||
if (tx != bound)
|
||||
{
|
||||
// Really cheesy way to see if I have a TextureObject
|
||||
if (mTexHandles[tx].getWidth() != 0UL)
|
||||
{
|
||||
glActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
glBindTexture(GL_TEXTURE_2D, mTexHandles[tx].getGLName());
|
||||
bound = tx;
|
||||
}
|
||||
else
|
||||
{
|
||||
glActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
glBindTexture(GL_TEXTURE_2D, mWhite->getGLName());
|
||||
bound = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mRenderMode == FaceColors)
|
||||
{
|
||||
//oneColor = ColorF(gRandGen.randF(0.0f, 1.0f), gRandGen.randF(0.0f, 1.0f), gRandGen.randF(0.0f, 1.0f), 1.0f);
|
||||
//glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, oneColor);
|
||||
glColor4f(gRandGen.randF(0.0f, 1.0f), gRandGen.randF(0.0f, 1.0f), gRandGen.randF(0.0f, 1.0f), 1.0f);
|
||||
}
|
||||
|
||||
mInteriorRes->mBrushes[i]->renderFace(j, (mRenderMode == Lighting || mRenderMode == TexLighting));
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
if (mRenderMode == TexShaded || mRenderMode == TexWireframe ||
|
||||
mRenderMode == Lighting || mRenderMode == TexLighting)
|
||||
{
|
||||
glActiveTextureARB(GL_TEXTURE1_ARB);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
glActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
//glDisable(GL_CULL_FACE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
U32 InteriorMap::packUpdate(NetConnection * con, U32 mask, BitStream * stream)
|
||||
{
|
||||
// Pack Parent.
|
||||
U32 retMask = Parent::packUpdate(con, mask, stream);
|
||||
|
||||
// Write fxPortal Mask Flag.
|
||||
if (stream->writeFlag(mask & MoveMask))
|
||||
{
|
||||
// Write Object Transform.
|
||||
stream->writeAffineTransform(mObjToWorld);
|
||||
|
||||
// Write Object Scale.
|
||||
mathWrite(*stream, mObjScale);
|
||||
|
||||
// Write the file name
|
||||
stream->writeString(mFileName);
|
||||
}
|
||||
|
||||
if (stream->writeFlag(mask & RenderModeMask))
|
||||
stream->write(mRenderMode);
|
||||
|
||||
// Were done ...
|
||||
return(retMask);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void InteriorMap::unpackUpdate(NetConnection * con, BitStream * stream)
|
||||
{
|
||||
// Unpack Parent.
|
||||
Parent::unpackUpdate(con, stream);
|
||||
|
||||
// Read fxPortal Mask Flag.
|
||||
if (stream->readFlag())
|
||||
{
|
||||
MatrixF ObjectMatrix;
|
||||
Point3F scale;
|
||||
|
||||
// Read Object Transform.
|
||||
stream->readAffineTransform(&ObjectMatrix);
|
||||
// Set Transform.
|
||||
setTransform(ObjectMatrix);
|
||||
|
||||
// Read Object Scale
|
||||
mathRead(*stream, &scale);
|
||||
// Set Scale
|
||||
setScale(scale);
|
||||
|
||||
// Reset the World Box.
|
||||
resetWorldBox();
|
||||
// Set the Render Transform.
|
||||
setRenderTransform(mObjToWorld);
|
||||
|
||||
// Read the file name
|
||||
mFileName = stream->readSTString();
|
||||
}
|
||||
|
||||
// New RenderMode?
|
||||
if (stream->readFlag())
|
||||
stream->read(&mRenderMode);
|
||||
}
|
||||
|
||||
void InteriorMap::buildConvex(const Box3F& box, Convex* convex)
|
||||
{
|
||||
Box3F realBox = box;
|
||||
mWorldToObj.mul(realBox);
|
||||
realBox.min.convolveInverse(mObjScale);
|
||||
realBox.max.convolveInverse(mObjScale);
|
||||
|
||||
mConvexList->collectGarbage();
|
||||
|
||||
for (U32 i = 0; i < mInteriorRes->mBrushes.size(); i++)
|
||||
{
|
||||
if (mInteriorRes->mBrushes[i]->mType == InteriorMapResource::Portal || mInteriorRes->mBrushes[i]->mType == InteriorMapResource::Trigger)
|
||||
continue;
|
||||
|
||||
if (mInteriorRes->mBrushes[i]->mStatus == ConvexBrush::Deleted)
|
||||
continue;
|
||||
|
||||
ConvexBrush* brush = mInteriorRes->mBrushes[i];
|
||||
|
||||
if (realBox.isOverlapped(brush->mBounds))
|
||||
{
|
||||
// See if this brush exists in the working set already...
|
||||
Convex* cc = 0;
|
||||
CollisionWorkingList& wl = convex->getWorkingList();
|
||||
|
||||
for (CollisionWorkingList* itr = wl.wLink.mNext; itr != &wl; itr = itr->wLink.mNext)
|
||||
{
|
||||
if (itr->mConvex->getType() == InteriorMapConvexType &&
|
||||
(static_cast<InteriorMapConvex*>(itr->mConvex)->getObject() == this &&
|
||||
static_cast<InteriorMapConvex*>(itr->mConvex)->brushIndex == i))
|
||||
{
|
||||
cc = itr->mConvex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cc)
|
||||
{
|
||||
// Got ourselves a new convex
|
||||
InteriorMapConvex* cp = new InteriorMapConvex;
|
||||
mConvexList->registerObject(cp);
|
||||
convex->addToWorkingList(cp);
|
||||
cp->mObject = this;
|
||||
cp->pOwner = this;
|
||||
cp->brushIndex = i;
|
||||
cp->box = brush->mBounds;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool InteriorMap::castRay(const Point3F& s, const Point3F& e, RayInfo* info)
|
||||
{
|
||||
// This assumes that the collision hulls are convex...otherwise it can return unpredictable results
|
||||
F32 outputFraction = 1.0f;
|
||||
VectorF outputNormal;
|
||||
|
||||
// Loop through the collision hulls checking for the nearest ray collision
|
||||
// MDFFIX: Again I really should have the collision hulls sorted into a bsp
|
||||
for (U32 i = 0; i < mInteriorRes->mBrushes.size(); i++)
|
||||
{
|
||||
if (mInteriorRes->mBrushes[i]->mStatus == ConvexBrush::Deleted)
|
||||
continue;
|
||||
|
||||
RayInfo test;
|
||||
|
||||
if (mInteriorRes->mBrushes[i]->castRay(s, e, &test))
|
||||
{
|
||||
if (test.t < outputFraction)
|
||||
{
|
||||
outputFraction = test.t;
|
||||
outputNormal = test.normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we had a collision fill in the info structure and return
|
||||
if (outputFraction >= 0.0f && outputFraction < 1.0f)
|
||||
{
|
||||
info->t = outputFraction;
|
||||
info->normal = outputNormal;
|
||||
info->point.interpolate(s, e, outputFraction);
|
||||
info->face = -1;
|
||||
info->object = this;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise we didn't collide
|
||||
return false;
|
||||
}
|
||||
|
||||
void InteriorMap::removeBrush(S32 brushIndex)
|
||||
{
|
||||
if (brushIndex < 0 || brushIndex >= mInteriorRes->mBrushes.size())
|
||||
return;
|
||||
|
||||
// Grab an iterator and point it at the beginning of the VectorPtr
|
||||
VectorPtr<ConvexBrush*>::iterator cbitr = mInteriorRes->mBrushes.begin();
|
||||
|
||||
// Move the pointer up to our brush
|
||||
cbitr += brushIndex;
|
||||
|
||||
// And remove it
|
||||
delete *cbitr;
|
||||
mInteriorRes->mBrushes.erase(cbitr);
|
||||
}
|
||||
|
||||
S32 InteriorMap::getBrushIndex(U32 brushID)
|
||||
{
|
||||
for (U32 i = 0; i < mInteriorRes->mBrushes.size(); i++)
|
||||
{
|
||||
if (mInteriorRes->mBrushes[i]->mID == brushID)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//****************************************************************************
|
||||
// Map Texture Management
|
||||
//****************************************************************************
|
||||
|
||||
// Returns the number of textures used in the map
|
||||
S32 InteriorMap::getTextureCount()
|
||||
{
|
||||
if(mInteriorRes)
|
||||
return mInteriorRes->mMaterials.size();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Returns the name of the texture given the texture's index
|
||||
const char* InteriorMap::getTextureName(S32 index)
|
||||
{
|
||||
S32 count = getTextureCount();
|
||||
if(index >= 0 && index < count)
|
||||
{
|
||||
if(mInteriorRes)
|
||||
return ((const char*) mInteriorRes->getTextureName(index));
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
// Returns the texture for the map
|
||||
const char* InteriorMap::getTexturePathway()
|
||||
{
|
||||
return ((const char*) mTexPath);
|
||||
}
|
||||
|
||||
// Returns the requested texture's dimensions
|
||||
Point2I InteriorMap::getTextureSize(S32 index)
|
||||
{
|
||||
S32 count = getTextureCount();
|
||||
if(index >= 0 && index < count)
|
||||
{
|
||||
if(mTexHandles[index])
|
||||
return Point2I(mTexHandles[index].getWidth(), mTexHandles[index].getHeight());
|
||||
}
|
||||
|
||||
return Point2I(0,0);
|
||||
}
|
196
engine/interior/interiorMap.h
Executable file
196
engine/interior/interiorMap.h
Executable file
@ -0,0 +1,196 @@
|
||||
#ifndef _INTERIORMAP_H_
|
||||
#define _INTERIORMAP_H_
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "sim/sceneObject.h"
|
||||
#include "collision/convex.h"
|
||||
#include "dgl/gTexManager.h"
|
||||
#include "core/tokenizer.h"
|
||||
#include "collision/convexBrush.h"
|
||||
#include "collision/abstractPolyList.h"
|
||||
#include "interior/interiorMapRes.h"
|
||||
|
||||
// Pre-define the InteriorMap class so that we can reference it in InteriorMapConvex
|
||||
class InteriorMap;
|
||||
|
||||
// This is the convex collision implementation for InteriorMap
|
||||
// Once something has collided against a InteriorMap then it creates one of
|
||||
// these for the actual collisions to occur against
|
||||
class InteriorMapConvex : public Convex
|
||||
{
|
||||
typedef Convex Parent;
|
||||
friend class InteriorMap; // So the "owner" object can set some properties when it creates this
|
||||
|
||||
public:
|
||||
// This is where you set the convex type
|
||||
// Needs to be defined in convex.h in the ConvexType enum
|
||||
InteriorMapConvex() { mType = InteriorMapConvexType; };
|
||||
~InteriorMapConvex() {};
|
||||
|
||||
protected:
|
||||
Box3F box; // The bounding box of the convex (in object space)
|
||||
InteriorMap* pOwner; // A pointer back to the "owner" object so we can reference the vertices
|
||||
|
||||
U32 nodeIndex;
|
||||
S32 brushIndex;
|
||||
|
||||
public:
|
||||
// Return the bounding box transformed into world space
|
||||
Box3F getBoundingBox() const;
|
||||
// Return the bounding box transformed and scaled by the input values
|
||||
Box3F getBoundingBox(const MatrixF& mat, const Point3F& scale) const;
|
||||
|
||||
// This returns a list of convex faces to collide against
|
||||
void getPolyList(AbstractPolyList* list);
|
||||
|
||||
// Returns the vertices, faces, and edges of our convex
|
||||
void getFeatures(const MatrixF& mat,const VectorF& n, ConvexFeature* cf);
|
||||
|
||||
// This returns the furthest point from the input vector
|
||||
Point3F support(const VectorF& v) const;
|
||||
|
||||
// A helper function that checks the edgelist for duplicates
|
||||
void addEdge(U32 zero, U32 one, U32 base, ConvexFeature* cf);
|
||||
};
|
||||
|
||||
class InteriorMap : public SceneObject
|
||||
{
|
||||
friend class InteriorMapConvex; // So the "child" convex(es) can reference the vertices
|
||||
|
||||
public:
|
||||
typedef SceneObject Parent;
|
||||
|
||||
// Declare Console Object.
|
||||
DECLARE_CONOBJECT(InteriorMap);
|
||||
protected:
|
||||
|
||||
// Create and use these to specify custom events.
|
||||
//
|
||||
// NOTE:- Using these allows you to group the changes into related
|
||||
// events. No need to change everything if something minor
|
||||
// changes. Only really important if you have *lots* of these
|
||||
// objects at start-up or you send alot of changes whilst the
|
||||
// game is in progress.
|
||||
//
|
||||
// Use "setMaskBits(InteriorMapMask)" to signal.
|
||||
// - Melv May
|
||||
|
||||
enum
|
||||
{
|
||||
MoveMask = (1 << 0),
|
||||
RenderModeMask = (1 << 1)
|
||||
};
|
||||
|
||||
bool mLoaded; // Make sure we don't load this twice
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
TexShaded = 0,
|
||||
SolidShaded,
|
||||
TexWireframe,
|
||||
SolidWireframe,
|
||||
Edges,
|
||||
BrushColors,
|
||||
FaceColors,
|
||||
BspPolys,
|
||||
CollisionHulls,
|
||||
Lighting,
|
||||
TexLighting
|
||||
};
|
||||
|
||||
TextureHandle* mTexHandles;
|
||||
|
||||
TextureHandle* mWhite;
|
||||
|
||||
StringTableEntry mFileName; // The name of the level
|
||||
StringTableEntry mFilePath; // The path of the level
|
||||
StringTableEntry mTexPath; // The path to the textures
|
||||
|
||||
U32 mRenderMode;
|
||||
bool mEnableLights;
|
||||
|
||||
Resource<InteriorMapResource> mInteriorRes;
|
||||
|
||||
InteriorMapResource::Entity* getEntity(char* classname)
|
||||
{
|
||||
for (U32 i = 0; i < mInteriorRes->mEntities.size(); i++)
|
||||
{
|
||||
if (dStricmp(classname, mInteriorRes->mEntities[i]->classname) == 0)
|
||||
return mInteriorRes->mEntities[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void getEntities(char* classname, VectorPtr<InteriorMapResource::Entity*> ents)
|
||||
{
|
||||
for (U32 i = 0; i < mInteriorRes->mEntities.size(); i++)
|
||||
{
|
||||
if (dStricmp(classname, mInteriorRes->mEntities[i]->classname) == 0)
|
||||
{
|
||||
ents.increment();
|
||||
ents.last() = mInteriorRes->mEntities[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
Convex* mConvexList;
|
||||
|
||||
// I split the render and load functions out of renderObject() and onAdd() for clarity
|
||||
bool render(void);
|
||||
|
||||
public:
|
||||
// Creation and destruction
|
||||
InteriorMap(void);
|
||||
virtual ~InteriorMap(void);
|
||||
|
||||
// Utility
|
||||
bool setPath(const char* filename);
|
||||
bool loadTextures();
|
||||
bool calcTexgenDiv();
|
||||
|
||||
// SceneObject
|
||||
// renderObject() is the function that gets called for evey SceneObject
|
||||
void renderObject(SceneState*, SceneRenderImage*);
|
||||
|
||||
// This function gets called to let you define a few proprties like translucency
|
||||
virtual bool prepRenderImage(SceneState*, const U32 stateKey, const U32 startZone,
|
||||
const bool modifyBaseZoneState = false);
|
||||
|
||||
// SimObject
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
void onEditorEnable();
|
||||
void onEditorDisable();
|
||||
void inspectPostApply();
|
||||
|
||||
// NetObject
|
||||
U32 packUpdate(NetConnection *, U32, BitStream *);
|
||||
void unpackUpdate(NetConnection *, BitStream *);
|
||||
|
||||
// ConObject.
|
||||
static void initPersistFields();
|
||||
|
||||
// Collision
|
||||
// castRay() returns the percentage along the line from a starting and an ending point
|
||||
// to where something collides with the object
|
||||
bool castRay(const Point3F&, const Point3F&, RayInfo*);
|
||||
|
||||
// Called whenever something overlaps our bounding box
|
||||
// This is where the SceneObject can submit convexes to the working list of an object interested in collision data
|
||||
void buildConvex(const Box3F& box, Convex* convex);
|
||||
|
||||
// Script access functions
|
||||
void removeBrush(S32 brushIndex); // Removes brush from mBrushes and deletes it from memory
|
||||
|
||||
S32 getTextureCount(); // Returns the number of textures used in the map
|
||||
const char* getTextureName(S32 index); // Returns the name of the texture given the texture's index
|
||||
const char* getTexturePathway(); // Returns the texture for the map
|
||||
Point2I getTextureSize(S32 index); // Returns the requested texture's dimensions
|
||||
|
||||
S32 getBrushIndex(U32 brushID);
|
||||
};
|
||||
|
||||
#endif
|
1034
engine/interior/interiorMapRes.cc
Executable file
1034
engine/interior/interiorMapRes.cc
Executable file
File diff suppressed because it is too large
Load Diff
123
engine/interior/interiorMapRes.h
Executable file
123
engine/interior/interiorMapRes.h
Executable file
@ -0,0 +1,123 @@
|
||||
#ifndef _INTERIORMAPRES_H_
|
||||
#define _INTERIORMAPRES_H_
|
||||
|
||||
#ifndef _RESMANAGER_H_
|
||||
#include "core/resManager.h"
|
||||
#endif
|
||||
|
||||
#include "core/tokenizer.h"
|
||||
#include "dgl/gTexManager.h"
|
||||
#include "dgl/materialList.h"
|
||||
#include "math/mPlane.h"
|
||||
|
||||
class InteriorMap;
|
||||
class ConvexBrush;
|
||||
|
||||
extern ResourceInstance* constructInteriorMAP(Stream& stream);
|
||||
|
||||
class InteriorMapResource : public ResourceInstance
|
||||
{
|
||||
typedef ResourceInstance Parent;
|
||||
|
||||
public:
|
||||
// Enums
|
||||
enum BrushType
|
||||
{
|
||||
Structural = 0,
|
||||
Detail = 1,
|
||||
Collision = 2,
|
||||
Portal = 3,
|
||||
Trigger = 4
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
Unknown = 0,
|
||||
Valve220 = 1,
|
||||
QuakeOld = 2,
|
||||
QuakeNew = 3
|
||||
};
|
||||
|
||||
// Structs
|
||||
struct Property
|
||||
{
|
||||
StringTableEntry name;
|
||||
StringTableEntry value;
|
||||
};
|
||||
|
||||
// Supporting classes
|
||||
class Entity
|
||||
{
|
||||
public:
|
||||
StringTableEntry classname;
|
||||
Vector<Property> properties;
|
||||
|
||||
Entity() {};
|
||||
~Entity() {};
|
||||
|
||||
char* getValue(char* property)
|
||||
{
|
||||
for (U32 i = 0; i < properties.size(); i++)
|
||||
{
|
||||
if (dStricmp(property, properties[i].name) == 0)
|
||||
return (char*)properties[i].value;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
// Data
|
||||
StringTableEntry mFileName; // The name of the level
|
||||
StringTableEntry mFilePath; // The path of the level
|
||||
StringTableEntry mTexPath; // The texture path
|
||||
|
||||
VectorPtr<Entity*> mEntities;
|
||||
Vector<StringTableEntry> mMaterials;
|
||||
|
||||
VectorPtr<ConvexBrush*> mBrushes;
|
||||
|
||||
U32 mBrushFormat;
|
||||
F32 mBrushScale;
|
||||
bool mTexGensCalced;
|
||||
|
||||
U32 mNextBrushID;
|
||||
|
||||
Entity* mWorldSpawn;
|
||||
|
||||
public:
|
||||
InteriorMapResource();
|
||||
~InteriorMapResource();
|
||||
|
||||
// I/O
|
||||
bool load(const char* filename);
|
||||
bool read(Stream& stream);
|
||||
bool write(Stream& stream);
|
||||
bool writeBrush(U32 brushIndex, Stream& stream);
|
||||
|
||||
// Parsing
|
||||
bool parseMap(Tokenizer* toker);
|
||||
bool parseEntity(Tokenizer* toker);
|
||||
bool parsePatch(Tokenizer* toker);
|
||||
bool parseBrush(Tokenizer* toker, BrushType type);
|
||||
bool parsePlane(Tokenizer* toker);
|
||||
bool parseQuakeValve(Tokenizer* toker, VectorF normal, U32& tdx, PlaneF* texGens, F32* scale);
|
||||
bool parseQuakeNew(Tokenizer* toker, U32& tdx, PlaneF* texGens, F32* scale);
|
||||
bool parseValve220TexGens(Tokenizer* toker, PlaneF* texGens, F32* scale);
|
||||
bool parseQuakeTexGens(Tokenizer* toker, VectorF normal, PlaneF* texGens, F32* scale);
|
||||
|
||||
// Texture manager
|
||||
U32 addTexture(char* texture);
|
||||
U32 getTextureSize(char* texture, F32* texSizes);
|
||||
bool getTextureSize(U32 texIdx, F32* texSizes);
|
||||
S32 getTextureIndex(char* texture);
|
||||
char* getTextureName(U32 texIdx);
|
||||
|
||||
// Utility
|
||||
bool validatePlane(const Point3F &k, const Point3F &j, const Point3F &l);
|
||||
|
||||
// Returns the next valid ID and increments mNextBrushID
|
||||
U32 getNextBrushID() { mNextBrushID++; return mNextBrushID - 1; };
|
||||
};
|
||||
|
||||
#endif
|
1724
engine/interior/interiorRender.cc
Executable file
1724
engine/interior/interiorRender.cc
Executable file
File diff suppressed because it is too large
Load Diff
320
engine/interior/interiorRes.cc
Executable file
320
engine/interior/interiorRes.cc
Executable file
@ -0,0 +1,320 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/console.h"
|
||||
#include "core/stream.h"
|
||||
#include "interior/interior.h"
|
||||
#include "interior/interiorResObjects.h"
|
||||
#include "dgl/gBitmap.h"
|
||||
#include "interior/forceField.h"
|
||||
|
||||
#include "interior/interiorRes.h"
|
||||
|
||||
const U32 InteriorResource::smFileVersion = 44;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
InteriorResource::InteriorResource()
|
||||
{
|
||||
VECTOR_SET_ASSOCIATION(mDetailLevels);
|
||||
VECTOR_SET_ASSOCIATION(mSubObjects);
|
||||
VECTOR_SET_ASSOCIATION(mTriggers);
|
||||
VECTOR_SET_ASSOCIATION(mInteriorPathFollowers);
|
||||
VECTOR_SET_ASSOCIATION(mForceFields);
|
||||
VECTOR_SET_ASSOCIATION(mAISpecialNodes);
|
||||
|
||||
mPreviewBitmap = NULL;
|
||||
}
|
||||
|
||||
InteriorResource::~InteriorResource()
|
||||
{
|
||||
U32 i;
|
||||
|
||||
for (i = 0; i < mDetailLevels.size(); i++)
|
||||
delete mDetailLevels[i];
|
||||
for (i = 0; i < mSubObjects.size(); i++)
|
||||
delete mSubObjects[i];
|
||||
for (i = 0; i < mTriggers.size(); i++)
|
||||
delete mTriggers[i];
|
||||
for (i = 0; i < mInteriorPathFollowers.size(); i++)
|
||||
delete mInteriorPathFollowers[i];
|
||||
for (i = 0; i < mForceFields.size(); i++)
|
||||
delete mForceFields[i];
|
||||
for (i = 0; i < mAISpecialNodes.size(); i++)
|
||||
delete mAISpecialNodes[i];
|
||||
|
||||
delete mPreviewBitmap;
|
||||
mPreviewBitmap = NULL;
|
||||
}
|
||||
|
||||
bool InteriorResource::read(Stream& stream)
|
||||
{
|
||||
AssertFatal(stream.hasCapability(Stream::StreamRead), "Interior::read: non-read capable stream passed");
|
||||
AssertFatal(stream.getStatus() == Stream::Ok, "Interior::read: Error, stream in inconsistent state");
|
||||
|
||||
U32 i;
|
||||
|
||||
// Version this stream
|
||||
U32 fileVersion;
|
||||
stream.read(&fileVersion);
|
||||
if (fileVersion != smFileVersion) {
|
||||
Con::errorf(ConsoleLogEntry::General, "InteriorResource::read: incompatible file version found.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle preview
|
||||
bool previewIncluded;
|
||||
stream.read(&previewIncluded);
|
||||
if (previewIncluded) {
|
||||
GBitmap bmp;
|
||||
bmp.readPNG(stream);
|
||||
}
|
||||
|
||||
// Details
|
||||
U32 numDetailLevels;
|
||||
stream.read(&numDetailLevels);
|
||||
mDetailLevels.setSize(numDetailLevels);
|
||||
for (i = 0; i < mDetailLevels.size(); i++)
|
||||
mDetailLevels[i] = NULL;
|
||||
|
||||
for (i = 0; i < mDetailLevels.size(); i++) {
|
||||
mDetailLevels[i] = new Interior;
|
||||
if (mDetailLevels[i]->read(stream) == false) {
|
||||
Con::errorf(ConsoleLogEntry::General, "Unable to read detail level %d in interior resource", i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Subobjects: mirrors, translucencies
|
||||
U32 numSubObjects;
|
||||
stream.read(&numSubObjects);
|
||||
mSubObjects.setSize(numSubObjects);
|
||||
for (i = 0; i < mSubObjects.size(); i++)
|
||||
mSubObjects[i] = NULL;
|
||||
|
||||
for (i = 0; i < mSubObjects.size(); i++) {
|
||||
mSubObjects[i] = new Interior;
|
||||
if (mSubObjects[i]->read(stream) == false) {
|
||||
AssertISV(false, avar("Unable to read subobject %d in interior resource", i));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Triggers
|
||||
U32 numTriggers;
|
||||
stream.read(&numTriggers);
|
||||
mTriggers.setSize(numTriggers);
|
||||
for (i = 0; i < mTriggers.size(); i++)
|
||||
mTriggers[i] = NULL;
|
||||
|
||||
for (i = 0; i < mTriggers.size(); i++) {
|
||||
mTriggers[i] = new InteriorResTrigger;
|
||||
if (mTriggers[i]->read(stream) == false) {
|
||||
AssertISV(false, avar("Unable to read trigger %d in interior resource", i));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
U32 numChildren;
|
||||
stream.read(&numChildren);
|
||||
mInteriorPathFollowers.setSize(numChildren);
|
||||
for (i = 0; i < mInteriorPathFollowers.size(); i++)
|
||||
mInteriorPathFollowers[i] = NULL;
|
||||
|
||||
for (i = 0; i < mInteriorPathFollowers.size(); i++) {
|
||||
mInteriorPathFollowers[i] = new InteriorPathFollower;
|
||||
if (mInteriorPathFollowers[i]->read(stream) == false) {
|
||||
AssertISV(false, avar("Unable to read child %d in interior resource", i));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
U32 numFields;
|
||||
stream.read(&numFields);
|
||||
mForceFields.setSize(numFields);
|
||||
for (i = 0; i < mForceFields.size(); i++)
|
||||
mForceFields[i] = NULL;
|
||||
|
||||
for (i = 0; i < mForceFields.size(); i++) {
|
||||
mForceFields[i] = new ForceField;
|
||||
if (mForceFields[i]->read(stream) == false) {
|
||||
AssertISV(false, avar("Unable to read field %d in interior resource", i));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
U32 numSpecNodes;
|
||||
stream.read(&numSpecNodes);
|
||||
mAISpecialNodes.setSize(numSpecNodes);
|
||||
for (i = 0; i < mAISpecialNodes.size(); i++)
|
||||
mAISpecialNodes[i] = NULL;
|
||||
|
||||
for (i = 0; i < mAISpecialNodes.size(); i++) {
|
||||
mAISpecialNodes[i] = new AISpecialNode;
|
||||
if (mAISpecialNodes[i]->read(stream) == false) {
|
||||
AssertISV(false, avar("Unable to read SpecNode %d in interior resource", i));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
U32 dummyInt;
|
||||
stream.read(&dummyInt);
|
||||
if (dummyInt == 1)
|
||||
{
|
||||
if (mDetailLevels.size() != 0)
|
||||
getDetailLevel(0)->readVehicleCollision(stream);
|
||||
}
|
||||
|
||||
// For expansion purposes
|
||||
stream.read(&dummyInt);
|
||||
if(dummyInt == 2)
|
||||
{
|
||||
U32 numGameEnts;
|
||||
stream.read(&numGameEnts);
|
||||
mGameEntities.setSize(numGameEnts);
|
||||
for (i = 0; i < numGameEnts; i++)
|
||||
mGameEntities[i] = new ItrGameEntity;
|
||||
|
||||
for (i = 0; i < numGameEnts; i++) {
|
||||
if (mGameEntities[i]->read(stream) == false) {
|
||||
AssertISV(false, avar("Unable to read SpecNode %d in interior resource", i));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
stream.read(&dummyInt);
|
||||
}
|
||||
|
||||
return (stream.getStatus() == Stream::Ok);
|
||||
}
|
||||
|
||||
bool InteriorResource::write(Stream& stream) const
|
||||
{
|
||||
AssertFatal(stream.hasCapability(Stream::StreamWrite), "Interior::write: non-write capable stream passed");
|
||||
AssertFatal(stream.getStatus() == Stream::Ok, "Interior::write: Error, stream in inconsistent state");
|
||||
|
||||
// Version the stream
|
||||
stream.write(smFileVersion);
|
||||
|
||||
// Handle preview
|
||||
//
|
||||
if (mPreviewBitmap != NULL) {
|
||||
stream.write(bool(true));
|
||||
mPreviewBitmap->writePNG(stream);
|
||||
} else {
|
||||
stream.write(bool(false));
|
||||
}
|
||||
|
||||
// Write out the interiors
|
||||
stream.write(mDetailLevels.size());
|
||||
U32 i;
|
||||
for (i = 0; i < mDetailLevels.size(); i++) {
|
||||
if (mDetailLevels[i]->write(stream) == false) {
|
||||
AssertISV(false, "Unable to write detail level to stream");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
stream.write(mSubObjects.size());
|
||||
for (i = 0; i < mSubObjects.size(); i++) {
|
||||
if (mSubObjects[i]->write(stream) == false) {
|
||||
AssertISV(false, "Unable to write subobject to stream");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
stream.write(mTriggers.size());
|
||||
for (i = 0; i < mTriggers.size(); i++) {
|
||||
if (mTriggers[i]->write(stream) == false) {
|
||||
AssertISV(false, "Unable to write trigger to stream");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
stream.write(mInteriorPathFollowers.size());
|
||||
for (i = 0; i < mInteriorPathFollowers.size(); i++) {
|
||||
if (mInteriorPathFollowers[i]->write(stream) == false) {
|
||||
AssertISV(false, avar("Unable to write child %d in interior resource", i));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
stream.write(mForceFields.size());
|
||||
for (i = 0; i < mForceFields.size(); i++) {
|
||||
if (mForceFields[i]->write(stream) == false) {
|
||||
AssertISV(false, avar("Unable to write field %d in interior resource", i));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
stream.write(mAISpecialNodes.size());
|
||||
for (i = 0; i < mAISpecialNodes.size(); i++) {
|
||||
if (mAISpecialNodes[i]->write(stream) == false) {
|
||||
AssertISV(false, avar("Unable to write SpecNode %d in interior resource", i));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
stream.write(U32(1));
|
||||
if (mDetailLevels.size() != 0)
|
||||
const_cast<Interior*>(mDetailLevels[0])->writeVehicleCollision(stream);
|
||||
|
||||
// For expansion purposes
|
||||
if (mGameEntities.size())
|
||||
{
|
||||
stream.write(U32(2));
|
||||
stream.write(mGameEntities.size());
|
||||
for(i = 0; i < mGameEntities.size(); i++)
|
||||
{
|
||||
if (mGameEntities[i]->write(stream) == false) {
|
||||
AssertISV(false, avar("Unable to write GameEnt %d in interior resource", i));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
stream.write(U32(0));
|
||||
|
||||
return (stream.getStatus() == Stream::Ok);
|
||||
}
|
||||
|
||||
GBitmap* InteriorResource::extractPreview(Stream& stream)
|
||||
{
|
||||
AssertFatal(stream.hasCapability(Stream::StreamRead), "Interior::read: non-read capable stream passed");
|
||||
AssertFatal(stream.getStatus() == Stream::Ok, "Interior::read: Error, stream in inconsistent state");
|
||||
|
||||
// Version this stream
|
||||
U32 fileVersion;
|
||||
stream.read(&fileVersion);
|
||||
if (fileVersion != smFileVersion) {
|
||||
Con::errorf(ConsoleLogEntry::General, "InteriorResource::read: incompatible file version found.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Handle preview
|
||||
bool previewIncluded;
|
||||
stream.read(&previewIncluded);
|
||||
if (previewIncluded) {
|
||||
GBitmap* pBmp = new GBitmap;
|
||||
if (pBmp->readPNG(stream) == true)
|
||||
return pBmp;
|
||||
|
||||
delete pBmp;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//-------------------------------------- Interior Resource constructor
|
||||
ResourceInstance* constructInteriorDIF(Stream& stream)
|
||||
{
|
||||
InteriorResource* pResource = new InteriorResource;
|
||||
|
||||
if (pResource->read(stream) == true)
|
||||
return pResource;
|
||||
else {
|
||||
delete pResource;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
151
engine/interior/interiorRes.h
Executable file
151
engine/interior/interiorRes.h
Executable file
@ -0,0 +1,151 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _INTERIORRES_H_
|
||||
#define _INTERIORRES_H_
|
||||
|
||||
#ifndef _RESMANAGER_H_
|
||||
#include "core/resManager.h"
|
||||
#endif
|
||||
|
||||
class Stream;
|
||||
class Interior;
|
||||
class GBitmap;
|
||||
class InteriorResTrigger;
|
||||
class InteriorPath;
|
||||
class InteriorPathFollower;
|
||||
class ForceField;
|
||||
class AISpecialNode;
|
||||
class ItrGameEntity;
|
||||
|
||||
class InteriorResource : public ResourceInstance
|
||||
{
|
||||
typedef ResourceInstance Parent;
|
||||
static const U32 smFileVersion;
|
||||
|
||||
protected:
|
||||
Vector<Interior*> mDetailLevels;
|
||||
Vector<Interior*> mSubObjects;
|
||||
Vector<InteriorResTrigger*> mTriggers;
|
||||
Vector<InteriorPathFollower*> mInteriorPathFollowers;
|
||||
Vector<ForceField*> mForceFields;
|
||||
Vector<AISpecialNode*> mAISpecialNodes;
|
||||
Vector<ItrGameEntity*> mGameEntities;
|
||||
|
||||
GBitmap* mPreviewBitmap;
|
||||
|
||||
public:
|
||||
InteriorResource();
|
||||
~InteriorResource();
|
||||
|
||||
bool read(Stream& stream);
|
||||
bool write(Stream& stream) const;
|
||||
static GBitmap* extractPreview(Stream&);
|
||||
|
||||
S32 getNumDetailLevels() const;
|
||||
S32 getNumSubObjects() const;
|
||||
S32 getNumTriggers() const;
|
||||
S32 getNumInteriorPathFollowers() const;
|
||||
S32 getNumForceFields() const;
|
||||
S32 getNumSpecialNodes() const;
|
||||
S32 getNumGameEntities() const;
|
||||
|
||||
Interior* getDetailLevel(const U32);
|
||||
Interior* getSubObject(const U32);
|
||||
InteriorResTrigger* getTrigger(const U32);
|
||||
InteriorPathFollower* getInteriorPathFollower(const U32);
|
||||
ForceField* getForceField(const U32);
|
||||
AISpecialNode* getSpecialNode(const U32);
|
||||
ItrGameEntity* getGameEntity(const U32);
|
||||
};
|
||||
extern ResourceInstance* constructInteriorDIF(Stream& stream);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline S32 InteriorResource::getNumDetailLevels() const
|
||||
{
|
||||
return mDetailLevels.size();
|
||||
}
|
||||
|
||||
inline S32 InteriorResource::getNumSubObjects() const
|
||||
{
|
||||
return mSubObjects.size();
|
||||
}
|
||||
|
||||
inline S32 InteriorResource::getNumTriggers() const
|
||||
{
|
||||
return mTriggers.size();
|
||||
}
|
||||
|
||||
inline S32 InteriorResource::getNumSpecialNodes() const
|
||||
{
|
||||
return mAISpecialNodes.size();
|
||||
}
|
||||
|
||||
inline S32 InteriorResource::getNumGameEntities() const
|
||||
{
|
||||
return mGameEntities.size();
|
||||
}
|
||||
|
||||
inline S32 InteriorResource::getNumInteriorPathFollowers() const
|
||||
{
|
||||
return mInteriorPathFollowers.size();
|
||||
}
|
||||
|
||||
inline S32 InteriorResource::getNumForceFields() const
|
||||
{
|
||||
return mForceFields.size();
|
||||
}
|
||||
|
||||
inline Interior* InteriorResource::getDetailLevel(const U32 idx)
|
||||
{
|
||||
AssertFatal(idx < getNumDetailLevels(), "Error, out of bounds detail level!");
|
||||
|
||||
return mDetailLevels[idx];
|
||||
}
|
||||
|
||||
inline Interior* InteriorResource::getSubObject(const U32 idx)
|
||||
{
|
||||
AssertFatal(idx < getNumSubObjects(), "Error, out of bounds subObject!");
|
||||
|
||||
return mSubObjects[idx];
|
||||
}
|
||||
|
||||
inline InteriorResTrigger* InteriorResource::getTrigger(const U32 idx)
|
||||
{
|
||||
AssertFatal(idx < getNumTriggers(), "Error, out of bounds trigger!");
|
||||
|
||||
return mTriggers[idx];
|
||||
}
|
||||
|
||||
inline InteriorPathFollower* InteriorResource::getInteriorPathFollower(const U32 idx)
|
||||
{
|
||||
AssertFatal(idx < getNumInteriorPathFollowers(), "Error, out of bounds path follower!");
|
||||
|
||||
return mInteriorPathFollowers[idx];
|
||||
}
|
||||
|
||||
inline ForceField* InteriorResource::getForceField(const U32 idx)
|
||||
{
|
||||
AssertFatal(idx < getNumForceFields(), "Error, out of bounds force field!");
|
||||
|
||||
return mForceFields[idx];
|
||||
}
|
||||
|
||||
inline AISpecialNode* InteriorResource::getSpecialNode(const U32 idx)
|
||||
{
|
||||
AssertFatal(idx < getNumSpecialNodes(), "Error, out of bounds Special Nodes!");
|
||||
|
||||
return mAISpecialNodes[idx];
|
||||
}
|
||||
|
||||
inline ItrGameEntity* InteriorResource::getGameEntity(const U32 idx)
|
||||
{
|
||||
AssertFatal(idx < getNumGameEntities(), "Error, out of bounds Game ENts!");
|
||||
|
||||
return mGameEntities[idx];
|
||||
}
|
||||
|
||||
#endif // _H_INTERIORRES_
|
||||
|
226
engine/interior/interiorResObjects.cc
Executable file
226
engine/interior/interiorResObjects.cc
Executable file
@ -0,0 +1,226 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "interior/interiorResObjects.h"
|
||||
#include "core/stream.h"
|
||||
#include "math/mathIO.h"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//--------------------------------------
|
||||
//
|
||||
|
||||
void InteriorDict::read(Stream &stream)
|
||||
{
|
||||
U32 sz;
|
||||
stream.read(&sz);
|
||||
setSize(sz);
|
||||
for(U32 i = 0; i < sz; i++)
|
||||
{
|
||||
InteriorDictEntry e;
|
||||
stream.readString(e.name);
|
||||
stream.readString(e.value);
|
||||
(*this)[i] = e;
|
||||
}
|
||||
}
|
||||
|
||||
void InteriorDict::write(Stream &stream) const
|
||||
{
|
||||
U32 sz = size();
|
||||
stream.write(sz);
|
||||
for(U32 i = 0; i < sz; i++)
|
||||
{
|
||||
stream.writeString((*this)[i].name);
|
||||
stream.writeString((*this)[i].value);
|
||||
}
|
||||
}
|
||||
|
||||
bool InteriorResTrigger::read(Stream& stream)
|
||||
{
|
||||
U32 i, size;
|
||||
stream.readString(mName);
|
||||
mDataBlock = stream.readSTString();
|
||||
mDictionary.read(stream);
|
||||
|
||||
// Read the polyhedron
|
||||
stream.read(&size);
|
||||
mPolyhedron.pointList.setSize(size);
|
||||
for (i = 0; i < mPolyhedron.pointList.size(); i++)
|
||||
mathRead(stream, &mPolyhedron.pointList[i]);
|
||||
|
||||
stream.read(&size);
|
||||
mPolyhedron.planeList.setSize(size);
|
||||
for (i = 0; i < mPolyhedron.planeList.size(); i++)
|
||||
mathRead(stream, &mPolyhedron.planeList[i]);
|
||||
|
||||
stream.read(&size);
|
||||
mPolyhedron.edgeList.setSize(size);
|
||||
for (i = 0; i < mPolyhedron.edgeList.size(); i++) {
|
||||
Polyhedron::Edge& rEdge = mPolyhedron.edgeList[i];
|
||||
|
||||
stream.read(&rEdge.face[0]);
|
||||
stream.read(&rEdge.face[1]);
|
||||
stream.read(&rEdge.vertex[0]);
|
||||
stream.read(&rEdge.vertex[1]);
|
||||
}
|
||||
|
||||
// And the offset
|
||||
mathRead(stream, &mOffset);
|
||||
|
||||
return (stream.getStatus() == Stream::Ok);
|
||||
}
|
||||
|
||||
bool InteriorResTrigger::write(Stream& stream) const
|
||||
{
|
||||
U32 i;
|
||||
|
||||
stream.writeString(mName);
|
||||
stream.writeString(mDataBlock);
|
||||
mDictionary.write(stream);
|
||||
|
||||
// Write the polyhedron
|
||||
stream.write(mPolyhedron.pointList.size());
|
||||
for (i = 0; i < mPolyhedron.pointList.size(); i++)
|
||||
mathWrite(stream, mPolyhedron.pointList[i]);
|
||||
|
||||
stream.write(mPolyhedron.planeList.size());
|
||||
for (i = 0; i < mPolyhedron.planeList.size(); i++)
|
||||
mathWrite(stream, mPolyhedron.planeList[i]);
|
||||
|
||||
stream.write(mPolyhedron.edgeList.size());
|
||||
for (i = 0; i < mPolyhedron.edgeList.size(); i++) {
|
||||
const Polyhedron::Edge& rEdge = mPolyhedron.edgeList[i];
|
||||
|
||||
stream.write(rEdge.face[0]);
|
||||
stream.write(rEdge.face[1]);
|
||||
stream.write(rEdge.vertex[0]);
|
||||
stream.write(rEdge.vertex[1]);
|
||||
}
|
||||
|
||||
// And the offset
|
||||
mathWrite(stream, mOffset);
|
||||
|
||||
return (stream.getStatus() == Stream::Ok);
|
||||
}
|
||||
|
||||
InteriorPathFollower::InteriorPathFollower()
|
||||
{
|
||||
mName = "";
|
||||
mPathIndex = 0;
|
||||
mOffset.set(0, 0, 0);
|
||||
}
|
||||
|
||||
InteriorPathFollower::~InteriorPathFollower()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool InteriorPathFollower::read(Stream& stream)
|
||||
{
|
||||
mName = stream.readSTString();
|
||||
mDataBlock = stream.readSTString();
|
||||
stream.read(&mInteriorResIndex);
|
||||
mathRead(stream, &mOffset);
|
||||
mDictionary.read(stream);
|
||||
|
||||
U32 numTriggers;
|
||||
stream.read(&numTriggers);
|
||||
mTriggerIds.setSize(numTriggers);
|
||||
for (U32 i = 0; i < mTriggerIds.size(); i++)
|
||||
stream.read(&mTriggerIds[i]);
|
||||
|
||||
U32 numWayPoints;
|
||||
stream.read(&numWayPoints);
|
||||
mWayPoints.setSize(numWayPoints);
|
||||
for(U32 i = 0; i < numWayPoints; i++)
|
||||
{
|
||||
mathRead(stream, &mWayPoints[i].pos);
|
||||
mathRead(stream, &mWayPoints[i].rot);
|
||||
stream.read(&mWayPoints[i].msToNext);
|
||||
stream.read(&mWayPoints[i].smoothingType);
|
||||
}
|
||||
stream.read(&mTotalMS);
|
||||
return (stream.getStatus() == Stream::Ok);
|
||||
}
|
||||
|
||||
bool InteriorPathFollower::write(Stream& stream) const
|
||||
{
|
||||
stream.writeString(mName);
|
||||
stream.writeString(mDataBlock);
|
||||
stream.write(mInteriorResIndex);
|
||||
mathWrite(stream, mOffset);
|
||||
mDictionary.write(stream);
|
||||
|
||||
stream.write(mTriggerIds.size());
|
||||
for (U32 i = 0; i < mTriggerIds.size(); i++)
|
||||
stream.write(mTriggerIds[i]);
|
||||
|
||||
stream.write(U32(mWayPoints.size()));
|
||||
for (U32 i = 0; i < mWayPoints.size(); i++) {
|
||||
mathWrite(stream, mWayPoints[i].pos);
|
||||
mathWrite(stream, mWayPoints[i].rot);
|
||||
stream.write(mWayPoints[i].msToNext);
|
||||
stream.write(mWayPoints[i].smoothingType);
|
||||
}
|
||||
stream.write(mTotalMS);
|
||||
|
||||
return (stream.getStatus() == Stream::Ok);
|
||||
}
|
||||
|
||||
AISpecialNode::AISpecialNode()
|
||||
{
|
||||
mName = "";
|
||||
mPos.set(0, 0, 0);
|
||||
}
|
||||
|
||||
AISpecialNode::~AISpecialNode()
|
||||
{
|
||||
}
|
||||
|
||||
bool AISpecialNode::read(Stream& stream)
|
||||
{
|
||||
mName = stream.readSTString();
|
||||
mathRead(stream, &mPos);
|
||||
|
||||
return (stream.getStatus() == Stream::Ok);
|
||||
}
|
||||
|
||||
bool AISpecialNode::write(Stream& stream) const
|
||||
{
|
||||
stream.writeString(mName);
|
||||
mathWrite(stream, mPos);
|
||||
|
||||
return (stream.getStatus() == Stream::Ok);
|
||||
}
|
||||
|
||||
ItrGameEntity::ItrGameEntity()
|
||||
{
|
||||
mDataBlock = "";
|
||||
mGameClass = "";
|
||||
mPos.set(0, 0, 0);
|
||||
}
|
||||
|
||||
ItrGameEntity::~ItrGameEntity()
|
||||
{
|
||||
}
|
||||
|
||||
bool ItrGameEntity::read(Stream& stream)
|
||||
{
|
||||
mDataBlock = stream.readSTString();
|
||||
mGameClass = stream.readSTString();
|
||||
mathRead(stream, &mPos);
|
||||
mDictionary.read(stream);
|
||||
|
||||
return (stream.getStatus() == Stream::Ok);
|
||||
}
|
||||
|
||||
bool ItrGameEntity::write(Stream& stream) const
|
||||
{
|
||||
stream.writeString(mDataBlock);
|
||||
stream.writeString(mGameClass);
|
||||
mathWrite(stream, mPos);
|
||||
mDictionary.write(stream);
|
||||
|
||||
return (stream.getStatus() == Stream::Ok);
|
||||
}
|
131
engine/interior/interiorResObjects.h
Executable file
131
engine/interior/interiorResObjects.h
Executable file
@ -0,0 +1,131 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _INTERIORRESOBJECTS_H_
|
||||
#define _INTERIORRESOBJECTS_H_
|
||||
|
||||
#ifndef _PLATFORM_H_
|
||||
#include "platform/platform.h"
|
||||
#endif
|
||||
#ifndef _MPOINT_H_
|
||||
#include "math/mPoint.h"
|
||||
#endif
|
||||
#ifndef _MBOX_H_
|
||||
#include "math/mBox.h"
|
||||
#endif
|
||||
#ifndef _MMATRIX_H_
|
||||
#include "math/mMatrix.h"
|
||||
#endif
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/tVector.h"
|
||||
#endif
|
||||
#ifndef _POLYHEDRON_H_
|
||||
#include "collision/polyhedron.h"
|
||||
#endif
|
||||
|
||||
class Stream;
|
||||
|
||||
struct InteriorDictEntry
|
||||
{
|
||||
char name[32];
|
||||
char value[32];
|
||||
};
|
||||
|
||||
class InteriorDict : public Vector<InteriorDictEntry>
|
||||
{
|
||||
public:
|
||||
void read(Stream& stream);
|
||||
void write(Stream& stream) const;
|
||||
};
|
||||
|
||||
class InteriorResTrigger
|
||||
{
|
||||
public:
|
||||
enum Constants {
|
||||
MaxNameChars = 255
|
||||
};
|
||||
|
||||
char mName[MaxNameChars+1];
|
||||
StringTableEntry mDataBlock;
|
||||
InteriorDict mDictionary;
|
||||
|
||||
Point3F mOffset;
|
||||
Polyhedron mPolyhedron;
|
||||
|
||||
public:
|
||||
InteriorResTrigger() { }
|
||||
|
||||
bool read(Stream& stream);
|
||||
bool write(Stream& stream) const;
|
||||
};
|
||||
|
||||
class InteriorPathFollower
|
||||
{
|
||||
public:
|
||||
struct WayPoint {
|
||||
Point3F pos;
|
||||
QuatF rot;
|
||||
U32 msToNext;
|
||||
U32 smoothingType;
|
||||
};
|
||||
StringTableEntry mName;
|
||||
StringTableEntry mDataBlock;
|
||||
U32 mInteriorResIndex;
|
||||
U32 mPathIndex;
|
||||
Point3F mOffset;
|
||||
Vector<U32> mTriggerIds;
|
||||
Vector<WayPoint> mWayPoints;
|
||||
U32 mTotalMS;
|
||||
InteriorDict mDictionary;
|
||||
|
||||
public:
|
||||
InteriorPathFollower();
|
||||
~InteriorPathFollower();
|
||||
|
||||
bool read(Stream& stream);
|
||||
bool write(Stream& stream) const;
|
||||
};
|
||||
|
||||
|
||||
class AISpecialNode
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
chute = 0,
|
||||
};
|
||||
|
||||
public:
|
||||
StringTableEntry mName;
|
||||
Point3F mPos;
|
||||
//U32 mType;
|
||||
|
||||
public:
|
||||
AISpecialNode();
|
||||
~AISpecialNode();
|
||||
|
||||
bool read(Stream& stream);
|
||||
bool write(Stream& stream) const;
|
||||
|
||||
};
|
||||
|
||||
class ItrGameEntity
|
||||
{
|
||||
public:
|
||||
StringTableEntry mDataBlock;
|
||||
StringTableEntry mGameClass;
|
||||
Point3F mPos;
|
||||
InteriorDict mDictionary;
|
||||
|
||||
public:
|
||||
ItrGameEntity();
|
||||
~ItrGameEntity();
|
||||
|
||||
bool read(Stream& stream);
|
||||
bool write(Stream& stream) const;
|
||||
|
||||
};
|
||||
|
||||
#endif // _H_INTERIORRESOBJECTS_
|
91
engine/interior/interiorSubObject.cc
Executable file
91
engine/interior/interiorSubObject.cc
Executable file
@ -0,0 +1,91 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "core/stream.h"
|
||||
#include "interior/interiorInstance.h"
|
||||
|
||||
#include "interior/interiorSubObject.h"
|
||||
#include "interior/mirrorSubObject.h"
|
||||
|
||||
|
||||
InteriorSubObject::InteriorSubObject()
|
||||
{
|
||||
mInteriorInstance = NULL;
|
||||
}
|
||||
|
||||
InteriorSubObject::~InteriorSubObject()
|
||||
{
|
||||
mInteriorInstance = NULL;
|
||||
}
|
||||
|
||||
InteriorSubObject* InteriorSubObject::readISO(Stream& stream)
|
||||
{
|
||||
U32 soKey;
|
||||
stream.read(&soKey);
|
||||
|
||||
InteriorSubObject* pObject = NULL;
|
||||
switch (soKey) {
|
||||
case MirrorSubObjectKey:
|
||||
pObject = new MirrorSubObject;
|
||||
break;
|
||||
|
||||
default:
|
||||
Con::errorf(ConsoleLogEntry::General, "Bad key in subObject stream!");
|
||||
return NULL;
|
||||
};
|
||||
|
||||
if (pObject) {
|
||||
bool readSuccess = pObject->_readISO(stream);
|
||||
if (readSuccess == false) {
|
||||
delete pObject;
|
||||
pObject = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return pObject;
|
||||
}
|
||||
|
||||
bool InteriorSubObject::writeISO(Stream& stream) const
|
||||
{
|
||||
stream.write(getSubObjectKey());
|
||||
return _writeISO(stream);
|
||||
}
|
||||
|
||||
bool InteriorSubObject::_readISO(Stream& stream)
|
||||
{
|
||||
return (stream.getStatus() == Stream::Ok);
|
||||
}
|
||||
|
||||
bool InteriorSubObject::_writeISO(Stream& stream) const
|
||||
{
|
||||
return (stream.getStatus() == Stream::Ok);
|
||||
}
|
||||
|
||||
const MatrixF& InteriorSubObject::getSOTransform() const
|
||||
{
|
||||
static const MatrixF csBadMatrix(true);
|
||||
|
||||
if (mInteriorInstance != NULL) {
|
||||
return mInteriorInstance->getTransform();
|
||||
} else {
|
||||
AssertWarn(false, "Returning bad transform for subobject");
|
||||
return csBadMatrix;
|
||||
}
|
||||
}
|
||||
|
||||
const Point3F& InteriorSubObject::getSOScale() const
|
||||
{
|
||||
return mInteriorInstance->getScale();
|
||||
}
|
||||
|
||||
InteriorInstance* InteriorSubObject::getInstance()
|
||||
{
|
||||
return mInteriorInstance;
|
||||
}
|
||||
|
||||
void InteriorSubObject::noteTransformChange()
|
||||
{
|
||||
//
|
||||
}
|
63
engine/interior/interiorSubObject.h
Executable file
63
engine/interior/interiorSubObject.h
Executable file
@ -0,0 +1,63 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _INTERIORSUBOBJECT_H_
|
||||
#define _INTERIORSUBOBJECT_H_
|
||||
|
||||
#ifndef _SCENESTATE_H_
|
||||
#include "sceneGraph/sceneState.h"
|
||||
#endif
|
||||
#ifndef _SCENEOBJECT_H_
|
||||
#include "sim/sceneObject.h"
|
||||
#endif
|
||||
|
||||
class InteriorInstance;
|
||||
|
||||
class SubObjectRenderImage : public SceneRenderImage
|
||||
{
|
||||
public:
|
||||
U32 mDetailLevel;
|
||||
};
|
||||
|
||||
class InteriorSubObject : public SceneObject
|
||||
{
|
||||
typedef SceneObject Parent;
|
||||
|
||||
protected:
|
||||
InteriorInstance* mInteriorInstance; // Should NOT be set by derived except in clone
|
||||
|
||||
protected:
|
||||
enum SubObjectKeys {
|
||||
TranslucentSubObjectKey = 0,
|
||||
MirrorSubObjectKey = 1
|
||||
};
|
||||
|
||||
virtual U32 getSubObjectKey() const = 0;
|
||||
virtual bool _readISO(Stream&);
|
||||
virtual bool _writeISO(Stream&) const;
|
||||
|
||||
InteriorInstance* getInstance();
|
||||
const MatrixF& getSOTransform() const;
|
||||
const Point3F& getSOScale() const;
|
||||
|
||||
public:
|
||||
InteriorSubObject();
|
||||
virtual ~InteriorSubObject();
|
||||
|
||||
// Render control. A sub-object should return false from renderDetailDependant if
|
||||
// it exists only at the level-0 detail level, ie, doors, elevators, etc., true
|
||||
// if should only render at the interiors detail, ie, translucencies.
|
||||
virtual SubObjectRenderImage* getRenderImage(SceneState*, const Point3F& osPoint) = 0;
|
||||
virtual bool renderDetailDependant() const = 0;
|
||||
virtual U32 getZone() const = 0;
|
||||
|
||||
virtual void noteTransformChange();
|
||||
virtual InteriorSubObject* clone(InteriorInstance*) const = 0;
|
||||
|
||||
static InteriorSubObject* readISO(Stream&);
|
||||
bool writeISO(Stream&) const;
|
||||
};
|
||||
|
||||
#endif // _H_INTERIORSUBOBJECT_
|
111
engine/interior/itf.h
Executable file
111
engine/interior/itf.h
Executable file
@ -0,0 +1,111 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _ITF_H_
|
||||
#define _ITF_H_
|
||||
|
||||
#ifndef _TYPES_H_
|
||||
#include "platform/types.h"
|
||||
#endif
|
||||
#ifndef _COLOR_H
|
||||
#include "core/color.h"
|
||||
#endif
|
||||
#ifndef _MPOINT_H_
|
||||
#include "math/mPoint.h"
|
||||
#endif
|
||||
|
||||
#ifndef _INTERIOR_H_
|
||||
// redecl struct here for now... interior.h brings in the whole fricking codebase.
|
||||
struct ItrPaddedPoint
|
||||
{
|
||||
Point3F point;
|
||||
union {
|
||||
F32 fogCoord;
|
||||
U8 fogColor[4];
|
||||
};
|
||||
};
|
||||
#endif
|
||||
|
||||
struct OutputPoint
|
||||
{
|
||||
Point3F point;
|
||||
union {
|
||||
F32 fogCoord; // to match input struct cleanly..
|
||||
U32 fogColors;
|
||||
U8 fogColor[4];
|
||||
};
|
||||
Point2F texCoord;
|
||||
Point2F lmCoord;
|
||||
};
|
||||
|
||||
struct OutputPointFC_VB
|
||||
{
|
||||
Point3F point; //0/4/8
|
||||
union {
|
||||
U32 currentColors;
|
||||
U8 currentColor[4];
|
||||
}; //12
|
||||
union {
|
||||
U32 fogColors;
|
||||
U8 fogColor[4];
|
||||
}; //16
|
||||
Point2F texCoord; //20/24
|
||||
Point2F lmCoord; //28/32
|
||||
};
|
||||
|
||||
struct OutputPointSP_FC_VB
|
||||
{
|
||||
Point3F point;
|
||||
union {
|
||||
U32 lmColors;
|
||||
U8 lmColor[4];
|
||||
};
|
||||
union {
|
||||
U32 fogColors;
|
||||
U8 fogColor[4];
|
||||
};
|
||||
Point2F texCoord;
|
||||
};
|
||||
|
||||
extern "C"
|
||||
{
|
||||
// Process Globals
|
||||
extern F32 texGen0[8];
|
||||
extern F32 texGen1[8];
|
||||
extern Point2F *fogCoordinatePointer;
|
||||
|
||||
// Process Functions
|
||||
void processTriFan(OutputPoint* dst,
|
||||
const ItrPaddedPoint* srcPoints,
|
||||
const U32* srcIndices,
|
||||
const U32 numIndices);
|
||||
void processTriFanSP(OutputPoint* dst,
|
||||
const ItrPaddedPoint* srcPoints,
|
||||
const U32* srcIndices,
|
||||
const U32 numIndices,
|
||||
const ColorI* srcColors);
|
||||
void processTriFanVC_TF(OutputPoint* dst,
|
||||
const ItrPaddedPoint* srcPoints,
|
||||
const U32* srcIndices,
|
||||
const U32 numIndices,
|
||||
const ColorI* srcColors);
|
||||
void processTriFanSP_FC(OutputPoint* dst,
|
||||
const ItrPaddedPoint* srcPoints,
|
||||
const U32* srcIndices,
|
||||
const U32 numIndices,
|
||||
const ColorI* srcColors);
|
||||
void processTriFanFC_VB(OutputPointFC_VB* dst,
|
||||
const ItrPaddedPoint* srcPoints,
|
||||
const U32* srcIndices,
|
||||
const U32 numIndices);
|
||||
void processTriFanSP_FC_VB(OutputPointSP_FC_VB* dst,
|
||||
const ItrPaddedPoint* srcPoints,
|
||||
const U32* srcIndices,
|
||||
const U32 numIndices,
|
||||
const ColorI* srcColors);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
717
engine/interior/itfdump.asm
Executable file
717
engine/interior/itfdump.asm
Executable file
@ -0,0 +1,717 @@
|
||||
;-----------------------------------------------------------------------------
|
||||
; Torque Game Engine
|
||||
; Copyright (C) GarageGames.com, Inc.
|
||||
;-----------------------------------------------------------------------------
|
||||
|
||||
segment .data
|
||||
|
||||
storeebp dd 0
|
||||
|
||||
srcPoints dd 0
|
||||
srcColors dd 0
|
||||
srcIndices dd 0
|
||||
numPoints dd 0
|
||||
two55 dd 0x437F0000
|
||||
alpha dd 0
|
||||
|
||||
%ifdef LINUX
|
||||
; No underscore needed for ELF object files
|
||||
%define _texGen0 texGen0
|
||||
%define _texGen1 texGen1
|
||||
%define _fogCoordinatePointer fogCoordinatePointer
|
||||
%endif
|
||||
extern _texGen0
|
||||
extern _texGen1
|
||||
extern _fogCoordinatePointer
|
||||
|
||||
|
||||
segment .text
|
||||
|
||||
;
|
||||
; these macros are good for both functions
|
||||
;
|
||||
|
||||
%define in_dst [ebp+8]
|
||||
%define in_src_points [ebp+12]
|
||||
%define in_src_indices [ebp+16]
|
||||
%define in_numpoints [ebp+20]
|
||||
|
||||
%define in_srcColors [ebp+24] ; Valid only for SP
|
||||
|
||||
; CodeWarrior sucks :P
|
||||
%ifdef LINUX
|
||||
global processTriFan
|
||||
|
||||
processTriFan:
|
||||
%else
|
||||
global _processTriFan
|
||||
|
||||
_processTriFan:
|
||||
%endif
|
||||
|
||||
; prologue
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push eax
|
||||
push ebx
|
||||
push ecx
|
||||
push edi
|
||||
push esi
|
||||
|
||||
; Store the destination and source pointers
|
||||
mov eax, in_src_points
|
||||
mov [srcPoints], eax
|
||||
mov eax, in_src_indices
|
||||
mov [srcIndices], eax
|
||||
mov eax, in_numpoints
|
||||
mov [numPoints], eax
|
||||
|
||||
mov edi, in_dst
|
||||
|
||||
mov [storeebp], ebp
|
||||
xor ebp, ebp
|
||||
procPointLp1:
|
||||
; This could be faster
|
||||
mov esi, [srcIndices]
|
||||
lea esi, [esi + ebp*4]
|
||||
mov eax, dword [esi]
|
||||
shl eax, 4 ; idx *= 16
|
||||
mov esi, [srcPoints]
|
||||
lea esi, [esi + eax]
|
||||
|
||||
mov eax, [esi + 0] ; x
|
||||
mov ebx, [esi + 4] ; y
|
||||
mov ecx, [esi + 8] ; z
|
||||
mov edx, [esi + 12] ; f
|
||||
mov [edi + 0], eax ; <- x
|
||||
mov [edi + 4], ebx ; <- y
|
||||
mov [edi + 8], ecx ; <- z
|
||||
mov [edi + 12], edx ; <- f
|
||||
|
||||
; tc0.s
|
||||
fld dword [_texGen0 + 0] ; tg0.s.x
|
||||
fmul dword [esi + 0]
|
||||
fld dword [_texGen0 + 4] ; tg0.s.y
|
||||
fmul dword [esi + 4]
|
||||
fld dword [_texGen0 + 8] ; tg0.s.z
|
||||
fmul dword [esi + 8]
|
||||
fld dword [_texGen0 + 12] ; tg0.s.w
|
||||
faddp st3, st0
|
||||
faddp st1, st0
|
||||
faddp st1, st0
|
||||
fstp dword [edi + 16] ; tc0.s
|
||||
|
||||
; tc0.t
|
||||
fld dword [_texGen0 + 16] ; tg0.t.x
|
||||
fmul dword [esi + 0]
|
||||
fld dword [_texGen0 + 20] ; tg0.t.y
|
||||
fmul dword [esi + 4]
|
||||
fld dword [_texGen0 + 24] ; tg0.t.z
|
||||
fmul dword [esi + 8]
|
||||
fld dword [_texGen0 + 28] ; tg0.t.w
|
||||
faddp st3, st0
|
||||
faddp st1, st0
|
||||
faddp st1, st0
|
||||
fstp dword [edi + 20] ; tc0.t
|
||||
|
||||
; tc1.s
|
||||
fld dword [_texGen1 + 0] ; tg1.s.x
|
||||
fmul dword [esi + 0]
|
||||
fld dword [_texGen1 + 4] ; tg1.s.y
|
||||
fmul dword [esi + 4]
|
||||
fld dword [_texGen1 + 8] ; tg1.s.z
|
||||
fmul dword [esi + 8]
|
||||
fld dword [_texGen1 + 12] ; tg1.s.w
|
||||
faddp st3, st0
|
||||
faddp st1, st0
|
||||
faddp st1, st0
|
||||
fstp dword [edi + 24] ; tc1.s
|
||||
|
||||
; tc1.t
|
||||
fld dword [_texGen1 + 16] ; tg1.t.x
|
||||
fmul dword [esi + 0]
|
||||
fld dword [_texGen1 + 20] ; tg1.t.y
|
||||
fmul dword [esi + 4]
|
||||
fld dword [_texGen1 + 24] ; tg1.t.z
|
||||
fmul dword [esi + 8]
|
||||
fld dword [_texGen1 + 28] ; tg1.t.w
|
||||
faddp st3, st0
|
||||
faddp st1, st0
|
||||
faddp st1, st0
|
||||
fstp dword [edi + 28] ; tc1.t
|
||||
|
||||
add edi, 32
|
||||
|
||||
inc ebp
|
||||
cmp ebp, [numPoints]
|
||||
jl near procPointLp1
|
||||
|
||||
mov ebp, [storeebp]
|
||||
|
||||
; epilogue
|
||||
pop esi
|
||||
pop edi
|
||||
pop ecx
|
||||
pop ebx
|
||||
pop eax
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
|
||||
; More suckage
|
||||
%ifdef LINUX
|
||||
global processTriFanSP
|
||||
|
||||
processTriFanSP:
|
||||
%else
|
||||
global _processTriFanSP
|
||||
|
||||
_processTriFanSP:
|
||||
%endif
|
||||
|
||||
; prologue
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push eax
|
||||
push ebx
|
||||
push ecx
|
||||
push edi
|
||||
push esi
|
||||
|
||||
; Store the destination and source pointers
|
||||
mov eax, in_src_points
|
||||
mov [srcPoints], eax
|
||||
mov eax, in_src_indices
|
||||
mov [srcIndices], eax
|
||||
mov eax, in_numpoints
|
||||
mov [numPoints], eax
|
||||
mov eax, in_srcColors
|
||||
mov [srcColors], eax
|
||||
|
||||
mov edi, in_dst
|
||||
|
||||
mov [storeebp], ebp
|
||||
xor ebp, ebp
|
||||
procPointLp2:
|
||||
; This could be faster
|
||||
mov esi, [srcIndices]
|
||||
lea esi, [esi + ebp*4]
|
||||
mov eax, dword [esi]
|
||||
shl eax, 4 ; idx *= 16
|
||||
mov esi, [srcPoints]
|
||||
lea esi, [esi + eax]
|
||||
|
||||
mov eax, [esi + 0] ; x
|
||||
mov ebx, [esi + 4] ; y
|
||||
mov ecx, [esi + 8] ; z
|
||||
mov edx, [srcColors] ; color
|
||||
mov [edi + 0], eax ; <- x
|
||||
lea edx, [edx + ebp*4] ; color
|
||||
mov [edi + 4], ebx ; <- y
|
||||
mov edx, [edx] ; color
|
||||
mov [edi + 8], ecx ; <- z
|
||||
mov [edi + 12], edx ; color
|
||||
|
||||
; tc0.s
|
||||
fld dword [_texGen0 + 0] ; tg0.s.x
|
||||
fmul dword [esi + 0]
|
||||
fld dword [_texGen0 + 4] ; tg0.s.y
|
||||
fmul dword [esi + 4]
|
||||
fld dword [_texGen0 + 8] ; tg0.s.z
|
||||
fmul dword [esi + 8]
|
||||
fld dword [_texGen0 + 12] ; tg0.s.w
|
||||
faddp st3, st0
|
||||
faddp st1, st0
|
||||
faddp st1, st0
|
||||
fstp dword [edi + 16] ; tc0.s
|
||||
|
||||
; tc0.t
|
||||
fld dword [_texGen0 + 16] ; tg0.t.x
|
||||
fmul dword [esi + 0]
|
||||
fld dword [_texGen0 + 20] ; tg0.t.y
|
||||
fmul dword [esi + 4]
|
||||
fld dword [_texGen0 + 24] ; tg0.t.z
|
||||
fmul dword [esi + 8]
|
||||
fld dword [_texGen0 + 28] ; tg0.t.w
|
||||
faddp st3, st0
|
||||
faddp st1, st0
|
||||
faddp st1, st0
|
||||
fstp dword [edi + 20] ; tc0.t
|
||||
|
||||
add edi, 32
|
||||
|
||||
inc ebp
|
||||
cmp ebp, [numPoints]
|
||||
jl near procPointLp2
|
||||
|
||||
mov ebp, [storeebp]
|
||||
|
||||
; epilogue
|
||||
pop esi
|
||||
pop edi
|
||||
pop ecx
|
||||
pop ebx
|
||||
pop eax
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
|
||||
; More suckage
|
||||
%ifdef LINUX
|
||||
global processTriFanVC_TF
|
||||
|
||||
processTriFanVC_TF:
|
||||
%else
|
||||
global _processTriFanVC_TF
|
||||
|
||||
_processTriFanVC_TF:
|
||||
%endif
|
||||
|
||||
; prologue
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push eax
|
||||
push ebx
|
||||
push ecx
|
||||
push edi
|
||||
push esi
|
||||
|
||||
; Store the destination and source pointers
|
||||
mov eax, in_src_points
|
||||
mov [srcPoints], eax
|
||||
mov eax, in_src_indices
|
||||
mov [srcIndices], eax
|
||||
mov eax, in_numpoints
|
||||
mov [numPoints], eax
|
||||
mov eax, in_srcColors
|
||||
mov [srcColors], eax
|
||||
|
||||
mov edi, in_dst
|
||||
|
||||
mov [storeebp], ebp
|
||||
xor ebp, ebp
|
||||
procPointLp4:
|
||||
; This could be faster
|
||||
mov esi, [srcIndices]
|
||||
lea esi, [esi + ebp*4]
|
||||
mov eax, dword [esi]
|
||||
shl eax, 4 ; idx *= 16
|
||||
mov esi, [srcPoints]
|
||||
lea esi, [esi + eax]
|
||||
|
||||
; Fog tex coord
|
||||
mov ebx, [_fogCoordinatePointer]
|
||||
shr eax, 1 ; idx /= 2
|
||||
lea ebx, [ebx + eax]
|
||||
mov ecx, [ebx + 0];
|
||||
mov edx, [ebx + 4];
|
||||
mov [edi + 16], ecx
|
||||
mov [edi + 20], edx
|
||||
|
||||
mov eax, [esi + 0] ; x
|
||||
mov ebx, [esi + 4] ; y
|
||||
mov ecx, [esi + 8] ; z
|
||||
mov edx, [srcColors] ; color
|
||||
mov [edi + 0], eax ; <- x
|
||||
lea edx, [edx + ebp*4] ; color
|
||||
mov [edi + 4], ebx ; <- y
|
||||
mov edx, [edx] ; color
|
||||
mov [edi + 8], ecx ; <- z
|
||||
mov [edi + 12], edx ; color
|
||||
|
||||
|
||||
; tc0.s
|
||||
fld dword [_texGen0 + 0] ; tg0.s.x
|
||||
fmul dword [esi + 0]
|
||||
fld dword [_texGen0 + 4] ; tg0.s.y
|
||||
fmul dword [esi + 4]
|
||||
fld dword [_texGen0 + 8] ; tg0.s.z
|
||||
fmul dword [esi + 8]
|
||||
fld dword [_texGen0 + 12] ; tg0.s.w
|
||||
faddp st3, st0
|
||||
faddp st1, st0
|
||||
faddp st1, st0
|
||||
fstp dword [edi + 24] ; tc0.s
|
||||
|
||||
; tc0.t
|
||||
fld dword [_texGen0 + 16] ; tg0.t.x
|
||||
fmul dword [esi + 0]
|
||||
fld dword [_texGen0 + 20] ; tg0.t.y
|
||||
fmul dword [esi + 4]
|
||||
fld dword [_texGen0 + 24] ; tg0.t.z
|
||||
fmul dword [esi + 8]
|
||||
fld dword [_texGen0 + 28] ; tg0.t.w
|
||||
faddp st3, st0
|
||||
faddp st1, st0
|
||||
faddp st1, st0
|
||||
fstp dword [edi + 28] ; tc0.t
|
||||
|
||||
add edi, 32
|
||||
|
||||
inc ebp
|
||||
cmp ebp, [numPoints]
|
||||
jl near procPointLp4
|
||||
|
||||
mov ebp, [storeebp]
|
||||
|
||||
; epilogue
|
||||
pop esi
|
||||
pop edi
|
||||
pop ecx
|
||||
pop ebx
|
||||
pop eax
|
||||
pop ebp
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
|
||||
; More suckagea
|
||||
%ifdef LINUX
|
||||
global processTriFanSP_FC
|
||||
|
||||
processTriFanSP_FC:
|
||||
%else
|
||||
global _processTriFanSP_FC
|
||||
|
||||
_processTriFanSP_FC:
|
||||
%endif
|
||||
|
||||
; prologue
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push eax
|
||||
push ebx
|
||||
push ecx
|
||||
push edi
|
||||
push esi
|
||||
|
||||
; Store the destination and source pointers
|
||||
mov eax, in_src_points
|
||||
mov [srcPoints], eax
|
||||
mov eax, in_src_indices
|
||||
mov [srcIndices], eax
|
||||
mov eax, in_numpoints
|
||||
mov [numPoints], eax
|
||||
mov eax, in_srcColors
|
||||
mov [srcColors], eax
|
||||
|
||||
mov edi, in_dst
|
||||
|
||||
mov [storeebp], ebp
|
||||
xor ebp, ebp
|
||||
procPointLp2_fc:
|
||||
; This could be faster
|
||||
mov esi, [srcIndices]
|
||||
lea esi, [esi + ebp*4]
|
||||
mov eax, dword [esi]
|
||||
shl eax, 4 ; idx *= 16
|
||||
mov esi, [srcPoints]
|
||||
lea esi, [esi + eax]
|
||||
|
||||
mov eax, [esi + 0] ; x
|
||||
mov ebx, [esi + 4] ; y
|
||||
mov ecx, [esi + 8] ; z
|
||||
mov edx, [esi + 12] ; fc
|
||||
mov [edi + 0], eax ; <- x
|
||||
mov [edi + 4], ebx ; <- y
|
||||
mov [edi + 8], ecx ; <- z
|
||||
mov [edi + 24], edx ; <- fc (lmcoord.x)
|
||||
mov edx, [srcColors] ; color
|
||||
lea edx, [edx + ebp*4] ; color
|
||||
mov edx, [edx] ; color
|
||||
mov [edi + 12], edx ; color
|
||||
|
||||
; tc0.s
|
||||
fld dword [_texGen0 + 0] ; tg0.s.x
|
||||
fmul dword [esi + 0]
|
||||
fld dword [_texGen0 + 4] ; tg0.s.y
|
||||
fmul dword [esi + 4]
|
||||
fld dword [_texGen0 + 8] ; tg0.s.z
|
||||
fmul dword [esi + 8]
|
||||
fld dword [_texGen0 + 12] ; tg0.s.w
|
||||
faddp st3, st0
|
||||
faddp st1, st0
|
||||
faddp st1, st0
|
||||
fstp dword [edi + 16] ; tc0.s
|
||||
|
||||
; tc0.t
|
||||
fld dword [_texGen0 + 16] ; tg0.t.x
|
||||
fmul dword [esi + 0]
|
||||
fld dword [_texGen0 + 20] ; tg0.t.y
|
||||
fmul dword [esi + 4]
|
||||
fld dword [_texGen0 + 24] ; tg0.t.z
|
||||
fmul dword [esi + 8]
|
||||
fld dword [_texGen0 + 28] ; tg0.t.w
|
||||
faddp st3, st0
|
||||
faddp st1, st0
|
||||
faddp st1, st0
|
||||
fstp dword [edi + 20] ; tc0.t
|
||||
|
||||
add edi, 32
|
||||
|
||||
inc ebp
|
||||
cmp ebp, [numPoints]
|
||||
jl near procPointLp2_fc
|
||||
|
||||
mov ebp, [storeebp]
|
||||
|
||||
; epilogue
|
||||
pop esi
|
||||
pop edi
|
||||
pop ecx
|
||||
pop ebx
|
||||
pop eax
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
|
||||
; CodeWarrior still sucks :P
|
||||
%ifdef LINUX
|
||||
global processTriFanFC_VB
|
||||
|
||||
processTriFanFC_VB:
|
||||
%else
|
||||
global _processTriFanFC_VB
|
||||
|
||||
_processTriFanFC_VB:
|
||||
%endif
|
||||
|
||||
; prologue
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push eax
|
||||
push ebx
|
||||
push ecx
|
||||
push edi
|
||||
push esi
|
||||
|
||||
; Store the destination and source pointers
|
||||
mov eax, in_src_points
|
||||
mov [srcPoints], eax
|
||||
mov eax, in_src_indices
|
||||
mov [srcIndices], eax
|
||||
mov eax, in_numpoints
|
||||
mov [numPoints], eax
|
||||
|
||||
mov edi, in_dst
|
||||
|
||||
mov [storeebp], ebp
|
||||
xor ebp, ebp
|
||||
procPointLp1_fc_vb:
|
||||
; This could be faster
|
||||
mov esi, [srcIndices]
|
||||
lea esi, [esi + ebp*4]
|
||||
mov eax, dword [esi]
|
||||
shl eax, 4 ; idx *= 16
|
||||
mov esi, [srcPoints]
|
||||
lea esi, [esi + eax]
|
||||
|
||||
mov eax, [esi + 0] ; x
|
||||
mov ebx, [esi + 4] ; y
|
||||
mov ecx, [esi + 8] ; z
|
||||
mov edx, 0xFFFFFFFF ; c
|
||||
mov [edi + 0], eax ; <- x
|
||||
mov [edi + 4], ebx ; <- y
|
||||
mov [edi + 8], ecx ; <- z
|
||||
mov [edi + 12], edx ; <- c
|
||||
|
||||
fld dword [esi + 12]
|
||||
fld dword [two55]
|
||||
fmulp st1, st0
|
||||
fistp dword [alpha]
|
||||
mov eax, 255
|
||||
sub eax, [alpha]
|
||||
cmp eax, 0
|
||||
jge near procPointLp1a_fc_vb
|
||||
mov eax, 0
|
||||
procPointLp1a_fc_vb:
|
||||
shl eax, 24
|
||||
mov [edi + 16], eax ; <- f
|
||||
|
||||
; tc0.s
|
||||
fld dword [_texGen0 + 0] ; tg0.s.x
|
||||
fmul dword [esi + 0]
|
||||
fld dword [_texGen0 + 4] ; tg0.s.y
|
||||
fmul dword [esi + 4]
|
||||
fld dword [_texGen0 + 8] ; tg0.s.z
|
||||
fmul dword [esi + 8]
|
||||
fld dword [_texGen0 + 12] ; tg0.s.w
|
||||
faddp st3, st0
|
||||
faddp st1, st0
|
||||
faddp st1, st0
|
||||
fstp dword [edi + 28] ; tc0.s
|
||||
|
||||
; tc0.t
|
||||
fld dword [_texGen0 + 16] ; tg0.t.x
|
||||
fmul dword [esi + 0]
|
||||
fld dword [_texGen0 + 20] ; tg0.t.y
|
||||
fmul dword [esi + 4]
|
||||
fld dword [_texGen0 + 24] ; tg0.t.z
|
||||
fmul dword [esi + 8]
|
||||
fld dword [_texGen0 + 28] ; tg0.t.w
|
||||
faddp st3, st0
|
||||
faddp st1, st0
|
||||
faddp st1, st0
|
||||
fstp dword [edi + 32] ; tc0.t
|
||||
|
||||
; tc1.s
|
||||
fld dword [_texGen1 + 0] ; tg1.s.x
|
||||
fmul dword [esi + 0]
|
||||
fld dword [_texGen1 + 4] ; tg1.s.y
|
||||
fmul dword [esi + 4]
|
||||
fld dword [_texGen1 + 8] ; tg1.s.z
|
||||
fmul dword [esi + 8]
|
||||
fld dword [_texGen1 + 12] ; tg1.s.w
|
||||
faddp st3, st0
|
||||
faddp st1, st0
|
||||
faddp st1, st0
|
||||
fstp dword [edi + 20] ; tc1.s
|
||||
|
||||
; tc1.t
|
||||
fld dword [_texGen1 + 16] ; tg1.t.x
|
||||
fmul dword [esi + 0]
|
||||
fld dword [_texGen1 + 20] ; tg1.t.y
|
||||
fmul dword [esi + 4]
|
||||
fld dword [_texGen1 + 24] ; tg1.t.z
|
||||
fmul dword [esi + 8]
|
||||
fld dword [_texGen1 + 28] ; tg1.t.w
|
||||
faddp st3, st0
|
||||
faddp st1, st0
|
||||
faddp st1, st0
|
||||
fstp dword [edi + 24] ; tc1.t
|
||||
|
||||
add edi, 36
|
||||
|
||||
inc ebp
|
||||
cmp ebp, [numPoints]
|
||||
jl near procPointLp1_fc_vb
|
||||
|
||||
mov ebp, [storeebp]
|
||||
|
||||
; epilogue
|
||||
pop esi
|
||||
pop edi
|
||||
pop ecx
|
||||
pop ebx
|
||||
pop eax
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
|
||||
; More suckagea
|
||||
%ifdef LINUX
|
||||
global processTriFanSP_FC_VB
|
||||
|
||||
processTriFanSP_FC_VB:
|
||||
%else
|
||||
global _processTriFanSP_FC_VB
|
||||
|
||||
_processTriFanSP_FC_VB:
|
||||
%endif
|
||||
|
||||
; prologue
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push eax
|
||||
push ebx
|
||||
push ecx
|
||||
push edi
|
||||
push esi
|
||||
|
||||
; Store the destination and source pointers
|
||||
mov eax, in_src_points
|
||||
mov [srcPoints], eax
|
||||
mov eax, in_src_indices
|
||||
mov [srcIndices], eax
|
||||
mov eax, in_numpoints
|
||||
mov [numPoints], eax
|
||||
mov eax, in_srcColors
|
||||
mov [srcColors], eax
|
||||
|
||||
mov edi, in_dst
|
||||
|
||||
mov [storeebp], ebp
|
||||
xor ebp, ebp
|
||||
procPointLp2_fc_vb:
|
||||
; This could be faster
|
||||
mov esi, [srcIndices]
|
||||
lea esi, [esi + ebp*4]
|
||||
mov eax, dword [esi]
|
||||
shl eax, 4 ; idx *= 16
|
||||
mov esi, [srcPoints]
|
||||
lea esi, [esi + eax]
|
||||
|
||||
mov eax, [esi + 0] ; x
|
||||
mov ebx, [esi + 4] ; y
|
||||
mov ecx, [esi + 8] ; z
|
||||
mov [edi + 0], eax ; <- x
|
||||
mov [edi + 4], ebx ; <- y
|
||||
mov [edi + 8], ecx ; <- z
|
||||
|
||||
fld dword [esi + 12]
|
||||
fld dword [two55]
|
||||
fmulp st1, st0
|
||||
fistp dword [alpha]
|
||||
mov eax, 255
|
||||
sub eax, [alpha]
|
||||
cmp eax, 0
|
||||
jge near procPointLp2a_fc_vb
|
||||
mov eax, 0
|
||||
procPointLp2a_fc_vb:
|
||||
shl eax, 24
|
||||
mov [edi + 16], eax ; <- fc
|
||||
|
||||
mov edx, [srcColors] ; color
|
||||
lea edx, [edx + ebp*4] ; color
|
||||
mov edx, [edx] ; color
|
||||
mov eax, edx
|
||||
mov ebx, 0x00FF00FF
|
||||
and edx, ebx
|
||||
not ebx
|
||||
rol edx, 16
|
||||
and eax, ebx
|
||||
or edx, eax
|
||||
mov [edi + 12], edx ; color
|
||||
|
||||
; tc0.s
|
||||
fld dword [_texGen0 + 0] ; tg0.s.x
|
||||
fmul dword [esi + 0]
|
||||
fld dword [_texGen0 + 4] ; tg0.s.y
|
||||
fmul dword [esi + 4]
|
||||
fld dword [_texGen0 + 8] ; tg0.s.z
|
||||
fmul dword [esi + 8]
|
||||
fld dword [_texGen0 + 12] ; tg0.s.w
|
||||
faddp st3, st0
|
||||
faddp st1, st0
|
||||
faddp st1, st0
|
||||
fstp dword [edi + 20] ; tc0.s
|
||||
|
||||
; tc0.t
|
||||
fld dword [_texGen0 + 16] ; tg0.t.x
|
||||
fmul dword [esi + 0]
|
||||
fld dword [_texGen0 + 20] ; tg0.t.y
|
||||
fmul dword [esi + 4]
|
||||
fld dword [_texGen0 + 24] ; tg0.t.z
|
||||
fmul dword [esi + 8]
|
||||
fld dword [_texGen0 + 28] ; tg0.t.w
|
||||
faddp st3, st0
|
||||
faddp st1, st0
|
||||
faddp st1, st0
|
||||
fstp dword [edi + 24] ; tc0.t
|
||||
|
||||
add edi, 28
|
||||
|
||||
inc ebp
|
||||
cmp ebp, [numPoints]
|
||||
jl near procPointLp2_fc_vb
|
||||
|
||||
mov ebp, [storeebp]
|
||||
|
||||
; epilogue
|
||||
pop esi
|
||||
pop edi
|
||||
pop ecx
|
||||
pop ebx
|
||||
pop eax
|
||||
pop ebp
|
||||
ret
|
310
engine/interior/itfdump_c.cc
Executable file
310
engine/interior/itfdump_c.cc
Executable file
@ -0,0 +1,310 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "interior/itf.h"
|
||||
|
||||
//two55 dd 0x437F0000
|
||||
//alpha dd 0
|
||||
|
||||
//============================================================
|
||||
void FN_CDECL processTriFan(OutputPoint* dst,
|
||||
const ItrPaddedPoint* srcPoints,
|
||||
const U32* srcIndices,
|
||||
const U32 numIndices)
|
||||
{
|
||||
U32 i, j;
|
||||
F32 x,y,z;
|
||||
for (i=0; i<numIndices; i++)
|
||||
{
|
||||
j = srcIndices[i];
|
||||
x = srcPoints[j].point.x;
|
||||
y = srcPoints[j].point.y;
|
||||
z = srcPoints[j].point.z;
|
||||
|
||||
dst->point.x = x;
|
||||
dst->point.y = y;
|
||||
dst->point.z = z;
|
||||
dst->fogCoord = srcPoints[j].fogCoord;
|
||||
|
||||
dst->texCoord.x = (texGen0[0]*x)
|
||||
+ (texGen0[1]*y)
|
||||
+ (texGen0[2]*z)
|
||||
+ (texGen0[3]);
|
||||
|
||||
dst->texCoord.y = (texGen0[4]*x)
|
||||
+ (texGen0[5]*y)
|
||||
+ (texGen0[6]*z)
|
||||
+ (texGen0[7]);
|
||||
|
||||
dst->lmCoord.x = (texGen1[0]*x)
|
||||
+ (texGen1[1]*y)
|
||||
+ (texGen1[2]*z)
|
||||
+ (texGen1[3]);
|
||||
|
||||
dst->lmCoord.y = (texGen1[4]*x)
|
||||
+ (texGen1[5]*y)
|
||||
+ (texGen1[6]*z)
|
||||
+ (texGen1[7]);
|
||||
|
||||
// move to next ptr.
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================
|
||||
void FN_CDECL processTriFanSP(OutputPoint* dst,
|
||||
const ItrPaddedPoint* srcPoints,
|
||||
const U32* srcIndices,
|
||||
const U32 numIndices,
|
||||
const ColorI* srcColors)
|
||||
{
|
||||
U32 i, j;
|
||||
float x,y,z;
|
||||
for (i=0; i<numIndices; i++)
|
||||
{
|
||||
j = srcIndices[i];
|
||||
x = srcPoints[j].point.x;
|
||||
y = srcPoints[j].point.y;
|
||||
z = srcPoints[j].point.z;
|
||||
|
||||
dst->point.x = x;
|
||||
dst->point.y = y;
|
||||
dst->point.z = z;
|
||||
dst->fogColors = srcColors[j].getARGBEndian();
|
||||
|
||||
dst->texCoord.x = (texGen0[0]*x)
|
||||
+ (texGen0[1]*y)
|
||||
+ (texGen0[2]*z)
|
||||
+ (texGen0[3]);
|
||||
|
||||
dst->texCoord.y = (texGen0[4]*x)
|
||||
+ (texGen0[5]*y)
|
||||
+ (texGen0[6]*z)
|
||||
+ (texGen0[7]);
|
||||
// move to next ptr.
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================
|
||||
void FN_CDECL processTriFanVC_TF(OutputPoint* dst,
|
||||
const ItrPaddedPoint* srcPoints,
|
||||
const U32* srcIndices,
|
||||
const U32 numIndices,
|
||||
const ColorI* srcColors)
|
||||
{
|
||||
U32 i, j;
|
||||
float x,y,z;
|
||||
for (i=0; i<numIndices; i++)
|
||||
{
|
||||
j = srcIndices[i];
|
||||
x = srcPoints[j].point.x;
|
||||
y = srcPoints[j].point.y;
|
||||
z = srcPoints[j].point.z;
|
||||
|
||||
dst->point.x = x;
|
||||
dst->point.y = y;
|
||||
dst->point.z = z;
|
||||
dst->fogColors = srcColors[j].getARGBEndian();
|
||||
|
||||
// dc - I >think< I got this right...
|
||||
dst->texCoord.x = fogCoordinatePointer[j].x;
|
||||
dst->texCoord.y = fogCoordinatePointer[j].y;
|
||||
|
||||
dst->lmCoord.x = (texGen0[0]*x)
|
||||
+ (texGen0[1]*y)
|
||||
+ (texGen0[2]*z)
|
||||
+ (texGen0[3]);
|
||||
|
||||
dst->lmCoord.y = (texGen0[4]*x)
|
||||
+ (texGen0[5]*y)
|
||||
+ (texGen0[6]*z)
|
||||
+ (texGen0[7]);
|
||||
// move to next ptr.
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================
|
||||
void FN_CDECL processTriFanSP_FC(OutputPoint* dst,
|
||||
const ItrPaddedPoint* srcPoints,
|
||||
const U32* srcIndices,
|
||||
const U32 numIndices,
|
||||
const ColorI* srcColors)
|
||||
{
|
||||
U32 i, j;
|
||||
float x,y,z;
|
||||
for (i=0; i<numIndices; i++)
|
||||
{
|
||||
j = srcIndices[i];
|
||||
x = srcPoints[j].point.x;
|
||||
y = srcPoints[j].point.y;
|
||||
z = srcPoints[j].point.z;
|
||||
|
||||
dst->point.x = x;
|
||||
dst->point.y = y;
|
||||
dst->point.z = z;
|
||||
dst->fogColors = srcColors[j].getARGBEndian();
|
||||
dst->lmCoord.x = srcPoints[j].fogCoord;
|
||||
|
||||
dst->texCoord.x = (texGen0[0]*x)
|
||||
+ (texGen0[1]*y)
|
||||
+ (texGen0[2]*z)
|
||||
+ (texGen0[3]);
|
||||
|
||||
dst->texCoord.y = (texGen0[4]*x)
|
||||
+ (texGen0[5]*y)
|
||||
+ (texGen0[6]*z)
|
||||
+ (texGen0[7]);
|
||||
// move to next ptr.
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================
|
||||
// helpers:
|
||||
const float two55 = (F32)0x473F0000; // !!!!!!TBD -- not sure this is right...
|
||||
|
||||
#define ALPHA_CALC(a, c) \
|
||||
a = c * two55; \
|
||||
a = 255 - a; /* flip direction of value. */ \
|
||||
if (a < 0) a = 0;
|
||||
|
||||
/* ASM for previous calculation:
|
||||
fld dword [esi + 12]
|
||||
fld dword [two55]
|
||||
fmulp st1, st0
|
||||
fistp dword [alpha]
|
||||
mov eax, 255
|
||||
sub eax, [alpha]
|
||||
cmp eax, 0
|
||||
jge near procPointLp1a_fc_vb
|
||||
mov eax, 0
|
||||
procPointLp1a_fc_vb:
|
||||
shl eax, 24 // left this in the function instead of the macro.
|
||||
mov [edi + 16], eax ; <- f
|
||||
*/
|
||||
|
||||
|
||||
//============================================================
|
||||
void FN_CDECL processTriFanFC_VB(OutputPointFC_VB* dst,
|
||||
const ItrPaddedPoint* srcPoints,
|
||||
const U32* srcIndices,
|
||||
const U32 numIndices)
|
||||
{
|
||||
S32 alpha;
|
||||
U32 i, j;
|
||||
float x,y,z;
|
||||
for (i=0; i<numIndices; i++)
|
||||
{
|
||||
j = srcIndices[i];
|
||||
x = srcPoints[j].point.x;
|
||||
y = srcPoints[j].point.y;
|
||||
z = srcPoints[j].point.z;
|
||||
|
||||
dst->point.x = x;
|
||||
dst->point.y = y;
|
||||
dst->point.z = z;
|
||||
dst->currentColors = 0xFFFFFFFF;
|
||||
|
||||
ALPHA_CALC(alpha, srcPoints[j].fogCoord);
|
||||
dst->fogColors = ((U32)alpha)<<24; // move into alpha position.
|
||||
|
||||
// dc - note the texGens are used in reverse order. that's what the ASM did...
|
||||
dst->texCoord.x = (texGen1[0]*x)
|
||||
+ (texGen1[1]*y)
|
||||
+ (texGen1[2]*z)
|
||||
+ (texGen1[3]);
|
||||
|
||||
dst->texCoord.y = (texGen1[4]*x)
|
||||
+ (texGen1[5]*y)
|
||||
+ (texGen1[6]*z)
|
||||
+ (texGen1[7]);
|
||||
|
||||
dst->lmCoord.x = (texGen0[0]*x)
|
||||
+ (texGen0[1]*y)
|
||||
+ (texGen0[2]*z)
|
||||
+ (texGen0[3]);
|
||||
|
||||
dst->lmCoord.y = (texGen0[4]*x)
|
||||
+ (texGen0[5]*y)
|
||||
+ (texGen0[6]*z)
|
||||
+ (texGen0[7]);
|
||||
|
||||
// move to next ptr.
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//!!!!!!TBD -- is there a rotate intrinsic?????
|
||||
#define ROL16(x) (x) = ((((x)<<16)&0xFFFF0000) | (((x)>>16)&0x0000FFFF))
|
||||
|
||||
//============================================================
|
||||
void FN_CDECL processTriFanSP_FC_VB(OutputPointSP_FC_VB* dst,
|
||||
const ItrPaddedPoint* srcPoints,
|
||||
const U32* srcIndices,
|
||||
const U32 numIndices,
|
||||
const ColorI* srcColors)
|
||||
{
|
||||
S32 alpha;
|
||||
U32 i, j, tmp, tmp2;
|
||||
float x,y,z;
|
||||
for (i=0; i<numIndices; i++)
|
||||
{
|
||||
j = srcIndices[i];
|
||||
x = srcPoints[j].point.x;
|
||||
y = srcPoints[j].point.y;
|
||||
z = srcPoints[j].point.z;
|
||||
|
||||
dst->point.x = x;
|
||||
dst->point.y = y;
|
||||
dst->point.z = z;
|
||||
|
||||
/*
|
||||
mov edx, [srcColors] ; color
|
||||
lea edx, [edx + ebp*4] ; color
|
||||
mov edx, [edx] ; color
|
||||
mov eax, edx
|
||||
mov ebx, 0x00FF00FF
|
||||
and edx, ebx
|
||||
not ebx
|
||||
and eax, ebx
|
||||
rol edx, 16
|
||||
or edx, eax
|
||||
mov [edi + 12], edx ; color
|
||||
*/
|
||||
|
||||
tmp = srcColors[j].getARGBEndian();
|
||||
tmp2 = tmp;
|
||||
|
||||
tmp = (tmp & 0x00FF00FF);
|
||||
tmp2 = (tmp2 & 0xFF00FF00);
|
||||
|
||||
ROL16(tmp);
|
||||
|
||||
dst->lmColors = (tmp | tmp2);
|
||||
|
||||
ALPHA_CALC(alpha, srcPoints[j].fogCoord);
|
||||
dst->fogColors = ((U32)alpha)<<24; // move into alpha position.
|
||||
|
||||
dst->texCoord.x = (texGen0[0]*x)
|
||||
+ (texGen0[1]*y)
|
||||
+ (texGen0[2]*z)
|
||||
+ (texGen0[3]);
|
||||
|
||||
dst->texCoord.y = (texGen0[4]*x)
|
||||
+ (texGen0[5]*y)
|
||||
+ (texGen0[6]*z)
|
||||
+ (texGen0[7]);
|
||||
// move to next ptr.
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
|
75
engine/interior/lightUpdateGrouper.cc
Executable file
75
engine/interior/lightUpdateGrouper.cc
Executable file
@ -0,0 +1,75 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "interior/lightUpdateGrouper.h"
|
||||
|
||||
LightUpdateGrouper::LightUpdateGrouper(const U32 bitStart, const U32 bitEnd)
|
||||
{
|
||||
AssertFatal(bitEnd >= bitStart, "Error, bitend must be greater than bit start");
|
||||
AssertFatal(bitEnd < 32, "Error, bitend too large. must be in the range 0..31");
|
||||
|
||||
mBitStart = bitStart;
|
||||
mBitEnd = bitEnd;
|
||||
}
|
||||
|
||||
|
||||
LightUpdateGrouper::~LightUpdateGrouper()
|
||||
{
|
||||
mBitStart = 0xFFFFFFFF;
|
||||
mBitEnd = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
|
||||
void LightUpdateGrouper::addKey(const U32 key)
|
||||
{
|
||||
#ifdef TORQUE_DEBUG
|
||||
for (U32 i = 0; i < mKeys.size(); i++)
|
||||
AssertFatal(mKeys[i] != key, "Error, key already in the array!");
|
||||
#endif
|
||||
|
||||
mKeys.push_back(key);
|
||||
}
|
||||
|
||||
U32 LightUpdateGrouper::getKeyMask(const U32 key) const
|
||||
{
|
||||
U32 numBits = mBitEnd - mBitStart + 1;
|
||||
for (U32 i = 0; i < mKeys.size(); i++) {
|
||||
if (mKeys[i] == key) {
|
||||
U32 idx = i % numBits;
|
||||
return (1 << (idx + mBitStart));
|
||||
}
|
||||
}
|
||||
|
||||
AssertFatal(false, "Error, key not in the array!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
LightUpdateGrouper::BitIterator LightUpdateGrouper::begin()
|
||||
{
|
||||
BitIterator itr;
|
||||
itr.mGrouper = this;
|
||||
itr.mCurrBit = mBitStart;
|
||||
itr.resetKeyArray();
|
||||
|
||||
return itr;
|
||||
}
|
||||
|
||||
void LightUpdateGrouper::BitIterator::resetKeyArray()
|
||||
{
|
||||
mKeyArray.clear();
|
||||
if (valid() == false)
|
||||
return;
|
||||
|
||||
// Ok, we need to select out every (mBitEnd - mBitStart - 1)th key,
|
||||
// starting at mCurrBit.
|
||||
|
||||
U32 numBits = mGrouper->mBitEnd - mGrouper->mBitStart + 1;
|
||||
U32 numKeys = mGrouper->mKeys.size();
|
||||
|
||||
for (U32 i = mCurrBit - mGrouper->mBitStart; i < numKeys; i += numBits) {
|
||||
mKeyArray.push_back(mGrouper->mKeys[i]);
|
||||
}
|
||||
}
|
||||
|
106
engine/interior/lightUpdateGrouper.h
Executable file
106
engine/interior/lightUpdateGrouper.h
Executable file
@ -0,0 +1,106 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _LIGHTUPDATEGROUPER_H_
|
||||
#define _LIGHTUPDATEGROUPER_H_
|
||||
|
||||
#ifndef _PLATFORM_H_
|
||||
#include "platform/platform.h"
|
||||
#endif
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/tVector.h"
|
||||
#endif
|
||||
|
||||
class LightUpdateGrouper
|
||||
{
|
||||
Vector<U32> mKeys;
|
||||
U32 mBitStart;
|
||||
U32 mBitEnd;
|
||||
|
||||
public:
|
||||
class BitIterator {
|
||||
friend class LightUpdateGrouper;
|
||||
|
||||
private:
|
||||
Vector<U32> mKeyArray;
|
||||
U32 mCurrBit;
|
||||
LightUpdateGrouper* mGrouper;
|
||||
|
||||
void resetKeyArray();
|
||||
|
||||
public:
|
||||
typedef U32 const* iterator;
|
||||
|
||||
bool valid();
|
||||
U32 getNumKeys();
|
||||
U32 getMask();
|
||||
|
||||
BitIterator& operator++(int);
|
||||
BitIterator& operator++();
|
||||
|
||||
iterator begin();
|
||||
iterator end();
|
||||
};
|
||||
friend class BitIterator;
|
||||
|
||||
public:
|
||||
LightUpdateGrouper(const U32 bitStart, const U32 bitEnd);
|
||||
~LightUpdateGrouper();
|
||||
|
||||
void addKey(const U32 key);
|
||||
U32 getKeyMask(const U32 key) const;
|
||||
|
||||
BitIterator begin();
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline LightUpdateGrouper::BitIterator& LightUpdateGrouper::BitIterator::operator++()
|
||||
{
|
||||
mCurrBit++;
|
||||
resetKeyArray();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline LightUpdateGrouper::BitIterator& LightUpdateGrouper::BitIterator::operator++(int)
|
||||
{
|
||||
return operator++();
|
||||
}
|
||||
|
||||
inline LightUpdateGrouper::BitIterator::iterator LightUpdateGrouper::BitIterator::begin()
|
||||
{
|
||||
if (valid() == false)
|
||||
return NULL;
|
||||
|
||||
return mKeyArray.begin();
|
||||
}
|
||||
|
||||
inline LightUpdateGrouper::BitIterator::iterator LightUpdateGrouper::BitIterator::end()
|
||||
{
|
||||
if (valid() == false)
|
||||
return NULL;
|
||||
|
||||
return mKeyArray.end();
|
||||
}
|
||||
|
||||
inline bool LightUpdateGrouper::BitIterator::valid()
|
||||
{
|
||||
return mCurrBit <= mGrouper->mBitEnd;
|
||||
}
|
||||
|
||||
inline U32 LightUpdateGrouper::BitIterator::getNumKeys()
|
||||
{
|
||||
return mKeyArray.size();
|
||||
}
|
||||
|
||||
inline U32 LightUpdateGrouper::BitIterator::getMask()
|
||||
{
|
||||
return (1 << mCurrBit);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // _H_LIGHTUPDATEGROUPER_
|
501
engine/interior/mirrorSubObject.cc
Executable file
501
engine/interior/mirrorSubObject.cc
Executable file
@ -0,0 +1,501 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//
|
||||
// 09/03/03 MM: Changes made by JF to use a stencil mask for mirrors.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "interior/mirrorSubObject.h"
|
||||
#include "interior/interiorInstance.h"
|
||||
#include "interior/interior.h"
|
||||
#include "dgl/materialList.h"
|
||||
#include "core/stream.h"
|
||||
#include "dgl/dgl.h"
|
||||
#include "sceneGraph/sgUtil.h"
|
||||
|
||||
|
||||
IMPLEMENT_CONOBJECT(MirrorSubObject);
|
||||
|
||||
#include "platform/platformVideo.h"
|
||||
#include "sceneGraph/sceneGraph.h"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
MirrorSubObject::MirrorSubObject()
|
||||
{
|
||||
mTypeMask = StaticObjectType;
|
||||
|
||||
mInitialized = false;
|
||||
}
|
||||
|
||||
MirrorSubObject::~MirrorSubObject()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void MirrorSubObject::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
|
||||
//
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void MirrorSubObject::renderObject(SceneState* state, SceneRenderImage* image)
|
||||
{
|
||||
// the surface is rendered when the portal is closed
|
||||
return;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void MirrorSubObject::transformModelview(const U32 portalIndex, const MatrixF& oldMV,
|
||||
MatrixF* pNewMV)
|
||||
{
|
||||
AssertFatal(isInitialized() == true, "Error, we should have been initialized by this point!");
|
||||
AssertFatal(portalIndex == 0, "Error, we only have one portal!");
|
||||
|
||||
*pNewMV = oldMV;
|
||||
pNewMV->mul(mReflectionMatrix);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void MirrorSubObject::transformPosition(const U32 portalIndex, Point3F& ioPosition)
|
||||
{
|
||||
AssertFatal(isInitialized() == true, "Error, we should have been initialized by this point!");
|
||||
AssertFatal(portalIndex == 0, "Error, we only have one portal!");
|
||||
|
||||
mReflectionMatrix.mulP(ioPosition);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool MirrorSubObject::computeNewFrustum(const U32 portalIndex,
|
||||
const F64* oldFrustum,
|
||||
const F64 nearPlane,
|
||||
const F64 farPlane,
|
||||
const RectI& oldViewport,
|
||||
F64* newFrustum,
|
||||
RectI& newViewport,
|
||||
const bool flippedMatrix)
|
||||
{
|
||||
AssertFatal(isInitialized() == true, "Error, we should have been initialized by this point!");
|
||||
AssertFatal(portalIndex == 0, "Error, mirrortests only have one portal!");
|
||||
|
||||
Interior* interior = getInstance()->getDetailLevel(mDetailLevel);
|
||||
|
||||
static Vector<SGWinding> mirrorWindings;
|
||||
mirrorWindings.setSize(surfaceCount);
|
||||
|
||||
for (U32 i = 0; i < surfaceCount; i++) {
|
||||
SGWinding& rSGWinding = mirrorWindings[i];
|
||||
const Interior::Surface& rSurface = interior->mSurfaces[surfaceStart + i];
|
||||
|
||||
U32 fanIndices[32];
|
||||
U32 numFanIndices = 0;
|
||||
interior->collisionFanFromSurface(rSurface, fanIndices, &numFanIndices);
|
||||
|
||||
for (U32 j = 0; j < numFanIndices; j++)
|
||||
rSGWinding.points[j] = interior->mPoints[fanIndices[j]].point;
|
||||
rSGWinding.numPoints = numFanIndices;
|
||||
}
|
||||
|
||||
MatrixF finalModelView;
|
||||
dglGetModelview(&finalModelView);
|
||||
finalModelView.mul(getSOTransform());
|
||||
finalModelView.scale(getSOScale());
|
||||
|
||||
return sgComputeNewFrustum(oldFrustum, nearPlane, farPlane,
|
||||
oldViewport,
|
||||
mirrorWindings.address(), mirrorWindings.size(),
|
||||
finalModelView,
|
||||
newFrustum, newViewport,
|
||||
flippedMatrix);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void MirrorSubObject::openPortal(const U32 portalIndex,
|
||||
SceneState* pCurrState,
|
||||
SceneState* pParentState)
|
||||
{
|
||||
AssertFatal(isInitialized() == true, "Error, we should have been initialized by this point!");
|
||||
AssertFatal(portalIndex == 0, "Error, mirrortests only have one portal!");
|
||||
|
||||
if (mZone == 0)
|
||||
pParentState->setupZoneProjection(getInstance()->getCurrZone(0));
|
||||
else
|
||||
pParentState->setupZoneProjection(mZone + getInstance()->getZoneRangeStart() - 1);
|
||||
|
||||
// setup transformation
|
||||
glPushMatrix();
|
||||
dglMultMatrix(&getSOTransform());
|
||||
glScalef(getSOScale().x, getSOScale().y, getSOScale().z);
|
||||
|
||||
// setup stencil buffer:
|
||||
glClearStencil(0x0);
|
||||
glStencilMask(~0u);
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
|
||||
static U32 lastStateKey = 0;
|
||||
U32 stateKey = gClientSceneGraph->getStateKey();
|
||||
|
||||
// dont clear the stencil for every portal
|
||||
if(lastStateKey != stateKey)
|
||||
{
|
||||
lastStateKey = stateKey;
|
||||
glClear(GL_STENCIL_BUFFER_BIT);
|
||||
}
|
||||
|
||||
// clear with the fog color
|
||||
ColorF fogColor = gClientSceneGraph->getFogColor();
|
||||
glColor3f(fogColor.red, fogColor.green, fogColor.blue);
|
||||
|
||||
Interior * interior = getInstance()->getDetailLevel(mDetailLevel);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(ItrPaddedPoint), interior->mPoints.address());
|
||||
|
||||
|
||||
// render the visible surface into the stencil buffer (also render the fog color
|
||||
// since terrain may not be rendered and it assumes a fog clear)
|
||||
glStencilFunc(GL_ALWAYS, 1, 0xffffffff);
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
|
||||
|
||||
for (U32 i = 0; i < surfaceCount; i++)
|
||||
{
|
||||
glDrawElements(GL_TRIANGLE_STRIP,
|
||||
interior->mSurfaces[surfaceStart+i].windingCount,
|
||||
GL_UNSIGNED_INT,
|
||||
&interior->mWindings[interior->mSurfaces[surfaceStart+i].windingStart]);
|
||||
}
|
||||
|
||||
// now clear the visible surface depth (use stencil). disable color buffers (already
|
||||
// rendered fog in previous step).
|
||||
glDepthRange(1, 1);
|
||||
glDepthFunc(GL_ALWAYS);
|
||||
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
||||
|
||||
glStencilFunc(GL_EQUAL, 1, 0xffffffff);
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
||||
|
||||
for (U32 i = 0; i < surfaceCount; i++)
|
||||
{
|
||||
glDrawElements(GL_TRIANGLE_STRIP,
|
||||
interior->mSurfaces[surfaceStart+i].windingCount,
|
||||
GL_UNSIGNED_INT,
|
||||
&interior->mWindings[interior->mSurfaces[surfaceStart+i].windingStart]);
|
||||
}
|
||||
|
||||
// reset states (stencil is setup correctly)
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
glDepthRange(0, 1);
|
||||
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
// reset transform
|
||||
glPopMatrix();
|
||||
dglSetCanonicalState();
|
||||
}
|
||||
|
||||
void MirrorSubObject::closePortal(const U32 portalIndex,
|
||||
SceneState* pCurrState,
|
||||
SceneState* pParentState)
|
||||
{
|
||||
AssertFatal(isInitialized() == true, "Error, we should have been initialized by this point!");
|
||||
AssertFatal(portalIndex == 0, "Error, mirrortests only have one portal!");
|
||||
|
||||
// setup transformation
|
||||
glPushMatrix();
|
||||
dglMultMatrix(&getSOTransform());
|
||||
glScalef(getSOScale().x, getSOScale().y, getSOScale().z);
|
||||
|
||||
// update depth over portal
|
||||
Interior * interior = getInstance()->getDetailLevel(mDetailLevel);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(ItrPaddedPoint), interior->mPoints.address());
|
||||
|
||||
|
||||
// want to clear stencil value
|
||||
glStencilFunc(GL_EQUAL, 1, 0xffffffff);
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
|
||||
|
||||
// render the alpha surface
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
|
||||
glActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
glEnable(GL_TEXTURE_GEN_S);
|
||||
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
|
||||
glEnable(GL_TEXTURE_GEN_T);
|
||||
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
|
||||
|
||||
glActiveTextureARB(GL_TEXTURE1_ARB);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
glEnable(GL_TEXTURE_GEN_S);
|
||||
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
|
||||
glEnable(GL_TEXTURE_GEN_T);
|
||||
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
|
||||
|
||||
glActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, interior->mMaterialList->getMaterial(interior->mSurfaces[surfaceStart].textureIndex).getGLName());
|
||||
|
||||
|
||||
glActiveTextureARB(GL_TEXTURE1_ARB);
|
||||
Vector<U32>* pLMapIndices = &interior->mNormalLMapIndices;
|
||||
U32 baseIndex = (*pLMapIndices)[surfaceStart];
|
||||
TextureHandle *tex = gInteriorLMManager.getHandle( interior->mLMHandle, getInstance()->getLMHandle(), baseIndex);
|
||||
glBindTexture(GL_TEXTURE_2D, tex->getGLName() );
|
||||
|
||||
|
||||
|
||||
glActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
glTexGenfv(GL_S, GL_OBJECT_PLANE, (GLfloat*)interior->mTexGenEQs[interior->mSurfaces[surfaceStart].texGenIndex].planeX);
|
||||
glTexGenfv(GL_T, GL_OBJECT_PLANE, (GLfloat*)interior->mTexGenEQs[interior->mSurfaces[surfaceStart].texGenIndex].planeY);
|
||||
|
||||
glActiveTextureARB(GL_TEXTURE1_ARB);
|
||||
|
||||
|
||||
glColor4f(1, 1, 1, mAlphaLevel);
|
||||
|
||||
for (U32 i = 0; i < surfaceCount; i++) {
|
||||
|
||||
glTexGenfv(GL_S, GL_OBJECT_PLANE, (GLfloat*)interior->mLMTexGenEQs[surfaceStart+i].planeX);
|
||||
glTexGenfv(GL_T, GL_OBJECT_PLANE, (GLfloat*)interior->mLMTexGenEQs[surfaceStart+i].planeY);
|
||||
|
||||
|
||||
glDrawElements(GL_TRIANGLE_STRIP,
|
||||
interior->mSurfaces[surfaceStart+i].windingCount,
|
||||
GL_UNSIGNED_INT,
|
||||
&interior->mWindings[interior->mSurfaces[surfaceStart+i].windingStart]);
|
||||
}
|
||||
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
glActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
glDisable(GL_TEXTURE_GEN_S);
|
||||
glDisable(GL_TEXTURE_GEN_T);
|
||||
|
||||
glActiveTextureARB(GL_TEXTURE1_ARB);
|
||||
glDisable(GL_TEXTURE_GEN_S);
|
||||
glDisable(GL_TEXTURE_GEN_T);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
glActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
|
||||
// reset transform
|
||||
glPopMatrix();
|
||||
|
||||
// disable stencil test
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
|
||||
dglSetCanonicalState();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void MirrorSubObject::getWSPortalPlane(const U32 portalIndex, PlaneF* pPlane)
|
||||
{
|
||||
AssertFatal(portalIndex == 0, "Error, mirrortests only have one portal!");
|
||||
|
||||
Interior* interior = getInstance()->getDetailLevel(mDetailLevel);
|
||||
const Interior::Surface& rSurface = interior->mSurfaces[surfaceStart];
|
||||
|
||||
PlaneF temp = interior->getPlane(rSurface.planeIndex);
|
||||
if (Interior::planeIsFlipped(rSurface.planeIndex))
|
||||
temp.neg();
|
||||
|
||||
mTransformPlane(getSOTransform(), getSOScale(), temp, pPlane);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
U32 MirrorSubObject::getSubObjectKey() const
|
||||
{
|
||||
return InteriorSubObject::MirrorSubObjectKey;
|
||||
}
|
||||
|
||||
|
||||
bool MirrorSubObject::_readISO(Stream& stream)
|
||||
{
|
||||
AssertFatal(isInitialized() == false, "Error, should not be initialized here!");
|
||||
|
||||
if (Parent::_readISO(stream) == false)
|
||||
return false;
|
||||
|
||||
stream.read(&mDetailLevel);
|
||||
stream.read(&mZone);
|
||||
stream.read(&mAlphaLevel);
|
||||
stream.read(&surfaceCount);
|
||||
stream.read(&surfaceStart);
|
||||
|
||||
stream.read(&mCentroid.x);
|
||||
stream.read(&mCentroid.y);
|
||||
stream.read(&mCentroid.z);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool MirrorSubObject::_writeISO(Stream& stream) const
|
||||
{
|
||||
if (Parent::_writeISO(stream) == false)
|
||||
return false;
|
||||
|
||||
stream.write(mDetailLevel);
|
||||
stream.write(mZone);
|
||||
stream.write(mAlphaLevel);
|
||||
stream.write(surfaceCount);
|
||||
stream.write(surfaceStart);
|
||||
|
||||
stream.write(mCentroid.x);
|
||||
stream.write(mCentroid.y);
|
||||
stream.write(mCentroid.z);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SubObjectRenderImage* MirrorSubObject::getRenderImage(SceneState* state,
|
||||
const Point3F& osPoint)
|
||||
{
|
||||
if (isInitialized() == false)
|
||||
setupTransforms();
|
||||
|
||||
// Check to make sure that we´re on the right side of the plane...
|
||||
Interior* interior = getInstance()->getDetailLevel(mDetailLevel);
|
||||
const Interior::Surface& rSurface = interior->mSurfaces[surfaceStart];
|
||||
|
||||
PlaneF plane = interior->getPlane(rSurface.planeIndex);
|
||||
if (Interior::planeIsFlipped(rSurface.planeIndex))
|
||||
plane.neg();
|
||||
|
||||
if (plane.whichSide(osPoint) != PlaneF::Front)
|
||||
return NULL;
|
||||
|
||||
// On the right side, guess we have to return an image and a portal...
|
||||
//
|
||||
SubObjectRenderImage* ri = new SubObjectRenderImage;
|
||||
|
||||
ri->obj = this;
|
||||
ri->isTranslucent = false;
|
||||
|
||||
U32 realZone;
|
||||
if (getInstance()->getZoneRangeStart() == 0xFFFFFFFF || mZone == 0) {
|
||||
realZone = getInstance()->getCurrZone(0);
|
||||
} else {
|
||||
realZone = getInstance()->getZoneRangeStart() + mZone - 1;
|
||||
}
|
||||
|
||||
// Create the WS start point. this will be the centroid of the first poly in os space,
|
||||
// transformed out for the sceneGraph, with a smidge of our normal added in to pull
|
||||
// it off the surface plane...
|
||||
|
||||
Point3F startPoint = mCentroid;
|
||||
PlaneF temp = interior->getPlane(rSurface.planeIndex);
|
||||
if (Interior::planeIsFlipped(rSurface.planeIndex))
|
||||
temp.neg();
|
||||
startPoint += Point3F(temp.x, temp.y, temp.z) * 0.01f;
|
||||
getSOTransform().mulP(startPoint);
|
||||
startPoint.convolve(getSOScale());
|
||||
|
||||
state->insertTransformPortal(this, 0, realZone, startPoint, true);
|
||||
|
||||
return ri;
|
||||
}
|
||||
|
||||
|
||||
bool MirrorSubObject::renderDetailDependant() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
U32 MirrorSubObject::getZone() const
|
||||
{
|
||||
return mZone;
|
||||
}
|
||||
|
||||
|
||||
void MirrorSubObject::setupTransforms()
|
||||
{
|
||||
mInitialized = true;
|
||||
|
||||
Interior* interior = getInstance()->getDetailLevel(mDetailLevel);
|
||||
const Interior::Surface& rSurface = interior->mSurfaces[surfaceStart];
|
||||
|
||||
for( U32 i=0; i<surfaceCount; i++ )
|
||||
{
|
||||
Interior::Surface& surface = interior->mSurfaces[surfaceStart + i];
|
||||
//surface.mirrored = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PlaneF plane = interior->getPlane(rSurface.planeIndex);
|
||||
if (Interior::planeIsFlipped(rSurface.planeIndex))
|
||||
plane.neg();
|
||||
|
||||
Point3F n(plane.x, plane.y, plane.z);
|
||||
Point3F q = n;
|
||||
q *= -plane.d;
|
||||
|
||||
MatrixF t(true);
|
||||
t.scale(getSOScale());
|
||||
t.mul(getSOTransform());
|
||||
|
||||
t.mulV(n);
|
||||
t.mulP(q);
|
||||
|
||||
F32* ra = mReflectionMatrix;
|
||||
|
||||
ra[0] = 1.0f - 2.0f*(n.x*n.x); ra[1] = 0.0f - 2.0f*(n.x*n.y); ra[2] = 0.0f - 2.0f*(n.x*n.z); ra[3] = 0.0f;
|
||||
ra[4] = 0.0f - 2.0f*(n.y*n.x); ra[5] = 1.0f - 2.0f*(n.y*n.y); ra[6] = 0.0f - 2.0f*(n.y*n.z); ra[7] = 0.0f;
|
||||
ra[8] = 0.0f - 2.0f*(n.z*n.x); ra[9] = 0.0f - 2.0f*(n.z*n.y); ra[10] = 1.0f - 2.0f*(n.z*n.z); ra[11] = 0.0f;
|
||||
|
||||
Point3F qnn = n * mDot(n, q);
|
||||
|
||||
ra[12] = qnn.x * 2.0f;
|
||||
ra[13] = qnn.y * 2.0f;
|
||||
ra[14] = qnn.z * 2.0f;
|
||||
ra[15] = 1.0f;
|
||||
|
||||
// Now, the GGems series (as of v1) uses row vectors (arg)
|
||||
mReflectionMatrix.transpose();
|
||||
}
|
||||
|
||||
void MirrorSubObject::noteTransformChange()
|
||||
{
|
||||
setupTransforms();
|
||||
Parent::noteTransformChange();
|
||||
}
|
||||
|
||||
InteriorSubObject* MirrorSubObject::clone(InteriorInstance* instance) const
|
||||
{
|
||||
MirrorSubObject* pClone = new MirrorSubObject;
|
||||
|
||||
pClone->mDetailLevel = mDetailLevel;
|
||||
pClone->mZone = mZone;
|
||||
pClone->mAlphaLevel = mAlphaLevel;
|
||||
pClone->mCentroid = mCentroid;
|
||||
pClone->surfaceCount = surfaceCount;
|
||||
pClone->surfaceStart = surfaceStart;
|
||||
|
||||
pClone->mInteriorInstance = instance;
|
||||
|
||||
return pClone;
|
||||
}
|
85
engine/interior/mirrorSubObject.h
Executable file
85
engine/interior/mirrorSubObject.h
Executable file
@ -0,0 +1,85 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _MIRRORSUBOBJECT_H_
|
||||
#define _MIRRORSUBOBJECT_H_
|
||||
|
||||
#ifndef _INTERIORSUBOBJECT_H_
|
||||
#include "interior/interiorSubObject.h"
|
||||
#endif
|
||||
|
||||
class TextureHandle;
|
||||
|
||||
class MirrorSubObject : public InteriorSubObject
|
||||
{
|
||||
typedef InteriorSubObject Parent;
|
||||
|
||||
public:
|
||||
U32 mDetailLevel;
|
||||
U32 mZone;
|
||||
|
||||
F32 mAlphaLevel;
|
||||
Point3F mCentroid;
|
||||
|
||||
U32 surfaceCount;
|
||||
U32 surfaceStart;
|
||||
|
||||
private:
|
||||
bool mInitialized;
|
||||
TextureHandle* mWhite;
|
||||
MatrixF mReflectionMatrix;
|
||||
|
||||
bool isInitialized() const { return mInitialized; }
|
||||
void setupTransforms();
|
||||
|
||||
|
||||
// ISO overrides
|
||||
protected:
|
||||
U32 getSubObjectKey() const;
|
||||
bool _readISO(Stream&);
|
||||
bool _writeISO(Stream&) const;
|
||||
|
||||
// Render control. A sub-object should return false from renderDetailDependant if
|
||||
// it exists only at the level-0 detail level, ie, doors, elevators, etc., true
|
||||
// if should only render at the interiors detail, ie, translucencies.
|
||||
SubObjectRenderImage* getRenderImage(SceneState *state, const Point3F&);
|
||||
bool renderDetailDependant() const;
|
||||
U32 getZone() const;
|
||||
void noteTransformChange();
|
||||
|
||||
InteriorSubObject* clone(InteriorInstance*) const;
|
||||
|
||||
// Rendering
|
||||
protected:
|
||||
void renderObject(SceneState *state, SceneRenderImage *image);
|
||||
void transformModelview(const U32 portalIndex, const MatrixF &oldMV, MatrixF *newMV);
|
||||
void transformPosition(const U32 portalIndex, Point3F &point);
|
||||
bool computeNewFrustum(const U32 portalIndex,
|
||||
const F64* oldFrustum,
|
||||
const F64 nearPlane,
|
||||
const F64 farPlane,
|
||||
const RectI& oldViewport,
|
||||
F64* newFrustum,
|
||||
RectI& newViewport,
|
||||
const bool flippedMatrix);
|
||||
void openPortal(const U32 portalIndex,
|
||||
SceneState* pCurrState,
|
||||
SceneState* pParentState);
|
||||
void closePortal(const U32 portalIndex,
|
||||
SceneState* pCurrState,
|
||||
SceneState* pParentState);
|
||||
void getWSPortalPlane(const U32 portalIndex, PlaneF *plane);
|
||||
|
||||
|
||||
public:
|
||||
MirrorSubObject();
|
||||
~MirrorSubObject();
|
||||
|
||||
DECLARE_CONOBJECT(MirrorSubObject);
|
||||
static void initPersistFields();
|
||||
};
|
||||
|
||||
#endif // _H_MIRRORSUBOBJECT
|
||||
|
625
engine/interior/pathedInterior.cc
Executable file
625
engine/interior/pathedInterior.cc
Executable file
@ -0,0 +1,625 @@
|
||||
//--------------------------------------------------------------------------
|
||||
// PathedInterior.cc:
|
||||
//
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
#include "interior/pathedInterior.h"
|
||||
#include "core/stream.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "dgl/dgl.h"
|
||||
#include "sceneGraph/sceneState.h"
|
||||
#include "math/mathIO.h"
|
||||
#include "core/bitStream.h"
|
||||
#include "interior/interior.h"
|
||||
#include "sim/simPath.h"
|
||||
#include "sim/pathManager.h"
|
||||
#include "core/frameAllocator.h"
|
||||
#include "sceneGraph/sceneGraph.h"
|
||||
|
||||
IMPLEMENT_CO_NETOBJECT_V1(PathedInterior);
|
||||
IMPLEMENT_CO_DATABLOCK_V1(PathedInteriorData);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
PathedInteriorData::PathedInteriorData()
|
||||
{
|
||||
for(U32 i = 0; i < MaxSounds; i++)
|
||||
sound[i] = NULL;
|
||||
}
|
||||
|
||||
void PathedInteriorData::initPersistFields()
|
||||
{
|
||||
addField("StartSound", TypeAudioProfilePtr, Offset(sound[StartSound], PathedInteriorData));
|
||||
addField("SustainSound", TypeAudioProfilePtr, Offset(sound[SustainSound], PathedInteriorData));
|
||||
addField("StopSound", TypeAudioProfilePtr, Offset(sound[StopSound], PathedInteriorData));
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
void PathedInteriorData::packData(BitStream *stream)
|
||||
{
|
||||
for (S32 i = 0; i < MaxSounds; i++)
|
||||
{
|
||||
if (stream->writeFlag(sound[i]))
|
||||
stream->writeRangedU32(packed? SimObjectId(sound[i]):
|
||||
sound[i]->getId(),DataBlockObjectIdFirst,DataBlockObjectIdLast);
|
||||
}
|
||||
Parent::packData(stream);
|
||||
}
|
||||
|
||||
void PathedInteriorData::unpackData(BitStream* stream)
|
||||
{
|
||||
for (S32 i = 0; i < MaxSounds; i++) {
|
||||
sound[i] = NULL;
|
||||
if (stream->readFlag())
|
||||
sound[i] = (AudioProfile*)stream->readRangedU32(DataBlockObjectIdFirst,
|
||||
DataBlockObjectIdLast);
|
||||
}
|
||||
Parent::unpackData(stream);
|
||||
}
|
||||
|
||||
bool PathedInteriorData::preload(bool server, char errorBuffer[256])
|
||||
{
|
||||
if(!Parent::preload(server, errorBuffer))
|
||||
return false;
|
||||
|
||||
// Resolve objects transmitted from server
|
||||
if (!server)
|
||||
{
|
||||
for (S32 i = 0; i < MaxSounds; i++)
|
||||
if (sound[i])
|
||||
Sim::findObject(SimObjectId(sound[i]),sound[i]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
PathedInterior::PathedInterior()
|
||||
{
|
||||
mNetFlags.set(Ghostable);
|
||||
mTypeMask = InteriorObjectType;
|
||||
|
||||
mCurrentPosition = 0;
|
||||
mTargetPosition = 0;
|
||||
mPathKey = 0xFFFFFFFF;
|
||||
mStopped = false;
|
||||
mSustainHandle = 0;
|
||||
}
|
||||
|
||||
PathedInterior::~PathedInterior()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
PathedInterior *PathedInterior::mClientPathedInteriors = NULL;
|
||||
//--------------------------------------------------------------------------
|
||||
void PathedInterior::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
|
||||
addField("interiorResource", TypeFilename, Offset(mInteriorResName, PathedInterior));
|
||||
addField("interiorIndex", TypeS32, Offset(mInteriorResIndex, PathedInterior));
|
||||
addField("basePosition", TypeMatrixPosition, Offset(mBaseTransform, PathedInterior));
|
||||
addField("baseRotation", TypeMatrixRotation, Offset(mBaseTransform, PathedInterior));
|
||||
addField("baseScale", TypePoint3F, Offset(mBaseScale, PathedInterior));
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool PathedInterior::onAdd()
|
||||
{
|
||||
if(!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
// Load the interior resource and extract the interior that is us.
|
||||
char buffer[256];
|
||||
mInteriorRes = ResourceManager->load(mInteriorResName);
|
||||
if (bool(mInteriorRes) == false)
|
||||
return false;
|
||||
mInterior = mInteriorRes->getSubObject(mInteriorResIndex);
|
||||
if (mInterior == NULL)
|
||||
return false;
|
||||
|
||||
// Setup bounding information
|
||||
mObjBox = mInterior->getBoundingBox();
|
||||
resetWorldBox();
|
||||
|
||||
setScale(mBaseScale);
|
||||
setTransform(mBaseTransform);
|
||||
|
||||
if (isClientObject()) {
|
||||
mNextClientPI = mClientPathedInteriors;
|
||||
mClientPathedInteriors = this;
|
||||
mInterior->prepForRendering(mInteriorRes.getFilePath());
|
||||
// gInteriorLMManager.addInstance(mInterior->getLMHandle(), mLMHandle, NULL, this);
|
||||
}
|
||||
|
||||
if(isClientObject())
|
||||
{
|
||||
Point3F initialPos;
|
||||
mBaseTransform.getColumn(3, &initialPos);
|
||||
Point3F pathPos;
|
||||
//gClientPathManager->getPathPosition(mPathKey, 0, pathPos);
|
||||
mOffset = initialPos - pathPos;
|
||||
//gClientPathManager->getPathPosition(mPathKey, mCurrentPosition, pathPos);
|
||||
MatrixF mat = getTransform();
|
||||
mat.setColumn(3, pathPos + mOffset);
|
||||
setTransform(mat);
|
||||
}
|
||||
|
||||
addToScene();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PathedInterior::onSceneAdd(SceneGraph *g)
|
||||
{
|
||||
if(!Parent::onSceneAdd(g))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void PathedInterior::onSceneRemove()
|
||||
{
|
||||
Parent::onSceneRemove();
|
||||
}
|
||||
|
||||
bool PathedInterior::onNewDataBlock(GameBaseData* dptr)
|
||||
{
|
||||
mDataBlock = dynamic_cast<PathedInteriorData*>(dptr);
|
||||
return Parent::onNewDataBlock(dptr);
|
||||
}
|
||||
|
||||
void PathedInterior::onRemove()
|
||||
{
|
||||
if(isClientObject())
|
||||
{
|
||||
if(mSustainHandle)
|
||||
{
|
||||
alxStop(mSustainHandle);
|
||||
mSustainHandle = 0;
|
||||
}
|
||||
PathedInterior **walk = &mClientPathedInteriors;
|
||||
while(*walk)
|
||||
{
|
||||
if(*walk == this)
|
||||
{
|
||||
*walk = mNextClientPI;
|
||||
break;
|
||||
}
|
||||
walk = &((*walk)->mNextClientPI);
|
||||
}
|
||||
/* if(bool(mInteriorRes) && mLMHandle != 0xFFFFFFFF)
|
||||
{
|
||||
if (mInterior->getLMHandle() != 0xFFFFFFFF)
|
||||
gInteriorLMManager.removeInstance(mInterior->getLMHandle(), mLMHandle);
|
||||
}*/
|
||||
}
|
||||
removeFromScene();
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool PathedInterior::buildPolyList(AbstractPolyList* list, const Box3F& wsBox, const SphereF&)
|
||||
{
|
||||
if (bool(mInteriorRes) == false)
|
||||
return false;
|
||||
|
||||
// Setup collision state data
|
||||
list->setTransform(&getTransform(), getScale());
|
||||
list->setObject(this);
|
||||
|
||||
return mInterior->buildPolyList(list, wsBox, mWorldToObj, getScale());
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool PathedInterior::prepRenderImage(SceneState* state, const U32 stateKey,
|
||||
const U32 /*startZone*/, const bool /*modifyBaseState*/)
|
||||
{
|
||||
if (isLastState(state, stateKey))
|
||||
return false;
|
||||
setLastState(state, stateKey);
|
||||
|
||||
if (mPathKey == Path::NoPathIndex)
|
||||
return false;
|
||||
|
||||
// This should be sufficient for most objects that don't manage zones, and
|
||||
// don't need to return a specialized RenderImage...
|
||||
bool render = false;
|
||||
for (U32 i = 0; i < getNumCurrZones(); i++)
|
||||
if (state->getZoneState(getCurrZone(i)).render == true)
|
||||
render = true;
|
||||
|
||||
if (render == true) {
|
||||
SceneRenderImage* image = new SceneRenderImage;
|
||||
image->obj = this;
|
||||
state->insertRenderImage(image);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
extern ColorF gInteriorFogColor;
|
||||
|
||||
void PathedInterior::renderObject(SceneState* state, SceneRenderImage*)
|
||||
{
|
||||
U32 storedWaterMark = FrameAllocator::getWaterMark();
|
||||
Point3F worldOrigin;
|
||||
getRenderTransform().getColumn(3, &worldOrigin);
|
||||
|
||||
// Set up the model view and the global render state...
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
|
||||
ColorF oneColor(1,1,1,1);
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, oneColor);
|
||||
|
||||
gClientSceneGraph->getLightManager()->sgSetupLights(this);
|
||||
|
||||
// dglMultMatrix(&newMat);
|
||||
dglMultMatrix(&mRenderObjToWorld);
|
||||
glScalef(mObjScale.x, mObjScale.y, mObjScale.z);
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
// We need to decide if we're going to use the low-res textures
|
||||
|
||||
//mInterior->setupFog(state);
|
||||
//gInteriorFogColor = state->getFogColor();
|
||||
mInterior->renderAsShape();
|
||||
|
||||
//mInterior->clearFog();
|
||||
|
||||
gClientSceneGraph->getLightManager()->sgResetLights();
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPopMatrix();
|
||||
|
||||
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on exit");
|
||||
|
||||
FrameAllocator::setWaterMark(storedWaterMark);
|
||||
dglSetRenderPrimType(0);
|
||||
|
||||
// Reset the small textures...
|
||||
TextureManager::setSmallTexturesActive(false);
|
||||
|
||||
}
|
||||
|
||||
void PathedInterior::resolvePathKey()
|
||||
{
|
||||
if(mPathKey == 0xFFFFFFFF && !isGhost())
|
||||
{
|
||||
mPathKey = getPathKey();
|
||||
Point3F pathPos;
|
||||
Point3F initialPos;
|
||||
mBaseTransform.getColumn(3, &initialPos);
|
||||
//gServerPathManager->getPathPosition(mPathKey, 0, pathPos);
|
||||
mOffset = initialPos - pathPos;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
U32 PathedInterior::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
|
||||
{
|
||||
U32 retMask = Parent::packUpdate(con, mask, stream);
|
||||
resolvePathKey();
|
||||
|
||||
if (stream->writeFlag(mask & InitialUpdateMask))
|
||||
{
|
||||
// Inital update...
|
||||
stream->writeString(mInteriorResName);
|
||||
stream->write(mInteriorResIndex);
|
||||
|
||||
stream->writeAffineTransform(mBaseTransform);
|
||||
mathWrite(*stream, mBaseScale);
|
||||
|
||||
stream->write(mPathKey);
|
||||
}
|
||||
if(stream->writeFlag((mask & NewPositionMask) && mPathKey != Path::NoPathIndex))
|
||||
stream->writeInt(S32(mCurrentPosition), gServerPathManager->getPathTimeBits(mPathKey));
|
||||
if(stream->writeFlag((mask & NewTargetMask) && mPathKey != Path::NoPathIndex))
|
||||
{
|
||||
if(stream->writeFlag(mTargetPosition < 0))
|
||||
{
|
||||
stream->writeFlag(mTargetPosition == -1);
|
||||
}
|
||||
else
|
||||
stream->writeInt(S32(mTargetPosition), gServerPathManager->getPathTimeBits(mPathKey));
|
||||
}
|
||||
return retMask;
|
||||
}
|
||||
|
||||
void PathedInterior::unpackUpdate(NetConnection* con, BitStream* stream)
|
||||
{
|
||||
Parent::unpackUpdate(con, stream);
|
||||
|
||||
MatrixF tempXForm;
|
||||
Point3F tempScale;
|
||||
|
||||
if (stream->readFlag())
|
||||
{
|
||||
// Initial
|
||||
mInteriorResName = stream->readSTString();
|
||||
stream->read(&mInteriorResIndex);
|
||||
|
||||
stream->readAffineTransform(&tempXForm);
|
||||
mathRead(*stream, &tempScale);
|
||||
mBaseTransform = tempXForm;
|
||||
mBaseScale = tempScale;
|
||||
|
||||
stream->read(&mPathKey);
|
||||
}
|
||||
if(stream->readFlag())
|
||||
{
|
||||
Point3F pathPos;
|
||||
mCurrentPosition = stream->readInt(gClientPathManager->getPathTimeBits(mPathKey));
|
||||
if(isProperlyAdded())
|
||||
{
|
||||
//gClientPathManager->getPathPosition(mPathKey, mCurrentPosition, pathPos);
|
||||
MatrixF mat = getTransform();
|
||||
mat.setColumn(3, pathPos + mOffset);
|
||||
setTransform(mat);
|
||||
}
|
||||
}
|
||||
if(stream->readFlag())
|
||||
{
|
||||
if(stream->readFlag())
|
||||
{
|
||||
mTargetPosition = stream->readFlag() ? -1 : -2;
|
||||
}
|
||||
else
|
||||
mTargetPosition = stream->readInt(gClientPathManager->getPathTimeBits(mPathKey));
|
||||
}
|
||||
}
|
||||
|
||||
void PathedInterior::processTick(const Move* move)
|
||||
{
|
||||
if(isServerObject())
|
||||
{
|
||||
U32 timeMs = 32;
|
||||
if(mCurrentPosition != mTargetPosition)
|
||||
{
|
||||
S32 delta;
|
||||
if(mTargetPosition == -1)
|
||||
delta = timeMs;
|
||||
else if(mTargetPosition == -2)
|
||||
delta = -timeMs;
|
||||
else
|
||||
{
|
||||
delta = mTargetPosition - mCurrentPosition;
|
||||
if(delta < -timeMs)
|
||||
delta = -timeMs;
|
||||
else if(delta > timeMs)
|
||||
delta = timeMs;
|
||||
}
|
||||
mCurrentPosition += delta;
|
||||
U32 totalTime = gClientPathManager->getPathTotalTime(mPathKey);
|
||||
while(mCurrentPosition > totalTime)
|
||||
mCurrentPosition -= totalTime;
|
||||
while(mCurrentPosition < 0)
|
||||
mCurrentPosition += totalTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PathedInterior::computeNextPathStep(U32 timeDelta)
|
||||
{
|
||||
S32 timeMs = timeDelta;
|
||||
mStopped = false;
|
||||
|
||||
if(mCurrentPosition == mTargetPosition)
|
||||
{
|
||||
mExtrudedBox = getWorldBox();
|
||||
mCurrentVelocity.set(0,0,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
S32 delta;
|
||||
if(mTargetPosition < 0)
|
||||
{
|
||||
if(mTargetPosition == -1)
|
||||
delta = timeMs;
|
||||
else if(mTargetPosition == -2)
|
||||
delta = -timeMs;
|
||||
mCurrentPosition += delta;
|
||||
U32 totalTime = gClientPathManager->getPathTotalTime(mPathKey);
|
||||
while(mCurrentPosition >= totalTime)
|
||||
mCurrentPosition -= totalTime;
|
||||
while(mCurrentPosition < 0)
|
||||
mCurrentPosition += totalTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
delta = mTargetPosition - mCurrentPosition;
|
||||
if(delta < -timeMs)
|
||||
delta = -timeMs;
|
||||
else if(delta > timeMs)
|
||||
delta = timeMs;
|
||||
mCurrentPosition += delta;
|
||||
}
|
||||
|
||||
Point3F curPoint;
|
||||
Point3F newPoint = Point3F(0,0,0); //BJGNOTE - this shuts up the compiler, three lines down will actually set it.
|
||||
MatrixF mat = getTransform();
|
||||
mat.getColumn(3, &curPoint);
|
||||
//gClientPathManager->getPathPosition(mPathKey, mCurrentPosition, newPoint);
|
||||
newPoint += mOffset;
|
||||
|
||||
Point3F displaceDelta = newPoint - curPoint;
|
||||
mExtrudedBox = getWorldBox();
|
||||
|
||||
if(displaceDelta.x < 0)
|
||||
mExtrudedBox.min.x += displaceDelta.x;
|
||||
else
|
||||
mExtrudedBox.max.x += displaceDelta.x;
|
||||
if(displaceDelta.y < 0)
|
||||
mExtrudedBox.min.y += displaceDelta.y;
|
||||
else
|
||||
mExtrudedBox.max.y += displaceDelta.y;
|
||||
if(displaceDelta.z < 0)
|
||||
mExtrudedBox.min.z += displaceDelta.z;
|
||||
else
|
||||
mExtrudedBox.max.z += displaceDelta.z;
|
||||
|
||||
mCurrentVelocity = displaceDelta * 1000 / F32(timeDelta);
|
||||
}
|
||||
Point3F pos;
|
||||
mExtrudedBox.getCenter(&pos);
|
||||
MatrixF mat = getTransform();
|
||||
mat.setColumn(3, pos);
|
||||
if(!mSustainHandle && mDataBlock->sound[PathedInteriorData::SustainSound])
|
||||
{
|
||||
//F32 volSave = mDataBlock->sound[PathedInteriorData::SustainSound]->mDescriptionObject->mDescription.mVolume;
|
||||
//mDataBlock->sound[PathedInteriorData::SustainSound]->mDescriptionObject->mDescription.mVolume = 0;
|
||||
mSustainHandle = alxPlay(mDataBlock->sound[PathedInteriorData::SustainSound], &mat);
|
||||
//mDataBlock->sound[PathedInteriorData::SustainSound]->mDescriptionObject->mDescription.mVolume = volSave;
|
||||
}
|
||||
if(mSustainHandle)
|
||||
{
|
||||
Point3F pos;
|
||||
mExtrudedBox.getCenter(&pos);
|
||||
MatrixF mat = getTransform();
|
||||
mat.setColumn(3, pos);
|
||||
alxSourceMatrixF(mSustainHandle, &mat);
|
||||
}
|
||||
}
|
||||
|
||||
Point3F PathedInterior::getVelocity()
|
||||
{
|
||||
return mCurrentVelocity;
|
||||
}
|
||||
|
||||
void PathedInterior::advance(F64 timeDelta)
|
||||
{
|
||||
if(mStopped)
|
||||
return;
|
||||
|
||||
F64 timeMs = timeDelta;
|
||||
if(mCurrentVelocity.len() == 0)
|
||||
{
|
||||
// if(mSustainHandle)
|
||||
// {
|
||||
// alxStop(mSustainHandle);
|
||||
// mSustainHandle = 0;
|
||||
// }
|
||||
return;
|
||||
}
|
||||
MatrixF mat = getTransform();
|
||||
Point3F newPoint;
|
||||
mat.getColumn(3, &newPoint);
|
||||
newPoint += mCurrentVelocity * timeDelta / 1000.0f;
|
||||
//gClientPathManager->getPathPosition(mPathKey, mCurrentPosition, newPoint);
|
||||
mat.setColumn(3, newPoint);// + mOffset);
|
||||
setTransform(mat);
|
||||
setRenderTransform(mat);
|
||||
}
|
||||
|
||||
U32 PathedInterior::getPathKey()
|
||||
{
|
||||
AssertFatal(isServerObject(), "Error, must be a server object to call this...");
|
||||
|
||||
SimGroup* myGroup = getGroup();
|
||||
AssertFatal(myGroup != NULL, "No group for this object?");
|
||||
|
||||
for (SimGroup::iterator itr = myGroup->begin(); itr != myGroup->end(); itr++) {
|
||||
Path* pPath = dynamic_cast<Path*>(*itr);
|
||||
if (pPath != NULL) {
|
||||
U32 pathKey = pPath->getPathIndex();
|
||||
AssertFatal(pathKey != Path::NoPathIndex, "Error, path must have event over at this point...");
|
||||
return pathKey;
|
||||
}
|
||||
}
|
||||
|
||||
return Path::NoPathIndex;
|
||||
}
|
||||
|
||||
void PathedInterior::setPathPosition(S32 newPosition)
|
||||
{
|
||||
resolvePathKey();
|
||||
if(newPosition < 0)
|
||||
newPosition = 0;
|
||||
if(newPosition > gServerPathManager->getPathTotalTime(mPathKey))
|
||||
newPosition = gServerPathManager->getPathTotalTime(mPathKey);
|
||||
mCurrentPosition = mTargetPosition = newPosition;
|
||||
setMaskBits(NewPositionMask | NewTargetMask);
|
||||
}
|
||||
|
||||
void PathedInterior::setTargetPosition(S32 newPosition)
|
||||
{
|
||||
resolvePathKey();
|
||||
if(newPosition < -2)
|
||||
newPosition = 0;
|
||||
if(newPosition > S32(gServerPathManager->getPathTotalTime(mPathKey)))
|
||||
newPosition = gServerPathManager->getPathTotalTime(mPathKey);
|
||||
if(mTargetPosition != newPosition)
|
||||
{
|
||||
mTargetPosition = newPosition;
|
||||
setMaskBits(NewTargetMask);
|
||||
}
|
||||
}
|
||||
|
||||
ConsoleMethod(PathedInterior, setPathPosition, void, 3, 3, "")
|
||||
{
|
||||
object->setPathPosition(dAtoi(argv[2]));
|
||||
}
|
||||
|
||||
ConsoleMethod(PathedInterior, setTargetPosition, void, 3, 3, "")
|
||||
{
|
||||
object->setTargetPosition(dAtoi(argv[2]));
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool PathedInterior::readPI(Stream& stream)
|
||||
{
|
||||
mName = stream.readSTString();
|
||||
mInteriorResName = stream.readSTString();
|
||||
stream.read(&mInteriorResIndex);
|
||||
stream.read(&mPathIndex);
|
||||
mathRead(stream, &mOffset);
|
||||
|
||||
U32 numTriggers;
|
||||
stream.read(&numTriggers);
|
||||
mTriggers.setSize(numTriggers);
|
||||
for (U32 i = 0; i < mTriggers.size(); i++)
|
||||
mTriggers[i] = stream.readSTString();
|
||||
|
||||
return (stream.getStatus() == Stream::Ok);
|
||||
}
|
||||
|
||||
bool PathedInterior::writePI(Stream& stream) const
|
||||
{
|
||||
stream.writeString(mName);
|
||||
stream.writeString(mInteriorResName);
|
||||
stream.write(mInteriorResIndex);
|
||||
stream.write(mPathIndex);
|
||||
mathWrite(stream, mOffset);
|
||||
|
||||
stream.write(mTriggers.size());
|
||||
for (U32 i = 0; i < mTriggers.size(); i++)
|
||||
stream.writeString(mTriggers[i]);
|
||||
|
||||
return (stream.getStatus() == Stream::Ok);
|
||||
}
|
||||
|
||||
PathedInterior* PathedInterior::clone() const
|
||||
{
|
||||
PathedInterior* pClone = new PathedInterior;
|
||||
|
||||
pClone->mName = mName;
|
||||
pClone->mInteriorResName = mInteriorResName;
|
||||
pClone->mInteriorResIndex = mInteriorResIndex;
|
||||
pClone->mPathIndex = mPathIndex;
|
||||
pClone->mOffset = mOffset;
|
||||
|
||||
return pClone;
|
||||
}
|
||||
|
||||
|
139
engine/interior/pathedInterior.h
Executable file
139
engine/interior/pathedInterior.h
Executable file
@ -0,0 +1,139 @@
|
||||
//--------------------------------------------------------------------------
|
||||
// PathedInterior.h:
|
||||
//
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
#ifndef _H_PATHEDINTERIOR
|
||||
#define _H_PATHEDINTERIOR
|
||||
|
||||
|
||||
#include "interior/interior.h"
|
||||
#include "game/gameBase.h"
|
||||
#include "core/resManager.h"
|
||||
#include "interior/interiorRes.h"
|
||||
#ifndef _INTERIORLMMANAGER_H_
|
||||
#include "interior/interiorLMManager.h"
|
||||
#endif
|
||||
#include "audio/audioDataBlock.h"
|
||||
|
||||
class InteriorInstance;
|
||||
class EditGeometry;
|
||||
class EditInteriorResource;
|
||||
|
||||
struct PathedInteriorData : public GameBaseData {
|
||||
typedef GameBaseData Parent;
|
||||
public:
|
||||
enum Sounds {
|
||||
StartSound,
|
||||
SustainSound,
|
||||
StopSound,
|
||||
MaxSounds
|
||||
};
|
||||
AudioProfile *sound[MaxSounds];
|
||||
static void initPersistFields();
|
||||
virtual void packData(BitStream* stream);
|
||||
virtual void unpackData(BitStream* stream);
|
||||
bool preload(bool server, char errorBuffer[256]);
|
||||
PathedInteriorData();
|
||||
|
||||
DECLARE_CONOBJECT(PathedInteriorData);
|
||||
};
|
||||
|
||||
class PathedInterior : public GameBase
|
||||
{
|
||||
typedef GameBase Parent;
|
||||
friend class InteriorInstance;
|
||||
friend class EditGeometry;
|
||||
friend class EditInteriorResource;
|
||||
|
||||
PathedInteriorData *mDataBlock;
|
||||
|
||||
public:
|
||||
enum UpdateMasks {
|
||||
NewTargetMask = Parent::NextFreeMask,
|
||||
NewPositionMask = Parent::NextFreeMask << 1,
|
||||
NextFreeMask = Parent::NextFreeMask << 2,
|
||||
};
|
||||
private:
|
||||
|
||||
U32 getPathKey(); // only used on the server
|
||||
|
||||
// Persist fields
|
||||
protected:
|
||||
StringTableEntry mName;
|
||||
S32 mPathIndex;
|
||||
Vector<StringTableEntry> mTriggers;
|
||||
Point3F mOffset;
|
||||
Box3F mExtrudedBox;
|
||||
bool mStopped;
|
||||
|
||||
// Loaded resources and fields
|
||||
protected:
|
||||
static PathedInterior *mClientPathedInteriors;
|
||||
|
||||
AUDIOHANDLE mSustainHandle;
|
||||
|
||||
StringTableEntry mInteriorResName;
|
||||
S32 mInteriorResIndex;
|
||||
Resource<InteriorResource> mInteriorRes;
|
||||
Interior* mInterior;
|
||||
Vector<ColorI> mVertexColorsNormal;
|
||||
Vector<ColorI> mVertexColorsAlarm;
|
||||
LM_HANDLE mLMHandle;
|
||||
|
||||
MatrixF mBaseTransform;
|
||||
Point3F mBaseScale;
|
||||
|
||||
U32 mPathKey; // only used on the client
|
||||
F64 mCurrentPosition;
|
||||
S32 mTargetPosition;
|
||||
Point3F mCurrentVelocity;
|
||||
|
||||
PathedInterior *mNextClientPI;
|
||||
|
||||
// Rendering
|
||||
protected:
|
||||
bool prepRenderImage(SceneState *state, const U32 stateKey, const U32 startZone, const bool modifyBaseZoneState);
|
||||
void renderObject(SceneState *state, SceneRenderImage *image);
|
||||
void renderShadowVolumes(SceneState *state);
|
||||
|
||||
protected:
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
bool onSceneAdd(SceneGraph *graph);
|
||||
void onSceneRemove();
|
||||
|
||||
public:
|
||||
PathedInterior();
|
||||
~PathedInterior();
|
||||
|
||||
PathedInterior *getNext() { return mNextClientPI; }
|
||||
|
||||
static PathedInterior *getClientPathedInteriors() { return mClientPathedInteriors; }
|
||||
|
||||
void processTick(const Move* move);
|
||||
void setStopped() { mStopped = true; }
|
||||
void resolvePathKey();
|
||||
|
||||
bool onNewDataBlock(GameBaseData* dptr);
|
||||
bool buildPolyList(AbstractPolyList* polyList, const Box3F &box, const SphereF &sphere);
|
||||
bool readPI(Stream&);
|
||||
bool writePI(Stream&) const;
|
||||
PathedInterior* clone() const;
|
||||
|
||||
DECLARE_CONOBJECT(PathedInterior);
|
||||
static void initPersistFields();
|
||||
void setPathPosition(S32 newPosition);
|
||||
void setTargetPosition(S32 targetPosition);
|
||||
void computeNextPathStep(U32 timeDelta);
|
||||
Box3F getExtrudedBox() { return mExtrudedBox; }
|
||||
Point3F getVelocity();
|
||||
void advance(F64 timeDelta);
|
||||
|
||||
U32 packUpdate(NetConnection *conn, U32 mask, BitStream* stream);
|
||||
void unpackUpdate(NetConnection *conn, BitStream* stream);
|
||||
};
|
||||
|
||||
#endif // _H_PATHEDINTERIOR
|
||||
|
Reference in New Issue
Block a user