tge/engine/interior/interiorInstance.h
2025-02-17 23:17:30 -06:00

459 lines
16 KiB
C++
Executable File

//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _INTERIORINSTANCE_H_
#define _INTERIORINSTANCE_H_
//Includes
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#endif
#ifndef _SCENEOBJECT_H_
#include "sim/sceneObject.h"
#endif
#ifndef _RESMANAGER_H_
#include "core/resManager.h"
#endif
#ifndef _INTERIORRES_H_
#include "interior/interiorRes.h"
#endif
#ifndef _INTERIORLMMANAGER_H_
#include "interior/interiorLMManager.h"
#endif
#ifndef _BITVECTOR_H_
#include "core/bitVector.h"
#endif
#ifndef _COLOR_H_
#include "core/color.h"
#endif
class AbstractPolyList;
class LightUpdateGrouper;
class InteriorSubObject;
class InteriorResTrigger;
class MaterialList;
class TextureObject;
class FloorPlan;
class Convex;
class AudioProfile;
class AudioEnvironment;
//--------------------------------------------------------------------------
class InteriorInstance : public SceneObject
{
typedef SceneObject Parent;
friend class SceneLighting;
friend class FloorPlan;
public:
InteriorInstance();
~InteriorInstance();
static void init();
static void destroy();
// Collision
public:
bool buildPolyList(AbstractPolyList *polyList, const Box3F &box, const SphereF &sphere);
bool castRay(const Point3F &start, const Point3F &end, RayInfo *info);
virtual void setTransform(const MatrixF &mat);
void buildConvex(const Box3F& box,Convex* convex);
private:
Convex* mConvexList;
public:
/// @name Lighting control
/// @{
/// This returns true if the interior is in an alarm state. Alarm state
/// will put different lighting into the interior and also possibly
/// have an audio element also.
bool inAlarmState() {return(mAlarmState);}
/// This sets the alarm mode of the interior.
/// @param alarm If true the interior will be in an alarm state next frame
void setAlarmMode(const bool alarm);
/// Activates a light with the given name on all detail levels of the interior
/// @param pLightName Name of the light
void activateLight(const char* pLightName);
/// Deactivates a light with the given name on all detail levels of the interior
/// @param pLightName Name of the light
void deactivateLight(const char* pLightName);
/// Echos out all the lights in the interior, starting with triggerable then
/// animated lights
void echoTriggerableLights();
/// @}
public:
/// @name Subobject access interface
/// @{
/// Returns the number of detail levels for an object
U32 getNumDetailLevels();
/// Gets the interior associated with a particular detail level
/// @param level Detail level
Interior* getDetailLevel(const U32 level);
/// Sets the detail level to render manually
/// @param level Detail level to force
void setDetailLevel(S32 level = -1) { mForcedDetailLevel = level; }
/// @}
// Material management for overlays
public:
/// Reloads material information if the interior skin changes
void renewOverlays();
/// Sets the interior skin to something different
/// @param newBase New base skin
void setSkinBase(const char *newBase);
public:
static bool smDontRestrictOutside;
static F32 smDetailModification;
DECLARE_CONOBJECT(InteriorInstance);
static void initPersistFields();
static void consoleInit();
void onStaticModified( const char* slotName );
/// Reads the lightmaps of the interior into the provided pointer
/// @param lightmaps Lightmaps in the interior (out)
bool readLightmaps(GBitmap ****lightmaps);
protected:
bool onAdd();
void onRemove();
void inspectPreApply();
void inspectPostApply();
static U32 smLightUpdatePeriod;
static bool smRenderDynamicLights;
U32 mLightUpdatedTime;
void setLightUpdatedTime(const U32);
U32 getLightUpdatedTime() const;
bool onSceneAdd(SceneGraph *graph);
void onSceneRemove();
U32 getPointZone(const Point3F& p);
bool getOverlappingZones(SceneObject* obj, U32* zones, U32* numZones);
bool getLightingAmbientColor(ColorF * col)
{
return false;
}
U32 calcDetailLevel(SceneState*, const Point3F&);
bool prepRenderImage(SceneState *state, const U32 stateKey, const U32 startZone, const bool modifyBaseZoneState);
void renderObject(SceneState *state, SceneRenderImage *image);
bool scopeObject(const Point3F& rootPosition,
const F32 rootDistance,
bool* zoneScopeState);
public:
/// This is used to store the preferred lighting method for this interior. It is networked.
bool mUseGLLighting;
/// This indicates what we're actually doing; that way we can bump things to use GL lighting when they are moved.
bool mDoSimpleDynamicRender;
/// Not yet implemented
void addChildren();
/// Returns true if the interiors are rendering dynamic lighting
static bool getRenderDynamicLights() { return(smRenderDynamicLights); }
/// Turns on or off dynamic lighting of interiors
/// @param val If true dynamic lighting is enabled
static void setRenderDynamicLights(bool val) { smRenderDynamicLights = val; }
private:
/// @name Light utility methods
/// These should not be called directly. Use the public activateLight(const char *)
/// method instead because unless the detail level is rendering and it's much
/// easier to not manage the lights on a per-detail level basis.
/// @{
/// Activates a specific light for a detail level
/// @param detail Detail level
/// @param lightIndex Index of light in light list
void activateLight(const U32 detail, const U32 lightIndex);
/// Deactivates a specific light for a detail level
/// @param detail Detail level
/// @param lightIndex Index of light in the light list
void deactivateLight(const U32 detail, const U32 lightIndex);
/// @}
U32 packUpdate (NetConnection *conn, U32 mask, BitStream *stream);
void unpackUpdate(NetConnection *conn, BitStream *stream);
enum UpdateMaskBits {
InitMask = BIT(0),
TransformMask = BIT(1),
AlarmMask = BIT(2),
// Reserved for light updates (8 bits for now)
_lightupdate0 = BIT(3),
_lightupdate1 = BIT(4),
_lightupdate2 = BIT(5),
_lightupdate3 = BIT(6),
_lightupdate4 = BIT(7),
_lightupdate5 = BIT(8),
_lightupdate6 = BIT(9),
_lightupdate7 = BIT(10),
SkinBaseMask = BIT(11),
AudioMask = BIT(12),
NextFreeMask = BIT(13)
};
enum Constants {
LightUpdateBitStart = 3,
LightUpdateBitEnd = 10
};
private:
StringTableEntry mInteriorFileName; ///< File name of the interior this instance encapuslates
U32 mInteriorFileHash; ///< Hash for interior file name, used for sorting
Resource<InteriorResource> mInteriorRes; ///< Interior managed by resource manager
Vector<MaterialList*> mMaterialMaps; ///< Materials for this interior
StringTableEntry mSkinBase; ///< Skin for this interior
Vector< Vector<InteriorSubObject*> > mInteriorSubObjects; ///< Sub objects of this interior
bool mShowTerrainInside; ///< Enables or disables terrain showing through the interior
LM_HANDLE mLMHandle; ///< Handle to the light manager
AudioProfile * mAudioProfile; ///< Audio profile
AudioEnvironment * mAudioEnvironment; ///< Audio environment
S32 mForcedDetailLevel; ///< Forced LOD, if -1 auto LOD
U32 mCRC; ///< CRC for the interior
public:
/// Returns the Light Manager handle
LM_HANDLE getLMHandle() { return(mLMHandle); }
/// Returns the audio profile
AudioProfile * getAudioProfile() { return(mAudioProfile); }
/// Returns the audio environment
AudioEnvironment * getAudioEnvironment() { return(mAudioEnvironment); }
/// This is used to determine just how 'inside' a point is in an interior.
/// This is used by the environmental audio code for audio properties and the
/// function always returns true.
/// @param pos Point to test
/// @param pScale How inside is the point 0 = totally outside, 1 = totally inside (out)
bool getPointInsideScale(const Point3F & pos, F32 * pScale); // ~0: outside -> 1: inside
/// Returns the interior resource
Resource<InteriorResource> & getResource() {return(mInteriorRes);} // SceneLighting::InteriorProxy interface
/// Returns the CRC for validation
U32 getCRC() { return(mCRC); }
/// @name Vertex Lighting
/// Vertex lighting is the alternative to lightmapped interiors
/// @{
Vector<Vector<ColorI>*> mVertexColorsNormal; ///< Vertex colors under normal lighting per detail level
Vector<Vector<ColorI>*> mVertexColorsAlarm; ///< Vertex colors under alarm lighting per detail level
/// Rebuilds the vertex colors for alarm and normal states for all detail levels
void rebuildVertexColors();
/// Returns the normal vertex lighting colors for a detail level
/// @param detail Detail level
Vector<ColorI>* getVertexColorsNormal(U32 detail);
/// Returns the alarm vertex lighting colors for a detail level
/// @param detail Detail level
Vector<ColorI>* getVertexColorsAlarm(U32 detail);
/// @}
// Alarm state information
private:
enum AlarmState {
Normal = 0,
Alarm = 1
};
bool mAlarmState; ///< Alarm state of the interior
// LightingAnimation information
private:
struct LightInfo {
struct Light {
U32 curState;
U32 curTime;
ColorI curColor;
bool active;
bool alarm;
};
struct StateDataInfo {
ColorI curColor;
U8* curMap;
bool alarm;
};
Vector<Light> mLights;
BitVector mSurfaceInvalid;
Vector<StateDataInfo> mStateDataInfo;
};
Vector<LightInfo> mLightInfo; ///< Light info, one per detail level
LightUpdateGrouper* mUpdateGrouper; ///< Designed to group net updates for lights to reduce traffic
/// @name Light Grouper
/// This is for managing light updates across the network
/// @{
/// Creates an update key for the LightGrouper
/// @param detail Detail level
/// @param lightIndex Index of light in the interior
static U32 makeUpdateKey(const U32 detail, const U32 lightIndex);
/// Takes an update key and returns the detail level part of it
/// @param key Update key
static U32 detailFromUpdateKey(const U32 key);
/// Takes an update key and returns the light index part of it
/// 2param key Update key
static U32 indexFromUpdateKey(const U32 key);
/// @}
/// @name Animated light functions
/// @{
/// Steps the animated light simulation by a delta
/// @param detail Detail level of interior
/// @param lightIndex Index of light to work on
/// @param ms Time delta from last update in miliseconds
void updateLightTime(const U32 detail, const U32 lightIndex, const U32 ms);
/// This loops through all the surfaces in an interior and calls updateLightMap on them
/// @param state SceneState - Not used
/// @param pInterior Interior to operate on
/// @param rLightInfo Light to use
void downloadLightmaps(SceneState *state, Interior *pInterior, LightInfo &rLightInfo);
/// This will set up a particular light in a particular detail level
/// @param detail Detail level
/// @param lightIndex Light to install
void installLight(const U32 detail, const U32 lightIndex);
/// Called by updateLightTime to update a light with a looping animation
/// @param interior Interior to work on
/// @param light Light to update
/// @param lightIndex Index of animated light
/// @param ms Time delta from last update in miliseconds
void updateLoopingLight(Interior *interior, LightInfo::Light &light, const U32 lightIndex, const U32 ms);
/// Called by updateLightTime to update a light with a flicker animation
/// @param interior Interior to work on
/// @param light Light to update
/// @param lightIndex Index of animated light
/// @param ms Time delta from last update in miliseconds
void updateFlickerLight(Interior *interior, LightInfo::Light &light, const U32 lightIndex, const U32 ms);
/// Called by updateLightTime to update a light with a fade-up (ramp) animation light
/// @param interior Interior to work on
/// @param light Light to update
/// @param lightIndex Index of animated light
/// @param ms Time delta from last update in miliseconds
void updateRampLight(Interior *interior, LightInfo::Light &light, const U32 lightIndex, const U32 ms);
/// Updates the animation for all lights
/// @param ms Time delta since last call in ms
void updateAllLights(const U32 ms);
/// Takes the original lightmap and adds the animated lights to it and then
/// binds the texture to it
/// @param pInterior Interior object to map
/// @param rLightInfo Light info to use to update the light map
/// @param surfaceIndex The surface to operate on inside the interior
void updateLightMap(Interior *pInterior, LightInfo &rLightInfo, const U32 surfaceIndex);
/// lightMap is a 24-bit RGB texture, intensityMap is an 8 bit intensity map.
/// This generates lightmap = [lightmap + (intensityMap * color)]
/// @param lightMap Lightmap to operate on (in/out)
/// @param width width of the ligth map
/// @param height hight of the light map
/// @param intensityMap Intensity map
/// @param color Color
void intensityMapMerge(U8* lightMap,
const U32 width, const U32 height,
const U8* intensityMap, const ColorI& color);
/// @}
private:
/// Creates a transform based on an trigger area
/// @param trigger Trigger to create a transform for
/// @param transform Transform generated (out)
void createTriggerTransform(const InteriorResTrigger *trigger, MatrixF *transform);
};
inline void InteriorInstance::setLightUpdatedTime(const U32 now)
{
mLightUpdatedTime = now;
}
inline U32 InteriorInstance::getLightUpdatedTime() const
{
return mLightUpdatedTime;
}
inline U32 InteriorInstance::makeUpdateKey(const U32 detail, const U32 lightIndex)
{
AssertFatal(detail < (1 << 16) && lightIndex < (1 << 16), "Error, out of bounds key params");
return (detail << 16) | (lightIndex & 0x0000FFFF);
}
inline U32 InteriorInstance::detailFromUpdateKey(const U32 key)
{
return (key >> 16) & 0xFFFF;
}
inline U32 InteriorInstance::indexFromUpdateKey(const U32 key)
{
return (key >> 0) & 0xFFFF;
}
inline Vector<ColorI>* InteriorInstance::getVertexColorsNormal(U32 detail)
{
if (bool(mInteriorRes) == false || detail > mInteriorRes->getNumDetailLevels())
return NULL;
return mVertexColorsNormal[detail];
}
inline Vector<ColorI>* InteriorInstance::getVertexColorsAlarm(U32 detail)
{
if (bool(mInteriorRes) == false || detail > mInteriorRes->getNumDetailLevels())
return NULL;
return mVertexColorsAlarm[detail];
}
#endif //_INTERIORBLOCK_H_