//----------------------------------------------------------------------------- // Torque Game Engine // Copyright (C) GarageGames.com, Inc. //----------------------------------------------------------------------------- #ifndef _INTERIOR_H_ #define _INTERIOR_H_ //Includes #ifndef _PLATFORM_H_ #include "platform/platform.h" #endif #ifndef _COLOR_H_ #include "core/color.h" #endif #ifndef _COLLISION_H_ #include "collision/collision.h" #endif #ifndef _RESMANAGER_H_ #include "core/resManager.h" #endif #ifndef _TVECTOR_H_ #include "core/tVector.h" #endif #ifndef _MPOINT_H_ #include "math/mPoint.h" #endif #ifndef _MPLANE_H_ #include "math/mPlane.h" #endif #ifndef _MBOX_H_ #include "math/mBox.h" #endif #ifndef _MSPHERE_H_ #include "math/mSphere.h" #endif #ifndef _CONVEX_H_ #include "collision/convex.h" #endif #ifndef _INTERIORLMMANAGER_H_ #include "interior/interiorLMManager.h" #endif //-------------------------------------- Forward declarations class Stream; class EditGeometry; class InteriorInstance; class GBitmap; class TextureHandle; class RectD; class SphereF; class MatrixF; class SceneState; class MaterialList; class AbstractPolyList; class InteriorSubObject; class TranslucentSubObject; class BitVector; struct RayInfo; struct EdgeList; class SurfaceHash; class InteriorPolytope; class FloorPlan; class LightInfo; class PlaneRange; class EditInteriorResource; //-------------------------------------------------------------------------- class InteriorConvex : public Convex { typedef Convex Parent; friend class Interior; friend class InteriorInstance; protected: Interior* pInterior; public: S32 hullId; Box3F box; InteriorConvex() { mType = InteriorConvexType; } InteriorConvex(const InteriorConvex& cv) { mObject = cv.mObject; pInterior = cv.pInterior; hullId = cv.hullId; box = box; } Box3F getBoundingBox() const; Box3F getBoundingBox(const MatrixF& mat, const Point3F& scale) const; Point3F support(const VectorF& v) const; void getFeatures(const MatrixF& mat,const VectorF& n, ConvexFeature* cf); void getPolyList(AbstractPolyList* list); }; class ZoneVisDeterminer { enum Mode { FromState, FromRects }; Mode mMode; SceneState* mState; U32 mZoneRangeOffset; U32 mParentZone; public: ZoneVisDeterminer() : mMode(FromRects), mState(NULL) { } void runFromState(SceneState*, U32, U32); void runFromRects(SceneState*, U32, U32); bool isZoneVisible(const U32) const; }; struct ItrPaddedPoint { Point3F point; union { F32 fogCoord; U8 fogColor[4]; }; }; //------------------------------------------------------------------------------ //-------------------------------------- CLASS NOTES // Interior: Base for all interior geometries. Contains all lighting, poly, // portal zone, bsp info, etc. to render an interior. // // Internal Structure Notes: // IBSPNode: // planeIndex: Obv. // frontIndex/backIndex: Top bit indicates if children are leaves. // Next bit indicates if leaf children are solid. // // IBSPLeafSolid: // planeIndex: obv. // surfaceIndex/surfaceCount: Polys that are on the faces of this leaf. Only // used for collision/surface info detection. // //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ class Interior { friend class FloorPlan; friend class EditGeometry; friend class InteriorInstance; friend class SceneLighting; friend class InteriorProxy; friend class TranslucentSubObject; friend class MirrorSubObject; friend class InteriorConvex; friend class InteriorLMManager; friend class EditInteriorResource; public: Interior(); ~Interior(); // Support for interior light map border sizes. private: U32 mLightMapBorderSize; public: U32 getLightMapBorderSize() const {return mLightMapBorderSize;} void setLightMapBorderSize(U32 value) {mLightMapBorderSize = value;} // Misc U32 getDetailLevel() const; U32 getMinPixels() const; const Box3F& getBoundingBox() const; S32 getNumZones() const; // Rendering bool prepForRendering(const char* path); void rebuildVertexColors(LM_HANDLE instanceHandle, Vector* normal, Vector* 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* normalVLights, const Vector* alarmVLights); void render_vc_tf(const bool useAlarmLighting, MaterialList* pMaterials, const LM_HANDLE instanceHandle, const Vector* normalVLights, const Vector* alarmVLights); void render_vc_fc(const bool useAlarmLighting, MaterialList* pMaterials, const LM_HANDLE instanceHandle, const Vector* normalVLights, const Vector* alarmVLights); void renderARB_vc_tf(const bool useAlarmLighting, MaterialList* pMaterials, const LM_HANDLE instanceHandle, const Vector* normalVLights, const Vector* 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); void renderAsShape(); bool useFogCoord(); bool scopeZones(const S32 baseZone, const Point3F& interiorRoot, bool* interiorScopingState); //-------------------------------------- Collision Interface and zone scans bool scanZones(const Box3F&, const MatrixF&, U16* zones, U32* numZones); bool castRay(const Point3F&, const Point3F&, RayInfo*); bool buildPolyList(AbstractPolyList*, const Box3F&, const MatrixF&, const Point3F&); bool buildLightPolyList(U32* lightSurfaces, U32* numLightSurfaces, const Box3F&, const MatrixF&, const Point3F&); bool getIntersectingHulls(const Box3F&, U16* hulls, U32* numHulls); bool getIntersectingVehicleHulls(const Box3F&, U16* hulls, U32* numHulls); protected: bool castRay_r(const U16, const U16, const Point3F&, const Point3F&, RayInfo*); void buildPolyList_r(InteriorPolytope& polytope, SurfaceHash& hash); void scanZone_r(const U16 node, const Point3F& center, const Point3F& axisx, const Point3F& axisy, const Point3F& axisz, U16* zones, U32* numZones); void scanZoneNew(InteriorPolytope& polytope, U16* zones, U32* numZones); void scopeZone(const U32 currZone, bool* interiorScopingState, const Point3F& interiorRoot, Vector& zoneStack, Vector& planeStack, Vector& 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 bool read(Stream& stream); bool write(Stream& stream) const; bool readVehicleCollision(Stream& stream); bool writeVehicleCollision(Stream& stream) const; protected: 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 protected: struct IBSPNode { U16 planeIndex; U16 frontIndex; U16 backIndex; U16 terminalZone; // if high bit set, then the lower 15 bits are the zone // of any of the subsidiary nodes. Note that this is // going to overestimate some, since an object could be // completely contained in solid, but it's probably // going to turn out alright. }; struct IBSPLeafSolid { U32 surfaceIndex; U16 surfaceCount; }; bool isBSPLeafIndex(U16 index) const; bool isBSPSolidLeaf(U16 index) const; bool isBSPEmptyLeaf(U16 index) const; U16 getBSPSolidLeafIndex(U16 index) const; U16 getBSPEmptyLeafZone(U16 index) const; void setupAveTexGenLength(); void truncateZoneTree(); void truncateZoneNode(const U16); bool getUnifiedZone(const U16, S32*); public: static U16 getPlaneIndex(const U16 index); static bool planeIsFlipped(const U16 index); const PlaneF& getPlane(const U16 index) const; PlaneF getFlippedPlane(const U16 index) const; protected: bool areEqualPlanes(U16, U16) const; bool isNullSurfaceIndex(const U32 index) const; bool isVehicleNullSurfaceIndex(const U32 index) const; U32 getNullSurfaceIndex(const U32 index) const; U32 getVehicleNullSurfaceIndex(const U32 index) const; //-------------------------------------- Portals and Zone structures struct Zone { U16 portalStart; U16 portalCount; U32 surfaceStart; U32 planeStart; U16 surfaceCount; U16 planeCount; U16 flags; U16 zoneId; // This is ephemeral, not persisted out. }; struct Portal { U16 planeIndex; U16 triFanCount; U32 triFanStart; // portals can have multiple windings U16 zoneFront; U16 zoneBack; }; //-------------------------------------- Poly/Surface structures public: enum SurfaceFlags { SurfaceDetail = BIT(0), SurfaceAmbiguous = BIT(1), SurfaceOrphan = BIT(2), SurfaceSharedLMaps = BIT(3), // Indicates that the alarm and normal states share a lightmap (for mission lighter) SurfaceOutsideVisible = BIT(4), SurfaceFlagMask = (SurfaceDetail | SurfaceAmbiguous | SurfaceOrphan | SurfaceSharedLMaps | SurfaceOutsideVisible) }; enum ZoneFlags { ZoneInside = BIT(0) }; const bool isSurfaceOutsideVisible(U32 surface) const; 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 = BIT(0), AnimationLoop = BIT(1), AnimationFlicker = BIT(2), AnimationTypeMask = BIT(3) - 1, AlarmLight = BIT(3) }; enum LightType { AmbientLooping = AnimationAmbient | AnimationLoop, AmbientFlicker = AnimationAmbient | AnimationFlicker, TriggerableLoop = AnimationLoop, TriggerableFlicker = AnimationFlicker, TriggerableRamp = 0 }; struct AnimatedLight { U32 nameIndex; ///< Light's name U32 stateIndex; ///< start point in the state list U16 stateCount; ///< number of states in this light U16 flags; ///< flags (Apply AnimationTypeMask to get type) U32 duration; ///< total duration of animation (ms) }; protected: struct LightState { U8 red; ///< state's color U8 green; U8 blue; U8 _color_padding_; U32 activeTime; ///< Time (ms) at which this state becomes active U32 dataIndex; ///< StateData count and index for this state U16 dataCount; U16 __32bit_padding__; }; struct LightStateData { U32 surfaceIndex; ///< Surface affected by this data U32 mapIndex; ///< Index into StateDataBuffer (0xFFFFFFFF indicates none) U16 lightStateIndex; ///< Entry to modify in InteriorInstance U16 __32bit_padding__; }; // convex hull collision structures... protected: struct ConvexHull { F32 minX; F32 maxX; F32 minY; F32 maxY; F32 minZ; F32 maxZ; U32 hullStart; U32 surfaceStart; U32 planeStart; U16 hullCount; U16 surfaceCount; U32 polyListPlaneStart; U32 polyListPointStart; U32 polyListStringStart; U16 searchTag; }; struct CoordBin { U32 binStart; U32 binCount; }; protected: LM_HANDLE mLMHandle; public: LM_HANDLE getLMHandle() {return(mLMHandle);} // SceneLighting::InteriorProxy interface const Surface & getSurface(const U32 surface) const; const U32 getSurfaceCount() const; const 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 protected: U32 mDetailLevel; U32 mMinPixels; F32 mAveTexGenLength; // Set in Interior::read after loading the texgen planes. Box3F mBoundingBox; SphereF mBoundingSphere; Vector mPlanes; Vector mPoints; Vector mPointVisibility; ColorF mBaseAmbient; ColorF mAlarmAmbient; Vector mBSPNodes; Vector mBSPSolidLeaves; bool mPreppedForRender; MaterialList* mMaterialList; TextureHandle* mWhite; TextureHandle* mWhiteRGB; TextureHandle* mLightFalloff; Vector mEnvironMaps; Vector mEnvironFactors; U32 mValidEnvironMaps; Vector mWindings; Vector mTexGenEQs; Vector mLMTexGenEQs; Vector mWindingIndices; Vector mSurfaces; Vector mNullSurfaces; Vector mSolidLeafSurfaces; // Portals and zones Vector mZones; Vector mZonePlanes; Vector mZoneSurfaces; Vector mZonePortalList; Vector mPortals; // Subobjects: Doors, translucencies, mirrors, etc. Vector mSubObjects; // Lighting info bool mHasAlarmState; U32 mNumLightStateEntries; Vector mLightmaps; Vector mLightmapKeep; Vector mNormalLMapIndices; Vector mAlarmLMapIndices; U32 mNumTriggerableLights; // Note: not persisted // Persistent animated light structures Vector mAnimatedLights; Vector mLightStates; Vector mStateData; Vector mStateDataBuffer; Vector mNameBuffer; Vector mConvexHulls; Vector mConvexHullEmitStrings; Vector mHullIndices; Vector mHullEmitStringIndices; Vector mHullSurfaceIndices; Vector mHullPlaneIndices; Vector mPolyListPlanes; Vector mPolyListPoints; Vector mPolyListStrings; CoordBin mCoordBins[NumCoordBins * NumCoordBins]; Vector mCoordBinIndices; U32 mCoordBinMode; Vector mVehicleConvexHulls; Vector mVehicleConvexHullEmitStrings; Vector mVehicleHullIndices; Vector mVehicleHullEmitStringIndices; Vector mVehicleHullSurfaceIndices; Vector mVehicleHullPlaneIndices; Vector mVehiclePolyListPlanes; Vector mVehiclePolyListPoints; Vector mVehiclePolyListStrings; Vector mVehiclePoints; Vector mVehicleNullSurfaces; Vector mVehiclePlanes; Vector mVehicleWindings; Vector mVehicleWindingIndices; U16 mSearchTag; //-------------------------------------- Private interface protected: const char* getName(const U32 nameIndex) const; static const char* getLightTypeString(const LightType); S32 getZoneForPoint(const Point3F&) const; void debugRender(MaterialList* pMaterials, LM_HANDLE instanceHandle); void debugRenderPortals(); void debugNormalRenderLines(); void debugShowDetail(); void debugShowAmbiguous(); void debugShowLightmaps(LM_HANDLE instanceHandle); void debugShowPortalZones(); void debugShowCollisionFans(); void debugShowOrphan(); void debugShowStrips(); void debugShowTexturesOnly(MaterialList* pMaterials); void debugShowLargeTextures(MaterialList* pMaterials); void debugShowNullSurfaces(MaterialList* pMaterials); void debugShowOutsideVisible(); void debugShowHullSurfaces(); void debugShowVehicleHullSurfaces(MaterialList* pMaterials); // void debugShowVertexColors(MaterialList* pMaterials); void debugShowDetailLevel(); void debugShowOrphansFinish(); 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& 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(const U16 index) const { AssertFatal(U32(index & ~0x8000) < mPlanes.size(), "Interior::getPlane: planeIndex out of range"); return mPlanes[index & ~0x8000]; } inline PlaneF Interior::getFlippedPlane(const U16 index) const { PlaneF plane = getPlane(index); if(Interior::planeIsFlipped(index)) plane.neg(); return plane; } inline U16 Interior::getPlaneIndex(const U16 index) { return U16(index & ~0x8000); } inline bool Interior::planeIsFlipped(const U16 index) { return (index >> 15)!=0; } inline bool Interior::areEqualPlanes(U16 o, U16 t) const { return (o & ~0x8000) == (t & ~0x8000); } inline 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 ""; } } 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::isSurfaceOutsideVisible: Invalid surface index"); return ((mSurfaces[surface].surfaceFlags & SurfaceOutsideVisible)!=0); } inline const U32 Interior::getWindingCount() const { return(mWindings.size()); } #endif //_INTERIOR_H_