t2 engine svn checkout

This commit is contained in:
loop 2024-01-07 04:36:33 +00:00
commit ff569bd2ae
988 changed files with 394180 additions and 0 deletions

123
interior/floorPlanRes.cc Normal file
View file

@ -0,0 +1,123 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, 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;
}
}

52
interior/floorPlanRes.h Normal file
View file

@ -0,0 +1,52 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, 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_

472
interior/forceField.cc Normal file
View file

@ -0,0 +1,472 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, 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 "PlatformWin32/platformGL.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();
}

182
interior/forceField.h Normal file
View file

@ -0,0 +1,182 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, 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_

2173
interior/interior.cc Normal file

File diff suppressed because it is too large Load diff

859
interior/interior.h Normal file
View file

@ -0,0 +1,859 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, 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
//-------------------------------------- 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;
public:
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 interfaces
public:
Interior();
~Interior();
// Misc
U32 getDetailLevel() const;
U32 getMinPixels() const;
const Box3F& getBoundingBox() const;
S32 getNumZones() const;
// Rendering
bool prepForRendering();
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,
U32* lightSurfaces,
U32 numLightSurfaces);
bool useFogCoord();
bool scopeZones(const S32 baseZone,
const Point3F& interiorRoot,
bool* interiorScopingState);
//-------------------------------------- Collision Interface and zone scans
public:
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;
//-------------------------------------- Persistence interface
public:
bool read(Stream& stream);
bool write(Stream& stream) const;
bool readVehicleCollision(Stream& stream);
bool writeVehicleCollision(Stream& stream) const;
private:
static const U32 smFileVersion;
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
private:
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(U16 index);
static bool planeIsFlipped(U16 index);
const PlaneF& getPlane(U16 index) const;
private:
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
private:
struct Zone {
U16 portalStart;
U16 portalCount;
U32 surfaceStart;
U32 planeStart;
U16 surfaceCount;
U16 planeCount;
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 = 1 << 0,
SurfaceAmbiguous = 1 << 1,
SurfaceOrphan = 1 << 2,
SurfaceSharedLMaps = 1 << 3, // Indicates that the alarm and normal states share a lightmap (for mission lighter)
SurfaceOutsideVisible = 1 << 4,
SurfaceFlagMask = (SurfaceDetail |
SurfaceAmbiguous |
SurfaceOrphan |
SurfaceSharedLMaps |
SurfaceOutsideVisible)
};
enum ZoneFlags {
ZoneInside = 1 << 0
};
const bool isSurfaceOutsideVisible(U32 surface) const;
public:
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;
U8 windingCount;
U32 fanMask; // 5
U32 lightStateInfoStart; // 6
U8 mapOffsetX; // 7
U8 mapOffsetY;
U8 mapSizeX;
U8 mapSizeY;
};
struct NullSurface {
U32 windingStart;
U16 planeIndex;
U8 surfaceFlags;
U8 windingCount;
};
//-------------------------------------- Animated lighting structures
enum LightFlags {
AnimationAmbient = 1 << 0,
AnimationLoop = 1 << 1,
AnimationFlicker = 1 << 2,
AnimationTypeMask = (1 << 3) - 1,
AlarmLight = 1 << 3
};
enum LightType {
AmbientLooping = AnimationAmbient | AnimationLoop,
AmbientFlicker = AnimationAmbient | AnimationFlicker,
TriggerableLoop = AnimationLoop,
TriggerableFlicker = AnimationFlicker,
TriggerableRamp = 0
};
private:
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)
};
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;
};
struct CoordBin {
U32 binStart;
U32 binCount;
};
//
private:
LM_HANDLE mLMHandle;
public:
LM_HANDLE getLMHandle() {return(mLMHandle);}
// SceneLighting::InteriorProxy interface
const Surface & getSurface(const U32 surface) const;
const U32 getSurfaceCount() const;
const U8 getNormalLMapIndex(const U32 surface) const;
const U8 getAlarmLMapIndex(const U32 surface) 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
private:
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;
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;
// Portals and zones
Vector<Zone> mZones;
Vector<U16> mZonePlanes;
Vector<U16> mZoneSurfaces;
Vector<U16> mZonePortalList;
Vector<Portal> mPortals;
// Subobjects: Doors, translucencies, mirrors, etc.
Vector<InteriorSubObject*> mSubObjects;
// Lighting info
bool mHasAlarmState;
U32 mNumLightStateEntries;
Vector<GBitmap*> mLightmaps;
Vector<bool> mLightmapKeep;
Vector<U8> mNormalLMapIndices;
Vector<U8> 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;
U16 mSearchTag;
//-------------------------------------- Private interface
private:
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();
void collisionFanFromSurface(const Surface&, U32* fan, U32* numIndices) const;
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 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(U16 index) const
{
AssertFatal(U32(index & ~0x8000) < mPlanes.size(),
"Interior::getPlane: planeIndex out of range");
return mPlanes[index & ~0x8000];
}
inline U16 Interior::getPlaneIndex(U16 index)
{
return U16(index & ~0x8000);
}
inline bool Interior::planeIsFlipped(U16 index)
{
return bool(index >> 15);
// return (index & 0x8000) != 0;
}
inline bool Interior::areEqualPlanes(U16 o, U16 t) const
{
return (o & ~0x8000) == (t & ~0x8000);
}
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 U8 Interior::getNormalLMapIndex(const U32 surface) const
{
AssertFatal(surface < mNormalLMapIndices.size(), "invalid index");
return(mNormalLMapIndices[surface]);
}
inline const U8 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::isSrufaceOutsideVisible: Invalid surface index");
return(mSurfaces[surface].surfaceFlags & SurfaceOutsideVisible);
}
inline const U32 Interior::getWindingCount() const
{
return(mWindings.size());
}
#endif //_INTERIOR_H_

File diff suppressed because it is too large Load diff

803
interior/interiorDebug.cc Normal file
View file

@ -0,0 +1,803 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "interior/interior.h"
#include "console/console.h"
#include "core/color.h"
#include "platformWIN32/platformGL.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);
}
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);
}

1128
interior/interiorIO.cc Normal file

File diff suppressed because it is too large Load diff

1965
interior/interiorInstance.cc Normal file

File diff suppressed because it is too large Load diff

293
interior/interiorInstance.h Normal file
View file

@ -0,0 +1,293 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, 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();
static void init();
static void destroy();
// Collision
public:
bool buildPolyList(AbstractPolyList*, const Box3F&, const SphereF&);
bool castRay(const Point3F&, const Point3F&, RayInfo*);
virtual void setTransform(const MatrixF&);
void buildConvex(const Box3F& box,Convex* convex);
private:
Convex* mConvexList;
// Lighting control
public:
bool inAlarmState() {return(mAlarmState);}
void setAlarmMode(const bool alarm);
void activateLight(const char* pLightName);
void deactivateLight(const char* pLightName);
void echoTriggerableLights();
// Subobject access interface
public:
U32 getNumDetailLevels();
Interior* getDetailLevel(const U32);
void setDetailLevel(S32 level = -1) { mForcedDetailLevel = level; }
// Material management for overlays
public:
void renewOverlays();
void setSkinBase(const char*);
public:
static bool smDontRestrictOutside;
static F32 smDetailModification;
DECLARE_CONOBJECT(InteriorInstance);
static void initPersistFields();
static void consoleInit();
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*);
void onSceneRemove();
U32 getPointZone(const Point3F& p);
bool getOverlappingZones(SceneObject* obj, U32* zones, U32* numZones);
U32 calcDetailLevel(SceneState*, const Point3F&);
bool prepRenderImage(SceneState*, const U32, const U32, const bool);
void renderObject(SceneState*, SceneRenderImage*);
bool scopeObject(const Point3F& rootPosition,
const F32 rootDistance,
bool* zoneScopeState);
public:
void addChildren();
static bool getRenderDynamicLights() { return(smRenderDynamicLights); }
static void setRenderDynamicLights(bool val) { smRenderDynamicLights = val; }
private:
void activateLight(const U32 detail, const U32 lightIndex);
void deactivateLight(const U32 detail, const U32 lightIndex);
U32 packUpdate(NetConnection *, U32 mask, BitStream *stream);
void unpackUpdate(NetConnection *, BitStream *stream);
enum UpdateMaskBits {
InitMask = 1 << 0,
TransformMask = 1 << 1,
AlarmMask = 1 << 2,
// Reserved for light updates (8 bits for now)
_lightupdate0 = 1 << 3,
_lightupdate1 = 1 << 4,
_lightupdate2 = 1 << 5,
_lightupdate3 = 1 << 6,
_lightupdate4 = 1 << 7,
_lightupdate5 = 1 << 8,
_lightupdate6 = 1 << 9,
_lightupdate7 = 1 << 10,
SkinBaseMask = 1 << 11,
AudioMask = 1 << 12,
NextFreeMask = 1 << 13
};
enum Constants {
LightUpdateBitStart = 3,
LightUpdateBitEnd = 10
};
private:
StringTableEntry mInteriorFileName;
U32 mInteriorFileHash;
Resource<InteriorResource> mInteriorRes;
Vector<MaterialList*> mMaterialMaps;
StringTableEntry mSkinBase;
Vector< Vector<InteriorSubObject*> > mInteriorSubObjects;
bool mShowTerrainInside;
LM_HANDLE mLMHandle;
AudioProfile * mAudioProfile;
AudioEnvironment * mAudioEnvironment;
S32 mForcedDetailLevel;
U32 mCRC;
public:
LM_HANDLE getLMHandle() { return(mLMHandle); }
AudioProfile * getAudioProfile() { return(mAudioProfile); }
AudioEnvironment * getAudioEnvironment() { return(mAudioEnvironment); }
bool getPointInsideScale(const Point3F & pos, F32 * pScale); // ~0: outside -> 1: inside
// SceneLighting::InteriorProxy interface
Resource<InteriorResource> & getResource() {return(mInteriorRes);}
U32 getCRC() { return(mCRC); }
Vector<Vector<ColorI>*> mVertexColorsNormal;
Vector<Vector<ColorI>*> mVertexColorsAlarm;
void rebuildVertexColors();
Vector<ColorI>* getVertexColorsNormal(U32 detail);
Vector<ColorI>* getVertexColorsAlarm(U32 detail);
// Alarm state information
private:
enum AlarmState {
Normal = 0,
Alarm = 1
};
bool mAlarmState;
// 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; // One for each detail level.
LightUpdateGrouper* mUpdateGrouper; // Cuts down on net traffic
static U32 makeUpdateKey(const U32 detail, const U32 lightIndex);
static U32 detailFromUpdateKey(const U32 key);
static U32 indexFromUpdateKey(const U32 key);
// Animated light functions
void updateLightTime(const U32 detail, const U32 lightIndex, const U32 ms);
void downloadLightmaps(SceneState*, Interior*, LightInfo&);
void installLight(const U32 detail, const U32 lightIndex);
void updateLoopingLight(Interior*, LightInfo::Light&, const U32 lightIndex, const U32 ms);
void updateFlickerLight(Interior*, LightInfo::Light&, const U32 lightIndex, const U32 ms);
void updateRampLight(Interior*, LightInfo::Light&, const U32 lightIndex, const U32 ms);
void updateAllLights(const U32);
void updateLightMap(Interior*, LightInfo&, const U32 surfaceIndex);
void intensityMapMerge(U8* lightMap,
const U32 width, const U32 height,
const U8* intensityMap, const ColorI& color);
private:
void createTriggerTransform(const InteriorResTrigger*, MatrixF*);
};
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_

View file

@ -0,0 +1,549 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "interior/interiorLMManager.h"
#include "dgl/gTexManager.h"
#include "dgl/gBitmap.h"
#include "PlatformWin32/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, const U32 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, reinterpret_cast<U32>(&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::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 dont 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 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--)
{
InteriorLMInfo * interiorInfo = mInteriors[i];
// - skip base texture if all the instances have a texture defined
BitVector needTexture;
needTexture.setSize(mInteriors[i]->mNumLightmaps);
needTexture.clear();
// walk the instances and have them download their textures
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--)
{
// need base instance's texture?
if((j == 0) && !needTexture.test(k))
continue;
if(!instanceInfo->mLightmapHandles[k])
{
needTexture.set(k);
continue;
}
TextureObject * texObj = *instanceInfo->mLightmapHandles[k];
if(!texObj || !texObj->bitmap || texObj->texGLName)
{
needTexture.set(k);
continue;
}
#ifdef 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;
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_TRIBESMTVFMT_EXT:
{
if (smMTVertexBuffer != -1)
return smMTVertexBuffer;
smMTVertexBuffer = glAllocateVertexBufferEXT(512,GL_TRIBESMTVFMT_EXT,false);
return smMTVertexBuffer;
}
case GL_TRIBESFTVFMT_EXT:
{
if (smFTVertexBuffer != -1)
return smFTVertexBuffer;
smFTVertexBuffer = glAllocateVertexBufferEXT(512,GL_TRIBESFTVFMT_EXT,false);
return smFTVertexBuffer;
}
case GL_TRIBESFMTVFMT_EXT:
{
if (smFMTVertexBuffer != -1)
return smFMTVertexBuffer;
smFMTVertexBuffer = glAllocateVertexBufferEXT(512,GL_TRIBESFMTVFMT_EXT,false);
return smFMTVertexBuffer;
}
}
AssertFatal(false,"What? We should never get here!!!");
return -1;
}

View file

@ -0,0 +1,90 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, 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();
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);
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

View file

@ -0,0 +1,404 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, 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: %f, 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 != 0xFFFFFFFFF) {
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;
}
}
}

1330
interior/interiorRender.cc Normal file

File diff suppressed because it is too large Load diff

320
interior/interiorRes.cc Normal file
View file

@ -0,0 +1,320 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, 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(mPaths);
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 < mPaths.size(); i++)
delete mPaths[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;
}
}
// Paths
U32 numPaths;
stream.read(&numPaths);
mPaths.setSize(numPaths);
for (i = 0; i < mPaths.size(); i++)
mPaths[i] = NULL;
for (i = 0; i < mPaths.size(); i++) {
mPaths[i] = new InteriorPath;
if (mPaths[i]->read(stream) == false) {
AssertISV(false, avar("Unable to read path %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);
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(mPaths.size());
for (i = 0; i < mPaths.size(); i++) {
if (mPaths[i]->write(stream) == false) {
AssertISV(false, "Unable to write path 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
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;
}
}

152
interior/interiorRes.h Normal file
View file

@ -0,0 +1,152 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, 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 InteriorResource : public ResourceInstance
{
typedef ResourceInstance Parent;
static const U32 smFileVersion;
protected:
Vector<Interior*> mDetailLevels;
Vector<Interior*> mSubObjects;
Vector<InteriorResTrigger*> mTriggers;
Vector<InteriorPath*> mPaths;
Vector<InteriorPathFollower*> mInteriorPathFollowers;
Vector<ForceField*> mForceFields;
Vector<AISpecialNode*> mAISpecialNodes;
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 getNumPaths() const;
S32 getNumInteriorPathFollowers() const;
S32 getNumForceFields() const;
S32 getNumSpecialNodes() const;
Interior* getDetailLevel(const U32);
Interior* getSubObject(const U32);
InteriorResTrigger* getTrigger(const U32);
InteriorPath* getPath(const U32);
InteriorPathFollower* getInteriorPathFollower(const U32);
ForceField* getForceField(const U32);
AISpecialNode* getSpecialNode(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::getNumPaths() const
{
return mPaths.size();
}
inline S32 InteriorResource::getNumSpecialNodes() const
{
return mAISpecialNodes.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 InteriorPath* InteriorResource::getPath(const U32 idx)
{
AssertFatal(idx < getNumPaths(), "Error, out of bounds path!");
return mPaths[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];
}
#endif // _H_INTERIORRES_

View file

@ -0,0 +1,200 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "interior/interiorResObjects.h"
#include "Core/stream.h"
#include "Math/mathIO.h"
//--------------------------------------------------------------------------
//--------------------------------------
//
bool InteriorResTrigger::read(Stream& stream)
{
U32 i, size;
stream.readString(mName);
// 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);
// 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);
}
//--------------------------------------------------------------------------
//--------------------------------------
//
InteriorPath::InteriorPath()
{
mName[0] = '\0';
mWayPoints = NULL;
mNumWayPoints = 0;
mLooping = false;
}
InteriorPath::~InteriorPath()
{
delete [] mWayPoints;
mWayPoints = NULL;
mNumWayPoints = 0;
}
bool InteriorPath::read(Stream& stream)
{
AssertFatal(mWayPoints == NULL, "Hm, this is probably going to cause problems, reading a path twice...");
stream.readString(mName);
stream.read(&mNumWayPoints);
mWayPoints = new WayPoint[mNumWayPoints];
for (U32 i = 0; i < mNumWayPoints; i++) {
mathRead(stream, &mWayPoints[i].pos);
mathRead(stream, &mWayPoints[i].rot);
stream.read(&mWayPoints[i].msToNext);
}
stream.read(&mTotalMS);
stream.read(&mLooping);
return (stream.getStatus() == Stream::Ok);
}
bool InteriorPath::write(Stream& stream) const
{
stream.writeString(mName);
stream.write(mNumWayPoints);
for (U32 i = 0; i < mNumWayPoints; i++) {
mathWrite(stream, mWayPoints[i].pos);
mathWrite(stream, mWayPoints[i].rot);
stream.write(mWayPoints[i].msToNext);
}
stream.write(mTotalMS);
stream.write(mLooping);
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();
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 InteriorPathFollower::write(Stream& stream) const
{
stream.writeString(mName);
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);
}
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);
}

View file

@ -0,0 +1,115 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, 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;
class InteriorResTrigger
{
public:
enum Constants {
MaxNameChars = 255
};
char mName[MaxNameChars+1];
Point3F mOffset;
Polyhedron mPolyhedron;
public:
InteriorResTrigger() { }
bool read(Stream& stream);
bool write(Stream& stream) const;
};
class InteriorPath
{
public:
struct WayPoint {
Point3F pos;
QuatF rot;
U32 msToNext;
};
public:
char mName[256];
WayPoint* mWayPoints;
U32 mNumWayPoints;
U32 mTotalMS;
bool mLooping;
public:
InteriorPath();
~InteriorPath();
bool read(Stream& stream);
bool write(Stream& stream) const;
};
class InteriorPathFollower
{
public:
StringTableEntry mName;
U32 mInteriorResIndex;
U32 mPathIndex;
Point3F mOffset;
Vector<StringTableEntry> mTriggers;
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;
};
#endif // _H_INTERIORRESOBJECTS_

View file

@ -0,0 +1,93 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, 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()
{
//
}

View file

@ -0,0 +1,65 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, 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_

104
interior/itf.h Normal file
View file

@ -0,0 +1,104 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, 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;
U8 fogColor[4];
};
Point2F texCoord;
Point2F lmCoord;
};
struct OutputPointFC_VB
{
Point3F point;
U8 currentColor[4];
U8 fogColor[4];
Point2F texCoord;
Point2F lmCoord;
};
struct OutputPointSP_FC_VB
{
Point3F point;
U8 lmColor[4];
U8 fogColor[4];
Point2F texCoord;
};
#ifndef TARG_MACCARB // don't bracket on mac.
extern "C" {
#endif
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);
extern F32 texGen0[8];
extern F32 texGen1[8];
extern void* fogCoordinatePointer;
#ifndef TARG_MACCARB // don't bracket on mac.
}
#endif
#endif

657
interior/itfdump.asm Normal file
View file

@ -0,0 +1,657 @@
;
; NASM version of tribes2/src/interior/itfdump.asm
;
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
; 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 ebp
ret
; More suckage
%ifdef __linux
global processTriFanSP
processTriFanSP:
%else
global _processTriFanSP
_processTriFanSP:
%endif
; prologue
push ebp
mov ebp, esp
; 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 ebp
ret
; More suckage
%ifdef __linux
global processTriFanVC_TF
processTriFanVC_TF:
%else
global _processTriFanVC_TF
_processTriFanVC_TF:
%endif
; prologue
push ebp
mov ebp, esp
; 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 ebp
ret
; More suckagea
%ifdef __linux
global processTriFanSP_FC
processTriFanSP_FC:
%else
global _processTriFanSP_FC
_processTriFanSP_FC:
%endif
; prologue
push ebp
mov ebp, esp
; 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 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
; 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 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
; 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 ebp
ret

311
interior/itfdump.cc Normal file
View file

@ -0,0 +1,311 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "interior/itf.h"
//two55 dd 0x437F0000
//alpha dd 0
//============================================================
void 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 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 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 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 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 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++;
}
}

311
interior/itfdump_c.cc Normal file
View file

@ -0,0 +1,311 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, 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++;
}
}

View file

@ -0,0 +1,77 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, 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 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]);
}
}

View file

@ -0,0 +1,108 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, 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_

532
interior/mirrorSubObject.cc Normal file
View file

@ -0,0 +1,532 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "interior/mirrorSubObject.h"
#include "interior/interiorInstance.h"
#include "interior/interior.h"
#include "dgl/materialList.h"
#include "Core/stream.h"
#include "PlatformWin32/platformGL.h"
#include "dgl/dgl.h"
#include "sceneGraph/sgUtil.h"
IMPLEMENT_CONOBJECT(MirrorSubObject);
//--------------------------------------------------------------------------
MirrorSubObject::MirrorSubObject()
{
mTypeMask = StaticObjectType;
mInitialized = false;
mWhite = NULL;
}
MirrorSubObject::~MirrorSubObject()
{
delete mWhite;
mWhite = NULL;
}
//--------------------------------------------------------------------------
void MirrorSubObject::initPersistFields()
{
Parent::initPersistFields();
//
}
//--------------------------------------------------------------------------
void MirrorSubObject::renderObject(SceneState* state, SceneRenderImage* image)
{
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on entry");
SubObjectRenderImage* sori = static_cast<SubObjectRenderImage*>(image);
if (mZone == 0) {
state->setupZoneProjection(getInstance()->getCurrZone(0));
} else {
state->setupZoneProjection(mZone + getInstance()->getZoneRangeStart() - 1);
}
RectI viewport;
dglGetViewport(&viewport);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
dglMultMatrix(&getSOTransform());
glScalef(getSOScale().x, getSOScale().y, getSOScale().z);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
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);
glEnableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glColor4f(1, 1, 1, mAlphaLevel);
Interior* interior = getInstance()->getDetailLevel(sori->mDetailLevel);
glVertexPointer(3, GL_FLOAT, sizeof(ItrPaddedPoint), interior->mPoints.address());
glBindTexture(GL_TEXTURE_2D, interior->mMaterialList->getMaterial(interior->mSurfaces[surfaceStart].textureIndex).getGLName());
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);
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]);
}
glDisableClientState(GL_VERTEX_ARRAY);
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ZERO);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
dglSetViewport(viewport);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
dglSetCanonicalState();
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on exit");
}
//--------------------------------------------------------------------------
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!");
RectI viewport;
dglGetViewport(&viewport);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
const SceneState::ZoneState& baseState = pCurrState->getBaseZoneState();
dglSetViewport(baseState.viewport);
glDisable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ZERO);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
glColor3f(1, 0, 0);
glBegin(GL_TRIANGLE_FAN);
glVertex3f(-1, -1, 0);
glVertex3f(-1, 1, 0);
glVertex3f( 1, 1, 0);
glVertex3f( 1, -1, 0);
glEnd();
// This is fairly tricky-tricky, so here's what's going on. We need this poly
// to be at the far plane, but have it's rasterization coords be exactly that of
// the final poly. So we copy the w-coord post projection into the z coord. this
// ensures that after the w divide, we have the z coord == 1. This would screw
// up texturing, but we don't really care, do we?
if (mZone == 0)
pParentState->setupZoneProjection(getInstance()->getCurrZone(0));
else
pParentState->setupZoneProjection(mZone + getInstance()->getZoneRangeStart() - 1);
MatrixF finalProj(true);
MatrixF currProj;
dglGetProjection(&currProj);
((F32*)finalProj)[10] = 0.0f;
((F32*)finalProj)[11] = 0.9999f;
finalProj.mul(currProj);
glMatrixMode(GL_PROJECTION);
dglLoadMatrix(&finalProj);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glPushMatrix();
dglMultMatrix(&getSOTransform());
glScalef(getSOScale().x, getSOScale().y, getSOScale().z);
glColor3f(0, 1, 0);
Interior* interior = getInstance()->getDetailLevel(mDetailLevel);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(ItrPaddedPoint), interior->mPoints.address());
for (U32 i = 0; i < surfaceCount; i++) {
const Interior::Surface& rSurface = interior->mSurfaces[surfaceStart + i];
glBegin(GL_TRIANGLE_STRIP);
for (U32 j = 0; j < rSurface.windingCount; j++) {
const Point3F& rPoint = interior->mPoints[interior->mWindings[rSurface.windingStart + j]].point;
glVertex3fv(rPoint);
}
glEnd();
}
glDisableClientState(GL_VERTEX_ARRAY);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
dglSetViewport(viewport);
glDepthFunc(GL_LEQUAL);
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!");
RectI viewport;
dglGetViewport(&viewport);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
const SceneState::ZoneState& baseState = pCurrState->getBaseZoneState();
dglSetViewport(baseState.viewport);
glDisable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDepthFunc(GL_ALWAYS);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glColor3f(0, 0, 1);
glBegin(GL_TRIANGLE_FAN);
glVertex3f(-1, -1, 1);
glVertex3f(-1, 1, 1);
glVertex3f( 1, 1, 1);
glVertex3f( 1, -1, 1);
glEnd();
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
if (mZone == 0) {
pParentState->setupZoneProjection(getInstance()->getCurrZone(0));
} else {
pParentState->setupZoneProjection(mZone + getInstance()->getZoneRangeStart() - 1);
}
glMatrixMode(GL_MODELVIEW);
dglLoadMatrix(&pParentState->mModelview);
dglMultMatrix(&getSOTransform());
glScalef(getSOScale().x, getSOScale().y, getSOScale().z);
// Need to have texturing turned on because of lame LSB z buffer errors
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, mWhite->getGLName());
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glColor3f(1, 0, 1);
glEnableClientState(GL_VERTEX_ARRAY);
Interior* interior = getInstance()->getDetailLevel(mDetailLevel);
glVertexPointer(3, GL_FLOAT, sizeof(ItrPaddedPoint), interior->mPoints.address());
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]);
}
glDisableClientState(GL_VERTEX_ARRAY);
glDisable(GL_TEXTURE_2D);
glBlendFunc(GL_ONE, GL_ZERO);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
dglSetViewport(viewport);
glDepthFunc(GL_LEQUAL);
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(mCentroid);
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;
// This is really bad, but it's just about the only good place for this...
if (getInstance()->isClientObject() && mWhite == NULL)
mWhite = new TextureHandle("special/whiteAlpha0", MeshTexture);
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();
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;
}

View file

@ -0,0 +1,87 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, 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*, const Point3F&);
bool renderDetailDependant() const;
U32 getZone() const;
void noteTransformChange();
InteriorSubObject* clone(InteriorInstance*) const;
// Rendering
protected:
void renderObject(SceneState*, SceneRenderImage*);
void transformModelview(const U32, const MatrixF&, MatrixF*);
void transformPosition(const U32, Point3F&);
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*);
public:
MirrorSubObject();
~MirrorSubObject();
DECLARE_CONOBJECT(MirrorSubObject);
static void initPersistFields();
};
#endif // _H_MIRRORSUBOBJECT