added everything

This commit is contained in:
Metario
2017-04-17 06:17:10 -06:00
commit 9c6ff74f19
6121 changed files with 1625704 additions and 0 deletions

View File

@ -0,0 +1,36 @@
//---------------------------------------------------------------
// Synapse Gaming - Binary Volume Partition Tree
// Copyright <20> Synapse Gaming 2004 - 2005
// Written by John Kabus
//
// Overview:
// The Binary Volume Partition Tree (BVPT) is a hybrid of the
// BSP and Oct-tree spacial partitioning schemes that combines
// the strengths of both into a system that can efficiently
// processes large amounts of geometry and geometry with large
// surface area, which allows optimal handling of both brush
// and mesh geometry.
//
// Similar to Oct-tree partitioning, BVPT splits the geometric
// 'world' into equal volumes and each volume into sub-volumes
// creating a tree that assigns each surface or object into the
// smallest volume that completely contains it.
//
// The main disadvantage to using Oct-trees is that all geometry
// that rides the border between *any* two octants is maintained
// by the parent volume, which means the geometry is used every
// time the parent volume is traversed regardless of the
// relationship to the requested octant.
//
// BVPT avoids Oct-tree inefficiencies by splitting volumes in
// half (instead of into eighths). Because of this all geometry
// maintained by the parent volume spans both of the two sub-volumes,
// meaning that the parent geometry has a definite relationship
// to the requested sub-volume.
//---------------------------------------------------------------
#include "lightingSystem/sgBinaryVolumePartitionTree.h"

View File

@ -0,0 +1,276 @@
//---------------------------------------------------------------
// Synapse Gaming - Binary Volume Partition Tree
// Copyright <20> Synapse Gaming 2004 - 2005
// Written by John Kabus
//
// Overview:
// The Binary Volume Partition Tree (BVPT) is a hybrid of the
// BSP and Oct-tree spacial partitioning schemes that combines
// the strengths of both into a system that can efficiently
// processes large amounts of geometry and geometry with large
// surface area, which allows optimal handling of both brush
// and mesh geometry.
//
// Similar to Oct-tree partitioning, BVPT splits the geometric
// 'world' into equal volumes and each volume into sub-volumes
// creating a tree that assigns each surface or object into the
// smallest volume that completely contains it.
//
// The main disadvantage to using Oct-trees is that all geometry
// that rides the border between *any* two octants is maintained
// by the parent volume, which means the geometry is used every
// time the parent volume is traversed regardless of the
// relationship to the requested octant.
//
// BVPT avoids Oct-tree inefficiencies by splitting volumes in
// half (instead of into eighths). Because of this all geometry
// maintained by the parent volume spans both of the two sub-volumes,
// meaning that the parent geometry has a definite relationship
// to the requested sub-volume.
//---------------------------------------------------------------
#ifndef BVPT_H_
#define BVPT_H_
#include "platform/types.h"
#include "core/color.h"
#include "math/mPoint.h"
#include "math/mBox.h"
#include "math/mPlane.h"
#include "core/tVector.h"
template<class Tstoreobj> class BVPT
{
public:
enum axisType
{
atX = 0,
atY = 1,
atZ = 2,
atNone = 3
};
typedef Vector<Tstoreobj> objectList;
// used for spacial partitioning...
PlaneF plane;
// objects contained in this partition...
objectList object;
// children in the tree...
BVPT *positive;
BVPT *negative;
// only used for passing info into children...
axisType axis;
// only used for passing info into children...
Box3F volume;
BVPT()
{
positive = negative = NULL;
clear();
}
BVPT(const Box3F &vol)
{
positive = negative = NULL;
init(vol);
}
~BVPT() {clear();}
void init(const Box3F &vol)
{
clear();
volume = vol;
calculatePartition();
}
void clear()
{
axis = atNone;
plane.set(0.0f, 0.0f, 0.0f);
plane.d = 0.0f;
volume.min.set(F32_MAX, F32_MAX, F32_MAX);
volume.max.set(-F32_MAX, -F32_MAX, -F32_MAX);
object.clear();
if(positive)
{
delete positive;
positive = NULL;
}
if(negative)
{
delete negative;
negative = NULL;
}
}
void calculatePartition()
{
Point3F span = volume.max - volume.min;
F32 bestspan = span.x;
axisType bestaxis = atX;
for(S32 i=1; i<3; i++)
{
if(bestspan < span[i])
{
bestspan = span[i];
bestaxis = axisType(i);
}
}
axis = bestaxis;
plane.set(0.0f, 0.0f, 0.0f);
plane[axis] = 1.0f;
plane.d = -(volume.min[axis] + (bestspan * 0.5f));
}
void storeObject(const Box3F &boundingbox, const Tstoreobj obj)
{
bool frontmin = plane.distToPlane(boundingbox.min) > 0.0f;
bool frontmax = plane.distToPlane(boundingbox.max) > 0.0f;
if(frontmin != frontmax)
{
// only fully contained by this volume...
object.push_back(obj);
}
else if(frontmin)
{
// positive side...
// setup child...
Box3F vol = volume;
vol.min[axis] = -plane.d;
if(!positive)
positive = new BVPT(vol);
// send down the object...
positive->storeObject(boundingbox, obj);
}
else
{
// negative side...
// setup child...
Box3F vol = volume;
vol.max[axis] = -plane.d;
if(!negative)
negative = new BVPT(vol);
// send down the object...
negative->storeObject(boundingbox, obj);
}
}
void collectObjects(const Box3F &boundingbox, objectList &objectslist)
{
// we're here so collect the objects...
U32 originalcount = objectslist.size();
objectslist.increment(object.size());
if(object.size() > 0)
{
dMemcpy((objectslist.address() + originalcount), object.address(), (object.size() * sizeof(Tstoreobj)));
}
bool frontmin = plane.distToPlane(boundingbox.min) > 0.0f;
bool frontmax = plane.distToPlane(boundingbox.max) > 0.0f;
if((frontmin || frontmax) && positive)
positive->collectObjects(boundingbox, objectslist);
if((!frontmin || !frontmax) && negative)
negative->collectObjects(boundingbox, objectslist);
}
// clips line to outer volume...
void collectObjectsClipped(Point3F start, Point3F end, objectList &objectslist)
{
F32 t;
Point3F vect;
if(!volume.isContained(start))
{
if(!volume.collideLine(start, end, &t, &vect))
return;// we missed the whole volume...
if((t < 0.0f) || (t > 1.0f))
return;// we missed the whole volume...
vect = end - start;
start += (vect * t);
}
if(!volume.isContained(end))
{
if(!volume.collideLine(end, start, &t, &vect))
return;// we missed the whole volume...
if((t < 0.0f) || (t > 1.0f))
return;// we missed the whole volume...
vect = start - end;
end += (vect * t);
}
collectObjectsUnclipped(start, end, objectslist);
}
// assumes the line has been clipped to the outer volume!!!
void collectObjectsUnclipped(const Point3F &start, const Point3F &end, objectList &objectslist)
{
// we're here so collect the objects...
U32 originalcount = objectslist.size();
objectslist.increment(object.size());
if(object.size() > 0)
{
dMemcpy((objectslist.address() + originalcount), object.address(), (object.size() * sizeof(Tstoreobj)));
}
// do we have children?
if((!positive) && (!negative))
return;
// test for sides...
F32 diststart = plane.distToPlane(start);
bool fronts = diststart > 0.0f;
bool fronte = plane.distToPlane(end) > 0.0f;
if(fronts == fronte)// same side?
{
if(fronts && positive)// in the front...
positive->collectObjectsUnclipped(start, end, objectslist);
else if((!fronts) && negative)// might be the back...
negative->collectObjectsUnclipped(start, end, objectslist);
}
else
{
// find the split...
Point3F split = end - start;
F32 t = mDot(split, plane);
if(t == 0)
return;
t = -diststart / t;
if(t > 0.0f)
{
split *= t;
split += start;
}
else
{
split = start;
}
// setup the orientation...
const Point3F *f;
const Point3F *b;
if(fronts)
{
f = &start;
b = &end;
}
else
{
f = &end;
b = &start;
}
// run the two new lines through the children...
if(positive)
positive->collectObjectsUnclipped((*f), split, objectslist);
if(negative)
negative->collectObjectsUnclipped(split, (*b), objectslist);
}
}
};
#endif//BVPT_H_

View File

@ -0,0 +1,188 @@
//-----------------------------------------------
// Synapse Gaming - Lighting Code Pack
// Copyright <20> Synapse Gaming 2003
// Written by John Kabus
//-----------------------------------------------
#include <d3dx.h>
#include "sgD3DCompatibility.h"
int sgD3DCompatibility::sgCombineMode[SG_MAX_CHANNELS];
int sgD3DCompatibility::sgScale[SG_MAX_CHANNELS];
unsigned long sgD3DCompatibility::sgShaders[sgstCount];
void sgD3DCompatibility::sgInitShaders(void *device)
{
LPDIRECT3DDEVICE7 m_d3ddev = (LPDIRECT3DDEVICE7)device;
m_d3ddev->BeginStateBlock();
m_d3ddev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_d3ddev->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
m_d3ddev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
m_d3ddev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
m_d3ddev->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
m_d3ddev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
m_d3ddev->EndStateBlock(&sgD3DCompatibility::sgShaders[sgstChannel0ModulateRGBA]);
m_d3ddev->BeginStateBlock();
m_d3ddev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_d3ddev->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
m_d3ddev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
m_d3ddev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
m_d3ddev->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
m_d3ddev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2);
m_d3ddev->EndStateBlock(&sgD3DCompatibility::sgShaders[sgstChannel0ModulateRGB]);
m_d3ddev->BeginStateBlock();
m_d3ddev->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_d3ddev->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
m_d3ddev->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
m_d3ddev->SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
m_d3ddev->SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
m_d3ddev->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
m_d3ddev->EndStateBlock(&sgD3DCompatibility::sgShaders[sgstChannel1ModulateRGBA]);
m_d3ddev->BeginStateBlock();
m_d3ddev->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_d3ddev->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
m_d3ddev->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
m_d3ddev->SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
m_d3ddev->SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
m_d3ddev->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2);
m_d3ddev->EndStateBlock(&sgD3DCompatibility::sgShaders[sgstChannel1ModulateRGB]);
m_d3ddev->BeginStateBlock();
m_d3ddev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_d3ddev->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
m_d3ddev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE2X);
m_d3ddev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
m_d3ddev->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
m_d3ddev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
m_d3ddev->EndStateBlock(&sgD3DCompatibility::sgShaders[sgstChannel0Modulate2RGBA]);
m_d3ddev->BeginStateBlock();
m_d3ddev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_d3ddev->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
m_d3ddev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE2X);
m_d3ddev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
m_d3ddev->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
m_d3ddev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2);
m_d3ddev->EndStateBlock(&sgD3DCompatibility::sgShaders[sgstChannel0Modulate2RGB]);
m_d3ddev->BeginStateBlock();
m_d3ddev->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_d3ddev->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
m_d3ddev->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE2X);
m_d3ddev->SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
m_d3ddev->SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
m_d3ddev->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
m_d3ddev->EndStateBlock(&sgD3DCompatibility::sgShaders[sgstChannel1Modulate2RGBA]);
m_d3ddev->BeginStateBlock();
m_d3ddev->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_d3ddev->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
m_d3ddev->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE2X);
m_d3ddev->SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
m_d3ddev->SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
m_d3ddev->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2);
m_d3ddev->EndStateBlock(&sgD3DCompatibility::sgShaders[sgstChannel1Modulate2RGB]);
m_d3ddev->BeginStateBlock();
m_d3ddev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_d3ddev->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
m_d3ddev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE4X);
m_d3ddev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
m_d3ddev->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
m_d3ddev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
m_d3ddev->EndStateBlock(&sgD3DCompatibility::sgShaders[sgstChannel0Modulate4RGBA]);
m_d3ddev->BeginStateBlock();
m_d3ddev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_d3ddev->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
m_d3ddev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE4X);
m_d3ddev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
m_d3ddev->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
m_d3ddev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2);
m_d3ddev->EndStateBlock(&sgD3DCompatibility::sgShaders[sgstChannel0Modulate4RGB]);
m_d3ddev->BeginStateBlock();
m_d3ddev->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_d3ddev->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
m_d3ddev->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE4X);
m_d3ddev->SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
m_d3ddev->SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
m_d3ddev->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
m_d3ddev->EndStateBlock(&sgD3DCompatibility::sgShaders[sgstChannel1Modulate4RGBA]);
m_d3ddev->BeginStateBlock();
m_d3ddev->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_d3ddev->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
m_d3ddev->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE4X);
m_d3ddev->SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
m_d3ddev->SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
m_d3ddev->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2);
m_d3ddev->EndStateBlock(&sgD3DCompatibility::sgShaders[sgstChannel1Modulate4RGB]);
m_d3ddev->BeginStateBlock();
m_d3ddev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_d3ddev->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TFACTOR);
m_d3ddev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_BLENDCURRENTALPHA);
m_d3ddev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
m_d3ddev->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
m_d3ddev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2);
m_d3ddev->EndStateBlock(&sgD3DCompatibility::sgShaders[sgstChannel0InterpolateRGB]);
for(long i=0; i<SG_MAX_CHANNELS; i++)
{
sgD3DCompatibility::sgCombineMode[i] = 0;
sgD3DCompatibility::sgScale[i] = 1;
}
}
void sgD3DCompatibility::sgDeleteShaders(void *device)
{
LPDIRECT3DDEVICE7 m_d3ddev = (LPDIRECT3DDEVICE7)device;
for(long i=1; i<sgstCount; i++)
{
m_d3ddev->DeleteStateBlock(sgD3DCompatibility::sgShaders[i]);
}
}
unsigned long sgD3DCompatibility::sgGetShader(long shader)
{
if(shader == sgstChannel0ModulateRGBA)
{
if(sgScale[0] == 2)
shader = sgstChannel0Modulate2RGBA;
else if(sgScale[0] == 4)
shader = sgstChannel0Modulate4RGBA;
}
if(shader == sgstChannel0ModulateRGB)
{
if(sgScale[0] == 2)
shader = sgstChannel0Modulate2RGB;
else if(sgScale[0] == 4)
shader = sgstChannel0Modulate4RGB;
}
if(shader == sgstChannel1ModulateRGBA)
{
if(sgScale[1] == 2)
shader = sgstChannel1Modulate2RGBA;
else if(sgScale[1] == 4)
shader = sgstChannel1Modulate4RGBA;
}
if(shader == sgstChannel1ModulateRGB)
{
if(sgScale[1] == 2)
shader = sgstChannel1Modulate2RGB;
else if(sgScale[1] == 4)
shader = sgstChannel1Modulate4RGB;
}
return sgD3DCompatibility::sgShaders[shader];
}

View File

@ -0,0 +1,47 @@
//-----------------------------------------------
// Synapse Gaming - Lighting Code Pack
// Copyright <20> Synapse Gaming 2003
// Written by John Kabus
//-----------------------------------------------
#ifndef _SGD3DCOMPATIBILITY_H_
#define _SGD3DCOMPATIBILITY_H_
#define SG_MAX_CHANNELS 10
class sgD3DCompatibility
{
public:
enum sgShaderTypes
{
sgstEmptyShader = 0,
sgstChannel0ModulateRGBA,
sgstChannel1ModulateRGBA,
sgstChannel0ModulateRGB,
sgstChannel1ModulateRGB,
sgstChannel0Modulate2RGBA,
sgstChannel1Modulate2RGBA,
sgstChannel0Modulate2RGB,
sgstChannel1Modulate2RGB,
sgstChannel0Modulate4RGBA,
sgstChannel1Modulate4RGBA,
sgstChannel0Modulate4RGB,
sgstChannel1Modulate4RGB,
sgstChannel0InterpolateRGB,
sgstCount
};
static int sgCombineMode[SG_MAX_CHANNELS];
static int sgScale[SG_MAX_CHANNELS];
private:
static unsigned long sgShaders[sgstCount];
public:
static void sgInitShaders(void *device);
static void sgDeleteShaders(void *device);
static unsigned long sgGetShader(long shader);
};
#endif//_SGD3DCOMPATIBILITY_H_

View File

@ -0,0 +1,308 @@
//-----------------------------------------------
// Synapse Gaming - Lighting System
// Copyright <20> Synapse Gaming 2003
// Written by John Kabus
//-----------------------------------------------
#include "lightingSystem/sgLighting.h"
#include "lightingSystem/sgDecalProjector.h"
#include "sim/decalManager.h"
#include "sim/netConnection.h"
#include "sceneGraph/sceneState.h"
extern bool gEditingMission;
class sgDecalProjector : public GameBase
{
typedef GameBase Parent;
DecalData *mDataBlock;
bool onNewDataBlock(GameBaseData* dptr);
protected:
bool sgInitNeeded;
bool sgProjection;
Point3F sgProjectionPoint;
Point3F sgProjectionNormal;
bool onAdd();
void onRemove();
void sgResetProjection();
void sgProject();
public:
sgDecalProjector();
void inspectPostApply();
void setTransform(const MatrixF &mat);
bool prepRenderImage(SceneState* state, const U32 stateKey,
const U32 startZone, const bool modifyBaseZoneState);
void renderObject(SceneState *state, SceneRenderImage *image);
U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream);
void unpackUpdate(NetConnection *con, BitStream *stream);
DECLARE_CONOBJECT(sgDecalProjector);
};
IMPLEMENT_CO_NETOBJECT_V1(sgDecalProjector);
sgDecalProjector::sgDecalProjector()
{
mTypeMask |= StaticObjectType | StaticTSObjectType | StaticRenderedObjectType;
mNetFlags.set(Ghostable | ScopeAlways);
mDataBlock = NULL;
sgProjection = false;
sgProjectionPoint = Point3F(0.0f, 0.0f, 0.0f);
sgProjectionNormal = Point3F(0.0f, 0.0f, 0.0f);
// for after load relinking...
sgInitNeeded = true;
}
bool sgDecalProjector::onAdd()
{
if(!Parent::onAdd())
return false;
mObjBox.min.set( -0.5, -0.5, -0.5 );
mObjBox.max.set( 0.5, 0.5, 0.5 );
resetWorldBox();
setRenderTransform(mObjToWorld);
addToScene();
return true;
}
void sgDecalProjector::onRemove()
{
if(isClientObject())
gDecalManager->ageDecal(getId());
removeFromScene();
Parent::onRemove();
}
bool sgDecalProjector::onNewDataBlock(GameBaseData* dptr)
{
mDataBlock = dynamic_cast<DecalData *>(dptr);
return Parent::onNewDataBlock(dptr);
}
bool sgDecalProjector::prepRenderImage(SceneState* state, const U32 stateKey,
const U32 startZone, const bool modifyBaseZoneState)
{
if(!gEditingMission)
return false;
if(isLastState(state, stateKey))
return false;
setLastState(state, stateKey);
if(state->isObjectRendered(this))
{
SceneRenderImage* image = new SceneRenderImage;
image->obj = this;
image->isTranslucent = true;
image->sortType = SceneRenderImage::EndSort;
state->insertRenderImage(image);
}
return false;
}
void sgDecalProjector::renderObject(SceneState *state, SceneRenderImage *image)
{
if(gEditingMission)
{
// render the directional line...
glBlendFunc(GL_ONE,GL_ZERO);
glEnable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
Point3F vector = SG_STATIC_SPOT_VECTOR_NORMALIZED * 10.0f;
Point3F origin = Point3F(0, 0, 0);
Point3F point = vector;
mObjToWorld.mulP(origin);
mObjToWorld.mulP(point);
glColor3f(0, 1, 0);
glBegin(GL_LINES);
glVertex3fv(origin);
glVertex3fv(point);
glEnd();
}
}
void sgDecalProjector::sgResetProjection()
{
sgProjection = false;
sgProjectionPoint = Point3F(0.0f, 0.0f, 0.0f);
sgProjectionNormal = Point3F(0.0f, 0.0f, 0.0f);
if(isClientObject())
return;
Point3F pos = getPosition();
Point3F normal = SG_STATIC_SPOT_VECTOR_NORMALIZED * 100.0f;
getTransform().mulV(normal);
RayInfo info;
if(!gServerContainer.castRay(pos, (pos + normal),
InteriorObjectType | TerrainObjectType, &info))
{
Con::errorf("Error in _sgDropDecal: no drop object found.");
return;
}
sgProjection = true;
sgProjectionPoint = info.point;
sgProjectionNormal = info.normal;
setMaskBits(0xffffffff);
}
void sgDecalProjector::sgProject()
{
if((isServerObject()) || (!mDataBlock))
return;
// use the instead of getId()...
// id's are flaky in zones...
U32 ownerid = U32(this);
gDecalManager->ageDecal(ownerid);
if(!sgProjection)
return;
Point3F tandir;
getTransform().getColumn(0, &tandir);
gDecalManager->addDecal(sgProjectionPoint, tandir, sgProjectionNormal, getScale(), mDataBlock, ownerid);
}
void sgDecalProjector::setTransform(const MatrixF & mat)
{
Parent::setTransform(mat);
sgResetProjection();
setMaskBits(0xffffffff);
}
U32 sgDecalProjector::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
{
U32 res = Parent::packUpdate(con, mask, stream);
if(sgInitNeeded && isServerObject())
{
sgInitNeeded = false;
sgResetProjection();
}
stream->writeAffineTransform(mObjToWorld);
if(stream->writeFlag(sgProjection))
{
// this is a joke right (no Point3F support)?!?
stream->write(sgProjectionPoint.x);
stream->write(sgProjectionPoint.y);
stream->write(sgProjectionPoint.z);
stream->write(sgProjectionNormal.x);
stream->write(sgProjectionNormal.y);
stream->write(sgProjectionNormal.z);
}
return res;
}
void sgDecalProjector::unpackUpdate(NetConnection *con, BitStream *stream)
{
Parent::unpackUpdate(con, stream);
MatrixF ObjectMatrix;
stream->readAffineTransform(&ObjectMatrix);
setTransform(ObjectMatrix);
sgProjection = stream->readFlag();
if(sgProjection)
{
// this is a joke right (no Point3F support)?!?
stream->read(&sgProjectionPoint.x);
stream->read(&sgProjectionPoint.y);
stream->read(&sgProjectionPoint.z);
stream->read(&sgProjectionNormal.x);
stream->read(&sgProjectionNormal.y);
stream->read(&sgProjectionNormal.z);
}
sgProject();
}
void sgDecalProjector::inspectPostApply()
{
Parent::inspectPostApply();
sgResetProjection();
setMaskBits(0xffffffff);
}
//-----------------------------------------------
ConsoleFunction(_sgCreateDecal, void, 6, 6, "(Point3F pos, Point3F tandir, Point3F norm, "
"Point3F scale, decalDataBlock) - this method must be called on the client side!")
{
// is this the client side?
// doesn't work...
//if(gDecalManager->isServerObject())
// return;
Point3F pos = Point3F(0, 0, 0);
Point3F tandir = Point3F(1, 0, 0);
Point3F normal = Point3F(0, 0, 1);
Point3F scale = Point3F(1, 1, 1);
DecalData *decaldata = NULL;
dSscanf(argv[1],"%f %f %f",&pos.x,&pos.y,&pos.z);
dSscanf(argv[2],"%f %f %f",&tandir.x,&tandir.y,&tandir.z);
dSscanf(argv[3],"%f %f %f",&normal.x,&normal.y,&normal.z);
dSscanf(argv[4],"%f %f %f",&scale.x,&scale.y,&scale.z);
decaldata = dynamic_cast<DecalData *>(Sim::findObject(argv[5]));
if(!decaldata)
return;
gDecalManager->addDecal(pos, tandir, normal, scale, decaldata);
}
ConsoleFunction(_sgDropDecal, void, 6, 6, "(Point3F pos, Point3F tandir, Point3F norm, "
"Point3F scale, decalDataBlock) - this method must be called on the client side! "
"This method drops a decal onto the interior or "
"terrain directly below the given position.")
{
// is this the client side?
// doesn't work...
//if(!gDecalManager->isGhost())
// return;
Point3F pos = Point3F(0, 0, 0);
Point3F tandir = Point3F(1, 0, 0);
Point3F normal = Point3F(0, 0, 1);
Point3F scale = Point3F(1, 1, 1);
DecalData *decaldata = NULL;
dSscanf(argv[1],"%f %f %f",&pos.x,&pos.y,&pos.z);
dSscanf(argv[2],"%f %f %f",&tandir.x,&tandir.y,&tandir.z);
dSscanf(argv[3],"%f %f %f",&normal.x,&normal.y,&normal.z);
dSscanf(argv[4],"%f %f %f",&scale.x,&scale.y,&scale.z);
decaldata = dynamic_cast<DecalData *>(Sim::findObject(argv[5]));
if(!decaldata)
return;
RayInfo info;
if(!gClientContainer.castRay(pos, (pos + Point3F(0, 0, -100)),
InteriorObjectType | TerrainObjectType, &info))
{
Con::errorf("Error in _sgDropDecal: no drop object found.");
return;
}
pos = info.point;
normal = info.normal;
gDecalManager->addDecal(pos, tandir, normal, scale, decaldata);
}

View File

@ -0,0 +1,16 @@
//-----------------------------------------------
// Synapse Gaming - Lighting System
// Copyright <20> Synapse Gaming 2003
// Written by John Kabus
//-----------------------------------------------
#ifndef _SGDECALMANAGER_H_
#define _SGDECALMANAGER_H_
#include "core/bitStream.h"
#include "game/gameBase.h"
#endif//_SGDECALMANAGER_H_

View File

@ -0,0 +1,228 @@
//-----------------------------------------------
// Synapse Gaming - Lighting System
// Copyright <20> Synapse Gaming 2003
// Written by John Kabus
//-----------------------------------------------
#include "lightingSystem/sgLighting.h"
#include "game/fx/particleEngine.h"
#include "console/consoleTypes.h"
#include "core/bitStream.h"
#include "game/gameConnection.h"
#include "sceneGraph/sceneGraph.h"
#include "sim/netConnection.h"
#include "dgl/materialPropertyMap.h"
#include "lightingSystem/sgDetailMapping.h"
void sgDetailMapping::sgInitDetailMapping(MaterialList *materials)
{
sgClearDetailMapping();
// need this for DX to GL switch...
sgMaterialsCache = materials;
if(!LightManager::sgAllowDetailMaps())
return;
GBitmap *b = new GBitmap(2, 2);
U8 *bits = b->getWritableBits();
dMemset(bits, 127, b->byteSize);
sgWhiteTexture = new TextureHandle(NULL, b);
MaterialPropertyMap *materialprops = static_cast<MaterialPropertyMap *>(Sim::findObject("MaterialPropertyMap"));
sgDetailMaps.setSize(materials->getMaterialCount());
for(U32 i=0; i<materials->getMaterialCount(); i++)
{
const char* name = materials->getMaterialName(i);
const MaterialPropertyMap::MapEntry* entry = materialprops->getMapEntry(name);
// init this to NULL...
sgDetailMaps[i] = NULL;
// try to fill it out now...
if((entry == NULL) || (entry->detailMapName == NULL))
continue;
// we're doing this by hand - Torque gives you no contol over mipmaps...
// load the texture...
GBitmap *bitmap = TextureManager::loadBitmapInstance(entry->detailMapName);
if(!bitmap)
continue;
// make a deletable copy and use it to create the texture...
// need to do this because BitmapTexture doesn't create mips (so refresh fails)...
//GBitmap *bitmapcopy = new GBitmap(*bitmap);
//TextureHandle *texture = new TextureHandle(NULL, bitmapcopy, DetailTexture);
//TextureHandle *texture = new TextureHandle(NULL, bitmap);
// manually extrude the original...
bitmap->extrudeMipLevels();
// fix the levels...
F32 scale = (2.0f / F32(bitmap->getNumMipLevels()));
F32 currentscale = 1.0f;
for(U32 m=0; m<bitmap->getNumMipLevels(); m++)
{
for(U32 y=0; y<bitmap->getHeight(m); y++)
{
for(U32 x=0; x<bitmap->getWidth(m); x++)
{
// this is ugly, but it only happens on load...
U8 *bits = bitmap->getAddress(x, y, m);
F32 bit = bits[0];
bits[0] = U8(((bit - 127.0f) * currentscale) + 127.0f);
bit = bits[1];
bits[1] = U8(((bit - 127.0f) * currentscale) + 127.0f);
bit = bits[2];
bits[2] = U8(((bit - 127.0f) * currentscale) + 127.0f);
}
}
currentscale -= scale;
currentscale = mClampF(currentscale, 0.0f, 1.0f);
}
// assign the bitmap...
//TextureObject *obj = *texture;
//obj->bitmap = bitmap;
//obj->type = DetailTexture;
// refresh...
//texture->refresh();
TextureHandle *texture = new TextureHandle(NULL, bitmap);
// unlink and delete...
//obj->bitmap = NULL;
//delete bitmap;
// keep link and set to keep texture (for DX/GL switch)...
//obj->type = BitmapKeepTexture;
// finally done...
sgDetailMaps[i] = texture;
}
}
void sgDetailMapping::sgBindDetailMap(U32 surfaceindex)
{
if(!LightManager::sgAllowDetailMaps())
return;
// DX to GL switch?
if((sgDetailMaps.size() == 0) && (sgMaterialsCache))
{
sgInitDetailMapping(sgMaterialsCache);
// don't want to go through that again...
sgMaterialsCache = NULL;
}
// bailout...
if(sgDetailMaps.size() <= surfaceindex)
return;
AssertFatal((sgDetailMaps.size() > surfaceindex), "Invalid surface index while detail mapping.");
TextureHandle *texture = sgDetailMaps[surfaceindex];
glActiveTextureARB(GL_TEXTURE2_ARB);
if(!texture)
glBindTexture(GL_TEXTURE_2D, sgWhiteTexture->getGLName());
else
glBindTexture(GL_TEXTURE_2D, texture->getGLName());
glActiveTextureARB(GL_TEXTURE3_ARB);
if(!texture)
glBindTexture(GL_TEXTURE_2D, sgWhiteTexture->getGLName());
else
glBindTexture(GL_TEXTURE_2D, texture->getGLName());
}
void sgDetailMapping::sgClearDetailMapping()
{
sgMaterialsCache = NULL;
if(sgWhiteTexture)
{
delete sgWhiteTexture;
sgWhiteTexture = NULL;
}
for(U32 i=0; i<sgDetailMaps.size(); i++)
delete sgDetailMaps[i];
sgDetailMaps.clear();
}
void sgDetailMapping::sgEnableDetailMapping(void *buffer, U32 elementsize)
{
if(!LightManager::sgAllowDetailMaps())
return;
const F32 scale[16] = {4.0, 0.0, 0.0, 0.0,
0.0, 4.0, 0.0, 0.0,
0.0, 0.0, 4.0, 0.0,
0.0, 0.0, 0.0, 1.0};
const F32 scaleX4[16] = {8.0, 0.0, 0.0, 0.0,
0.0, 8.0, 0.0, 0.0,
0.0, 0.0, 8.0, 0.0,
0.0, 0.0, 0.0, 1.0};
glActiveTextureARB(GL_TEXTURE2_ARB);
glEnable(GL_TEXTURE_2D);
LightManager::sgSetupExposureRendering();
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glMultMatrixf(scale);
glActiveTextureARB(GL_TEXTURE3_ARB);
//glDisable(GL_TEXTURE_2D);
glEnable(GL_TEXTURE_2D);
LightManager::sgSetupExposureRendering();
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glMultMatrixf(scaleX4);
glActiveTextureARB(GL_TEXTURE0_ARB);
glClientActiveTextureARB(GL_TEXTURE2_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, elementsize, buffer);
glClientActiveTextureARB(GL_TEXTURE3_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, elementsize, buffer);
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
void sgDetailMapping::sgDisableDetailMapping()
{
if(!LightManager::sgAllowDetailMaps())
return;
glClientActiveTextureARB(GL_TEXTURE3_ARB);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE2_ARB);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glActiveTextureARB(GL_TEXTURE3_ARB);
glMatrixMode(GL_TEXTURE);
glPopMatrix();
LightManager::sgResetExposureRendering();
glDisable(GL_TEXTURE_2D);
glActiveTextureARB(GL_TEXTURE2_ARB);
glMatrixMode(GL_TEXTURE);
glPopMatrix();
LightManager::sgResetExposureRendering();
glDisable(GL_TEXTURE_2D);
glActiveTextureARB(GL_TEXTURE0_ARB);
}

View File

@ -0,0 +1,31 @@
//-----------------------------------------------
// Synapse Gaming - Lighting System
// Copyright <20> Synapse Gaming 2003
// Written by John Kabus
//-----------------------------------------------
#ifndef _SGDETAILMAPPING_H_
#define _SGDETAILMAPPING_H_
class MaterialList;
class sgDetailMapping
{
private:
TextureHandle *sgWhiteTexture;
MaterialList *sgMaterialsCache;
Vector<TextureHandle *> sgDetailMaps;
public:
sgDetailMapping()
{
sgWhiteTexture = NULL;
sgMaterialsCache = NULL;
}
~sgDetailMapping() {sgClearDetailMapping();}
void sgInitDetailMapping(MaterialList *materials);
void sgClearDetailMapping();
void sgBindDetailMap(U32 surfaceindex);
void sgEnableDetailMapping(void *buffer, U32 elementsize);
void sgDisableDetailMapping();
};
#endif//_SGDETAILMAPPING_H_

View File

@ -0,0 +1,92 @@
//---------------------------------------------------------------
// Synapse Gaming - Hash Map
// Copyright <20> Synapse Gaming 2004 - 2005
// Written by John Kabus
//---------------------------------------------------------------
#ifndef HASHMAP_H_
#define HASHMAP_H_
#include "platform/types.h"
#include "core/tVector.h"
template<class T, class Tinfo> class hash_multimap
{
public:
U32 hashCode;
// entry level info or single object per-entry...
Tinfo info;
// for storing multiple objects per-entry...
Vector<T> object;
hash_multimap *mapHigh;
hash_multimap *mapLow;
hash_multimap *linkHigh;
hash_multimap *linkLow;
hash_multimap()
{
// theoretical mean for hash code (balance the tree)...
hashCode = 0x7fffffff;
// this unfortunately clears objects after the constructor
// setups up values, but is necessary for clearing pointers...
dMemset(&info, 0, sizeof(Tinfo));
mapHigh = mapLow = linkHigh = linkLow = NULL;
}
hash_multimap(U32 hashcode)
{
hashCode = hashcode;
// this unfortunately clears objects after the constructor
// setups up values, but is necessary for clearing pointers...
dMemset(&info, 0, sizeof(Tinfo));
mapHigh = mapLow = linkHigh = linkLow = NULL;
}
virtual ~hash_multimap()
{
clear();
}
void clear()
{
if(mapHigh)
delete mapHigh;
if(mapLow)
delete mapLow;
mapHigh = mapLow = linkHigh = linkLow = NULL;
}
void relink(hash_multimap *high, hash_multimap *low, hash_multimap *insert)
{
if(high)
high->linkLow = insert;
if(low)
low->linkHigh = insert;
insert->linkHigh = high;
insert->linkLow = low;
}
hash_multimap *find(U32 hashcode)
{
if(hashcode == hashCode)
return this;
else if(hashcode < hashCode)
{
if(!mapLow)
{
mapLow = new hash_multimap(hashcode);
relink(this, this->linkLow, mapLow);
return mapLow;
}
return mapLow->find(hashcode);
}
else
{
if(!mapHigh)
{
mapHigh = new hash_multimap(hashcode);
relink(this->linkHigh, this, mapHigh);
return mapHigh;
}
return mapHigh->find(hashcode);
}
}
};
#endif//HASHMAP_H_

View File

@ -0,0 +1,882 @@
//-----------------------------------------------
// Synapse Gaming - Lighting System
// Copyright <20> Synapse Gaming 2003
// Written by John Kabus
//-----------------------------------------------
#include "lightingSystem/sgLighting.h"
#include "lightingSystem/sgLightManager.h"
#include "lightingSystem/sgLightingModel.h"
#include "lightingSystem/sgMissionLightingFilter.h"
#include "interior/interiorInstance.h"
#include "terrain/terrData.h"
#include "game/shadow.h"
#include "lightingSystem/sgLightObject.h"
#include "sim/netConnection.h"
#include "editor/worldEditor.h"
#include "platform/profiler.h"
bool LightManager::sgLightingProperties[sgPropertyCount];
bool LightManager::sgUseSelfIlluminationColor = false;
ColorF LightManager::sgSelfIlluminationColor(0.0f, 0.0f, 0.0f);
bool LightManager::sgFilterZones = false;
S32 LightManager::sgZones[2] = {-1, -1};
bool LightManager::sgDynamicParticleSystemLighting = true;
bool LightManager::sgBlendedTerrainDynamicLighting = true;
U32 LightManager::sgLightingProfileQuality = LightManager::lpqtProduction;
bool LightManager::sgLightingProfileAllowShadows = true;
LightInfo LightManager::sgDefaultLight;
bool LightManager::sgDetailMaps = true;
S32 LightManager::sgMaxBestLights = 10;
bool LightManager::sgUseDynamicShadows = true;
U32 LightManager::sgDynamicLightingOcclusionQuality = dlqtFourSample;
U32 LightManager::sgDynamicShadowQuality = 0;
bool LightManager::sgMultipleDynamicShadows = true;
bool LightManager::sgInGUIEditor = false;
bool sgRelightFilter::sgFilterRelight = false;
bool sgRelightFilter::sgFilterRelightVisible = true;
bool sgRelightFilter::sgFilterRelightByDistance = true;
F32 sgRelightFilter::sgFilterRelightByDistanceRadius = 60;
Point3F sgRelightFilter::sgFilterRelightByDistancePosition;
U32 sgStatistics::sgInteriorLexelCount = 0;
U32 sgStatistics::sgInteriorLexelTime = 0;
U32 sgStatistics::sgInteriorLexelDiffuseCount = 0;
U32 sgStatistics::sgInteriorObjectCount = 0;
U32 sgStatistics::sgInteriorObjectIncludedCount = 0;
U32 sgStatistics::sgInteriorObjectIlluminationCount = 0;
U32 sgStatistics::sgInteriorSurfaceIncludedCount = 0;
U32 sgStatistics::sgInteriorSurfaceIlluminationCount = 0;
U32 sgStatistics::sgInteriorSurfaceIlluminatedCount = 0;
U32 sgStatistics::sgInteriorSurfaceSmoothedCount = 0;
U32 sgStatistics::sgInteriorSurfaceSmoothedLexelCount = 0;
U32 sgStatistics::sgInteriorSurfaceSetupTime = 0;
U32 sgStatistics::sgInteriorSurfaceSetupCount = 0;
U32 sgStatistics::sgInteriorSurfaceMergeTime = 0;
U32 sgStatistics::sgInteriorSurfaceMergeCount = 0;
U32 sgStatistics::sgStaticMeshSurfaceOccluderCount = 0;
U32 sgStatistics::sgTerrainLexelCount = 0;
U32 sgStatistics::sgTerrainLexelTime = 0;
sgInteriorDynamicLightingCache::sgCacheEntry sgInteriorDynamicLightingCache::sgCache;
sgDTSDynamicLightingCache::sgCacheEntry sgDTSDynamicLightingCache::sgCache;
LightInfo::LightInfo()
{
mType = Vector;
mPos = Point3F(0.0f, 0.0f, 0.0f);
mDirection = Point3F(0.0f, 0.0f, 1.0f);
mColor = ColorF(0.0f, 0.0f, 0.0f);
mAmbient = ColorF(0.0f, 0.0f, 0.0f);
mRadius = 1;
mScore = 0;
sgSpotAngle = 90.0f;
sgAssignedToTSObject = false;
sgCastsShadows = true;
sgDiffuseRestrictZone = false;
sgAmbientRestrictZone = false;
sgZone[0] = -1;
sgZone[1] = -1;
sgLocalAmbientAmount = 0.0f;
sgSmoothSpotLight = false;
sgDoubleSidedAmbient = false;
sgAssignedToParticleSystem = false;
sgLightingModelName = NULL;
sgUseNormals = true;
sgSpotPlane = PlaneF(0.0f, 0.0f, 0.0f, 0.0f);
sgDTSLightingOcclusionAdjust = 1.0f;
sgMoveSnapshotId = 0;
sgTrackMoveSnapshot = false;
sgLightingTransform.identity();
}
bool LightInfo::sgIsInZone(S32 zone)
{
if((zone == sgZone[0]) || (zone ==sgZone[1]))
return true;
return false;
}
bool LightInfo::sgAllowDiffuseZoneLighting(S32 zone)
{
if(!sgDiffuseRestrictZone)
return true;
if(sgIsInZone(zone))
return true;
return false;
}
void LightInfoList::sgRegisterLight(LightInfo *light)
{
if(!light)
return;
// just add the light, we'll try to scan for dupes later...
push_back(light);
}
void LightInfoList::sgUnregisterLight(LightInfo *light)
{
// remove all of them...
LightInfoList &list = *this;
for(U32 i=0; i<list.size(); i++)
{
if(list[i] != light)
continue;
// this moves last to i, which allows
// the search to continue forward...
list.erase_fast(i);
// want to check this location again...
i--;
}
}
//-----------------------------------------------
//-----------------------------------------------
bool LightManager::sgAllowBlendedTerrainDynamicLighting()
{
if(!sgBlendedTerrainDynamicLighting)
return false;
return (dglGetMaxTextureUnits() > 2);
}
LightInfo *LightManager::sgGetSpecialLight(sgSpecialLightTypesEnum type)
{
if(sgSpecialLights[type])
return sgSpecialLights[type];
// return a default light...
return &sgDefaultLight;
}
void LightManager::sgRegisterGlobalLight(LightInfo *light)
{
sgRegisteredGlobalLights.sgRegisterLight(light);
}
void LightManager::sgRegisterGlobalLights(bool staticlighting)
{
// make sure we're clean...
sgUnregisterAllLights();
// ask all light objects to register themselves...
SimSet *lightset = Sim::getLightSet();
for(SimObject **itr=lightset->begin(); itr!=lightset->end(); itr++)
(*itr)->registerLights(this, staticlighting);
}
void LightManager::sgUnregisterAllLights()
{
sgRegisteredGlobalLights.clear();
sgRegisteredLocalLights.clear();
dMemset(&sgSpecialLights, 0, sizeof(sgSpecialLights));
}
void LightManager::sgGetAllUnsortedLights(LightInfoList &list)
{
list.clear();
list.merge(sgRegisteredGlobalLights);
list.merge(sgRegisteredLocalLights);
// find dupes...
dQsort(list.address(), list.size(), sizeof(LightInfo*), sgSortLightsByAddress);
LightInfo *last = NULL;
for(U32 i=0; i<list.size(); i++)
{
if(list[i] == last)
{
list.erase(i);
i--;
continue;
}
last = list[i];
}
}
void LightManager::sgSetupLights(SceneObject *obj)
{
PROFILE_START(LightManager_sgSetupLights);
sgResetLights();
bool outside = false;
for(U32 i=0; i<obj->getNumCurrZones(); i++)
{
if(obj->getCurrZone(i) == 0)
{
outside = true;
break;
}
}
sgSetProperty(sgReceiveSunLightProp, obj->receiveSunLight);
sgSetProperty(sgAdaptiveSelfIlluminationProp, obj->useAdaptiveSelfIllumination);
sgSetProperty(sgCustomAmbientLightingProp, obj->useCustomAmbientLighting);
sgSetProperty(sgCustomAmbientForSelfIlluminationProp, obj->customAmbientForSelfIllumination);
ColorF ambientColor;
ColorF selfillum = obj->customAmbientLighting * 0.5f;
LightInfo *sun = sgGetSpecialLight(sgSunLightType);
if(obj->getLightingAmbientColor(&ambientColor))
{
const F32 directionalFactor = 0.5f;
const F32 ambientFactor = 0.5f;
dMemset(&obj->mLightingInfo.smAmbientLight, 0, sizeof(obj->mLightingInfo.smAmbientLight));
LightInfo &light = obj->mLightingInfo.smAmbientLight;
light.mType = LightInfo::Ambient;
light.mDirection = VectorF(0.0f, 0.0f, -1.0f);
light.sgCastsShadows = sun->sgCastsShadows;
// players, vehicles, ...
if(obj->overrideOptions)
{
if(outside)
{
light.mType = LightInfo::Vector;
light.mDirection = sun->mDirection;
}
//else
//{
light.mColor = ambientColor * directionalFactor;
light.mAmbient = ambientColor * ambientFactor;
//}
}// beyond here are the static dts options...
else if(sgAllowDiffuseCustomAmbient())
{
light.mColor = obj->customAmbientLighting * 0.5f;
light.mAmbient = obj->customAmbientLighting * 0.5f;
}
else if(sgAllowReceiveSunLight() && sun)
{
light.mType = LightInfo::Vector;
if(outside)
light.mDirection = sun->mDirection;
if(obj->receiveLMLighting)
light.mColor = ambientColor * 0.8f;
else
light.mColor = sun->mColor;
light.mAmbient = sun->mAmbient;
}
else if(obj->receiveLMLighting)
{
light.mColor = ambientColor * directionalFactor;
light.mAmbient = ambientColor * ambientFactor;
}
if(sgAllowCollectSelfIlluminationColor())
{
selfillum = light.mAmbient + light.mColor;
selfillum.clamp();
}
light.mPos = light.mDirection * -10000.0f;
sgRegisterLocalLight(&obj->mLightingInfo.smAmbientLight);
}
// install assigned baked lights from simgroup...
// step one get the objects...
U32 i;
NetConnection *connection = NetConnection::getConnectionToServer();
for(i=0; i<obj->lightIds.size(); i++)
{
SimObject *sim = connection->resolveGhost(obj->lightIds[i]);
if(!sim)
continue;
sgLightObject *light = dynamic_cast<sgLightObject*>(sim);
if(!light)
continue;
sgLightObjectData *data = static_cast<sgLightObjectData *>(light->getDataBlock());
if((data) && (data->sgStatic) && (data->mLightOn) && (light->mEnable))
{
light->mLight.sgAssignedToTSObject = true;
sgRegisterLocalLight(&light->mLight);
}
}
// step three install dynamic lights...
sgUseSelfIlluminationColor = sgGetProperty(sgAdaptiveSelfIlluminationProp);
if(sgUseSelfIlluminationColor)
sgSelfIlluminationColor = selfillum;
sgSetupZoneLighting(true, obj);
sgFindBestLights(obj, obj->getRenderWorldBox(), sgMaxBestLights, Point3F(0.0f, 0.0f, 0.0f), false);
sgInstallLights();
PROFILE_END();
}
void LightManager::sgSetupLights(SceneObject *obj, const Point3F &camerapos,
const Point3F &cameradir, F32 viewdist, S32 maxlights)
{
sgResetLights();
sgSetupZoneLighting(true, obj);
Box3F box;
box.max = camerapos + Point3F(viewdist, viewdist, viewdist);
box.min = camerapos - Point3F(viewdist, viewdist, viewdist);
sgFindBestLights(obj, box, maxlights, cameradir, true);
}
void LightManager::sgSetupLights(SceneObject *obj, const Box3F &box, S32 maxlights)
{
sgResetLights();
sgSetupZoneLighting(true, obj);
sgFindBestLights(obj, box, maxlights, Point3F(0.0f, 0.0f, 0.0f), true);
}
void LightManager::sgInstallLights()
{
U32 count = getMin(U32(sgBestLights.size()), U32(8));
glEnable(GL_LIGHTING);
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, (const F32 *)ColorF(0.0f, 0.0f, 0.0f, 0.0f));
for(U32 i=0; i<count; i++)
{
LightInfo *light = sgBestLights[i];
sgLightingModel &lightingmodel = sgLightingModelManager::sgGetLightingModel(
light->sgLightingModelName);
lightingmodel.sgSetState(light);
U32 gllight = GL_LIGHT0 + i;
glEnable(gllight);
lightingmodel.sgLightingGL(gllight);
lightingmodel.sgResetState();
}
}
void LightManager::sgResetLights()
{
sgSetupZoneLighting(false, NULL);
sgRegisteredLocalLights.clear();
sgBestLights.clear();
// ok these seem weird, but dts rendering changes them...
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (const F32 *)ColorF(0.0f, 0.0f, 0.0f, 0.0f));
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (const F32 *)ColorF(1.0f, 1.0f, 1.0f, 1.0f));
for(S32 i=7; i>=0; i--)
glDisable(GL_LIGHT0 + i);
glDisable(GL_LIGHTING);
}
void LightManager::sgFindBestLights(SceneObject *obj, const Box3F &box, S32 maxlights, const Point3F &viewdi, bool camerabased)
{
sgBestLights.clear();
// gets them all and removes any dupes...
sgGetAllUnsortedLights(sgBestLights);
SphereF sphere;
box.getCenter(&sphere.center);
sphere.radius = Point3F(box.max - sphere.center).len();
for(U32 i=0; i<sgBestLights.size(); i++)
sgScoreLight(sgBestLights[i], obj, box, sphere, camerabased);
dQsort(sgBestLights.address(), sgBestLights.size(), sizeof(LightInfo*), sgSortLightsByScore);
for(U32 i=0; i<sgBestLights.size(); i++)
{
if((sgBestLights[i]->mScore > 0) && (i < maxlights))
continue;
sgBestLights.setSize(i);
break;
}
}
void LightManager::sgScoreLight(LightInfo *light, SceneObject *obj, const Box3F &box, const SphereF &sphere, bool camerabased)
{
if(sgFilterZones && light->sgDiffuseRestrictZone)
{
bool allowdiffuse = false;
if(sgZones[0] > -1)
{
if(light->sgAllowDiffuseZoneLighting(sgZones[0]))
allowdiffuse = true;
else if(sgZones[1] > -1)
{
if(light->sgAllowDiffuseZoneLighting(sgZones[1]))
allowdiffuse = true;
}
}
if(!allowdiffuse)
{
light->mScore = 0;
return;
}
}
F32 distintensity = 1.0f;
F32 colorintensity = 1.0f;
F32 weight = SG_LIGHTMANAGER_DYNAMIC_PRIORITY;
if(camerabased)
{
sgLightingModel &model = sgLightingModelManager::sgGetLightingModel(light->sgLightingModelName);
model.sgSetState(light);
F32 maxrad = model.sgGetMaxRadius(true);
model.sgResetState();
Point3F vect = sphere.center - light->mPos;
F32 dist = vect.len();
F32 distlightview = sphere.radius + maxrad;
if(distlightview <= 0.0f)
distintensity = 0.0f;
else
{
distintensity = 1.0f - (dist / distlightview);
distintensity = mClampF(distintensity, 0.0f, 1.0f);
}
}
else
{
// side test...
if((light->mType == LightInfo::Spot) || (light->mType == LightInfo::SGStaticSpot))
{
bool anyfront = false;
F32 x, y, z;
for(U32 i=0; i<8; i++)
{
if(i & 0x1)
x = box.max.x;
else
x = box.min.x;
if(i & 0x2)
y = box.max.y;
else
y = box.min.y;
if(i & 0x4)
z = box.max.z;
else
z = box.min.z;
if(light->sgSpotPlane.whichSide(Point3F(x, y, z)) == PlaneF::Back)
continue;
anyfront = true;
break;
}
if(!anyfront)
{
light->mScore = 0;
return;
}
}
if((light->mType == LightInfo::Vector) || (light->mType == LightInfo::Ambient))
{
colorintensity =
(light->mColor.red + light->mAmbient.red) * 0.346f +
(light->mColor.green + light->mAmbient.green) * 0.588f +
(light->mColor.blue + light->mAmbient.blue) * 0.070f;
distintensity = 1;
weight = SG_LIGHTMANAGER_SUN_PRIORITY;
}
else
{
if(light->sgAssignedToParticleSystem)
{
colorintensity = SG_PARTICLESYSTEMLIGHT_FIXED_INTENSITY;
}
else
{
colorintensity =
(light->mColor.red * 0.3333f) +
(light->mColor.green * 0.3333f) +
(light->mColor.blue * 0.3333f);
}
sgLightingModel &model = sgLightingModelManager::sgGetLightingModel(light->sgLightingModelName);
model.sgSetState(light);
distintensity = model.sgScoreLight(light, sphere);
model.sgResetState();
if(light->sgAssignedToTSObject)
weight = SG_LIGHTMANAGER_ASSIGNED_PRIORITY;
else if((light->mType == LightInfo::SGStaticPoint) || (light->mType == LightInfo::SGStaticSpot))
weight = SG_LIGHTMANAGER_STATIC_PRIORITY;
if(((light->mType == LightInfo::SGStaticPoint) || (light->mType == LightInfo::SGStaticSpot)) &&
light->sgCastsShadows && (distintensity > 0.0f) && (sgDynamicLightingOcclusionQuality < dlqtNoShadows) &&
obj->useLightingOcclusion)
{
sgDTSDynamicLightingCache::sgCacheEntry *entry = sgDTSDynamicLightingCache::sgFindCacheEntry((void *)obj, light);
if((!entry->info.sgAlreadyProcessed) ||
(entry->info.sgLastObjectMoveSnapshotId != obj->moveSnapshotId) ||
(entry->info.sgLastLightMoveSnapshotId != light->sgMoveSnapshotId))
{
entry->info.sgAlreadyProcessed = true;
entry->info.sgLastObjectMoveSnapshotId = obj->moveSnapshotId;
entry->info.sgLastLightMoveSnapshotId = light->sgMoveSnapshotId;
U32 shadowcalcs = 0;
F32 shadowamount = 0.0f;
F32 x, y, z;
RayInfo info;
obj->disableCollision();
U32 samples = (sgDynamicLightingOcclusionQuality < dlqtCenterSample) ? 7 : 1;
for(U32 a=0; a<samples; a++)
{
Point3F pos = sphere.center;
switch(a)
{
//case 0:
// pos = pos;
// break;
case 1:
pos.x = box.max.x;
break;
case 2:
pos.x = box.min.x;
break;
case 3:
pos.y = box.max.y;
break;
case 4:
pos.y = box.min.y;
break;
case 5:
pos.z = box.max.z;
break;
case 6:
pos.z = box.min.z;
break;
};
Point3F planenorm = pos - sphere.center;
Point3F lightdir = sphere.center - light->mPos;
if((sgDynamicLightingOcclusionQuality > dlqtSevenSample) && (mDot(planenorm, lightdir) > 0.0f))
continue;
shadowcalcs++;
if(gClientContainer.castRay(light->mPos, pos, ShadowCasterObjectType, &info))
shadowamount += 1.0f;
}
obj->enableCollision();
entry->info.sgCachedLightingMultiplier = 1.0f - (shadowamount / ((F32)shadowcalcs));
}
distintensity *= entry->info.sgCachedLightingMultiplier;
light->sgDTSLightingOcclusionAdjust = entry->info.sgCachedLightingMultiplier;
}
else
light->sgDTSLightingOcclusionAdjust = 1.0f;
}
}
F32 intensity = colorintensity * distintensity;
if(intensity < SG_MIN_LEXEL_INTENSITY)
intensity = 0.0f;
light->mScore = S32(intensity * weight * 1024.0f);
}
void LightManager::sgInit()
{
for(U32 i=0; i<sgPropertyCount; i++)
sgLightingProperties[i] = false;
Con::addVariable("$pref::LightManager::sgDynamicParticleSystemLighting", TypeBool, &sgDynamicParticleSystemLighting);
Con::addVariable("$pref::LightManager::sgBlendedTerrainDynamicLighting", TypeBool, &sgBlendedTerrainDynamicLighting);
Con::addVariable("$pref::LightManager::sgMaxBestLights", TypeS32, &sgMaxBestLights);
Con::addVariable("$pref::LightManager::sgLightingProfileQuality", TypeS32, &sgLightingProfileQuality);
Con::addVariable("$pref::LightManager::sgLightingProfileAllowShadows", TypeBool, &sgLightingProfileAllowShadows);
Con::addVariable("$pref::LightManager::sgUseDynamicShadows", TypeBool, &sgUseDynamicShadows);
Con::addVariable("$pref::LightManager::sgDynamicLightingOcclusionQuality", TypeS32, &sgDynamicLightingOcclusionQuality);
Con::addVariable("$pref::LightManager::sgDynamicShadowQuality", TypeS32, &sgDynamicShadowQuality);
Con::addVariable("$pref::LightManager::sgMultipleDynamicShadows", TypeBool, &sgMultipleDynamicShadows);
Con::addVariable("$LightManager::sgInGUIEditor", TypeBool, &sgInGUIEditor);
Con::addVariable("$pref::Interior::sgDetailMaps", TypeBool, &sgDetailMaps);
sgRelightFilter::sgInit();
}
bool LightManager::sgAllowDetailMaps()
{
return (sgDetailMaps && (dglGetMaxTextureUnits() >= 4));
}
void LightManager::sgGetFilteredLightColor(ColorF &color, ColorF &ambient, S32 objectzone)
{
sgMissionLightingFilter *filterbasezone = NULL;
sgMissionLightingFilter *filtercurrentzone = NULL;
SimSet *filters = Sim::getsgMissionLightingFilterSet();
for(SimObject ** itr = filters->begin(); itr != filters->end(); itr++)
{
sgMissionLightingFilter *filter = dynamic_cast<sgMissionLightingFilter*>(*itr);
if(!filter)
continue;
S32 zone = filter->getCurrZone(0);
if(zone == 0)
filterbasezone = filter;
if(zone == objectzone)
{
filtercurrentzone = filter;
break;
}
}
if(filtercurrentzone)
filterbasezone = filtercurrentzone;
if(!filterbasezone)
return;
sgMissionLightingFilterData *datablock = (sgMissionLightingFilterData *)filterbasezone->getDataBlock();
if(!datablock)
return;
ColorF composite = datablock->sgLightingFilter * datablock->sgLightingIntensity;
color *= composite;
color.clamp();
ambient *= composite;
ambient.clamp();
if(!datablock->sgCinematicFilter)
return;
// must use the lighting filter intensity
// to lock the reference value relative
// to the lighting intensity
composite = datablock->sgCinematicFilterReferenceColor *
datablock->sgCinematicFilterReferenceIntensity *
datablock->sgLightingIntensity;
F32 intensity = color.red + color.green + color.blue + ambient.red + ambient.green + ambient.blue;
F32 intensityref = composite.red + composite.green + composite.blue;
intensity -= intensityref;
// blue is too intense...
if(intensity > 0.0f)
intensity *= 0.25f;
F32 redoffset = 1.0f - ((intensity) * 0.1f * datablock->sgCinematicFilterAmount);
F32 blueoffset = 1.0f + ((intensity) * 0.1f * datablock->sgCinematicFilterAmount);
F32 greenoffset = 1.0f - ((1.0f - getMin(redoffset, blueoffset)) * 0.5f);
ColorF multiplier = ColorF(redoffset, greenoffset, blueoffset);
color *= multiplier;
color.clamp();
ambient *= multiplier;
ambient.clamp();
}
void LightManager::sgSetupZoneLighting(bool enable, SimObject *sobj)
{
sgFilterZones = false;
// these must be -2...
sgZones[0] = -2;
sgZones[1] = -2;
if(!enable)
return;
if(dynamic_cast<InteriorInstance *>(sobj))
return;
SceneObject *obj = dynamic_cast<SceneObject *>(sobj);
if(!obj)
return;
sgFilterZones = true;
U32 count = getMin(obj->getNumCurrZones(), U32(2));
for(U32 i=0; i<count; i++)
{
sgZones[i] = obj->getCurrZone(i);
}
}
void LightManager::sgSetupExposureRendering()
{
if(!dglDoesSupportARBMultitexture())
return;
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, SG_LIGHTING_OVERBRIGHT_AMOUNT);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
}
void LightManager::sgResetExposureRendering()
{
if(!dglDoesSupportARBMultitexture())
return;
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, SG_LIGHTING_NORMAL_AMOUNT);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
}
// adds proper support for self-illumination...
void LightManager::sgSetAmbientSelfIllumination(LightInfo *lightinfo, F32 *lightColor,
F32 *ambientColor)
{
//LightInfo *lightInfo = (LightInfo *)lightinfo;
if(sgAllowCollectSelfIlluminationColor())
{
if(lightinfo->mType == LightInfo::Vector)
sgSelfIlluminationColor = ColorF(lightColor[0], lightColor[1], lightColor[2]);
else
sgSelfIlluminationColor = ColorF(ambientColor[0], ambientColor[1], ambientColor[2]);
}
}
void sgStatistics::sgClear()
{
sgInteriorLexelCount = 0;
sgInteriorLexelTime = 0;
sgInteriorLexelDiffuseCount = 0;
sgInteriorObjectCount = 0;
sgInteriorObjectIncludedCount = 0;
sgInteriorObjectIlluminationCount = 0;
sgInteriorSurfaceIncludedCount = 0;
sgInteriorSurfaceIlluminationCount = 0;
sgInteriorSurfaceIlluminatedCount = 0;
sgInteriorSurfaceSmoothedCount = 0;
sgInteriorSurfaceSmoothedLexelCount = 0;
sgInteriorSurfaceSetupTime = 0;
sgInteriorSurfaceSetupCount = 0;
sgInteriorSurfaceMergeTime = 0;
sgInteriorSurfaceMergeCount = 0;
sgStaticMeshSurfaceOccluderCount = 0;
sgTerrainLexelCount = 0;
sgTerrainLexelTime = 0;
}
void sgStatistics::sgPrint()
{
Con::printf("");
Con::printf(" Lighting Pack lighting system stats:");
Con::printf(" Interior Lexel Count: %d", sgInteriorLexelCount);
Con::printf(" Interior Lexel Time (ms): %f", F32(sgInteriorLexelTime) / getMax(1.0f, F32(sgInteriorLexelCount)));
Con::printf(" Interior Lexel Time Total (ms): %d", sgInteriorLexelTime);
Con::printf(" Interior Lexel Diffuse Count: %d", sgInteriorLexelDiffuseCount);
Con::printf(" Interior Object Count: %d", sgInteriorObjectCount);
Con::printf(" Interior Object Included Count: %d", sgInteriorObjectIncludedCount);
Con::printf(" Interior Object Illumination Count: %d", sgInteriorObjectIlluminationCount);
Con::printf(" Interior Surface Included Count: %d", sgInteriorSurfaceIncludedCount);
Con::printf(" Interior Surface Illumination Count: %d", sgInteriorSurfaceIlluminationCount);
Con::printf(" Interior Surface Illuminated Count: %d", sgInteriorSurfaceIlluminatedCount);
Con::printf(" Interior Surface Smoothed Count: %d", sgInteriorSurfaceSmoothedCount);
Con::printf(" Interior Surface Smoothed Lexel Count: %d", sgInteriorSurfaceSmoothedLexelCount);
Con::printf(" Interior Surface Setup Count: %d", sgInteriorSurfaceSetupCount);
Con::printf(" Interior Surface Setup Time Total (ms): %d", sgInteriorSurfaceSetupTime);
Con::printf(" Interior Surface Merge Count: %d", sgInteriorSurfaceMergeCount);
Con::printf(" Interior Surface Merge Time Total (ms): %d", sgInteriorSurfaceMergeTime);
Con::printf(" Static Mesh Surface Occluder Count: %d", sgStaticMeshSurfaceOccluderCount);
Con::printf(" Terrain Lexel Count: %d", sgTerrainLexelCount);
Con::printf(" Terrain Lexel Time (ms): %f", F32(sgTerrainLexelTime) / getMax(1.0f, F32(sgTerrainLexelCount)));
Con::printf(" Terrain Lexel Time Total (ms): %d", sgTerrainLexelTime);
}
S32 QSORT_CALLBACK LightManager::sgSortLightsByAddress(const void* a, const void* b)
{
return ((*(LightInfo**)b) - (*(LightInfo**)a));
}
S32 QSORT_CALLBACK LightManager::sgSortLightsByScore(const void* a, const void* b)
{
return((*(LightInfo**)b)->mScore - (*(LightInfo**)a)->mScore);
}
void sgRelightFilter::sgInit()
{
Con::addVariable("SceneLighting::sgFilterRelight", TypeBool, &sgRelightFilter::sgFilterRelight);
Con::addVariable("SceneLighting::sgFilterRelightVisible", TypeBool, &sgRelightFilter::sgFilterRelightVisible);
Con::addVariable("SceneLighting::sgFilterRelightByDistance", TypeBool, &sgRelightFilter::sgFilterRelightByDistance);
Con::addVariable("SceneLighting::sgFilterRelightByDistanceRadius", TypeF32, &sgRelightFilter::sgFilterRelightByDistanceRadius);
Con::addVariable("SceneLighting::sgFilterRelightByDistancePosition", TypePoint3F, &sgRelightFilter::sgFilterRelightByDistancePosition);
}
bool sgRelightFilter::sgAllowLighting(const Box3F &box, bool forcefilter)
{
if((sgRelightFilter::sgFilterRelight && sgRelightFilter::sgFilterRelightByDistance) || forcefilter)
{
if(!sgRelightFilter::sgFilterRelightVisible)
return false;
Point3F min = EditTSCtrl::smCamPos;
min.x = min.x - sgRelightFilter::sgFilterRelightByDistanceRadius;
min.y = min.y - sgRelightFilter::sgFilterRelightByDistanceRadius;
min.z = min.z - sgRelightFilter::sgFilterRelightByDistanceRadius;
Point3F max = EditTSCtrl::smCamPos;
max.x = max.x + sgRelightFilter::sgFilterRelightByDistanceRadius;
max.y = max.y + sgRelightFilter::sgFilterRelightByDistanceRadius;
max.z = max.z + sgRelightFilter::sgFilterRelightByDistanceRadius;
Box3F lightbox(min, max);
if(!box.isOverlapped(lightbox))
return false;
}
return true;
}
void sgRelightFilter::sgRenderAllowedObjects(void *editor)
{
U32 i;
WorldEditor *worldeditor = (WorldEditor *)editor;
Vector<SceneObject *> objects;
gServerContainer.findObjects(InteriorObjectType, sgFindObjectsCallback, &objects);
const ColorI color(255, 0, 255);
for(i = 0; i < objects.size(); i++)
{
SceneObject * obj = objects[i];
if(worldeditor->objClassIgnored(obj))
continue;
if(!sgRelightFilter::sgAllowLighting(obj->getWorldBox(), true))
continue;
worldeditor->renderObjectBox(obj, color);
}
}

View File

@ -0,0 +1,426 @@
//-----------------------------------------------
// Synapse Gaming - Lighting System
// Copyright <20> Synapse Gaming 2003
// Written by John Kabus
//-----------------------------------------------
#ifndef _SGLIGHTMANAGER_H_
#define _SGLIGHTMANAGER_H_
#ifndef _MMATH_H_
#include "math/mMath.h"
#endif
#ifndef _COLOR_H_
#include "core/color.h"
#endif
#ifndef _TVECTOR_H_
#include "core/tVector.h"
#endif
#ifndef _DATACHUNKER_H_
#include "core/dataChunker.h"
#endif
#include "console/console.h"
#include "console/consoleTypes.h"
#include "core/stringTable.h"
#include "core/crc.h"
#include "lightingSystem/sgHashMap.h"
class SceneObject;
static void sgFindObjectsCallback(SceneObject* obj, void *val)
{
Vector<SceneObject*> * list = (Vector<SceneObject*>*)val;
list->push_back(obj);
}
//-----------------------------------------------
// Original name maintained due to widespread use...
class LightInfo
{
friend class LightManager;
public:
enum Type {
Point = 0,
Spot = 1,
Vector = 2,
Ambient = 3,
SGStaticPoint,
SGStaticSpot
};
Type mType;
Point3F mPos;
VectorF mDirection;
ColorF mColor;
ColorF mAmbient;
F32 mRadius;
S32 mScore;
public:
F32 sgSpotAngle;
bool sgAssignedToTSObject;
bool sgCastsShadows;
bool sgDiffuseRestrictZone;
bool sgAmbientRestrictZone;
S32 sgZone[2];
F32 sgLocalAmbientAmount;
bool sgSmoothSpotLight;
bool sgDoubleSidedAmbient;
bool sgAssignedToParticleSystem;
StringTableEntry sgLightingModelName;
bool sgUseNormals;
MatrixF sgLightingTransform;
PlaneF sgSpotPlane;
// temp data used by the system...
Point3F sgTempModelInfo;
F32 sgDTSLightingOcclusionAdjust;
// this increases on tracked lights as they move...
U32 sgMoveSnapshotId;
bool sgTrackMoveSnapshot;
LightInfo();
bool sgIsInZone(S32 zone);
bool sgAllowDiffuseZoneLighting(S32 zone);
};
class LightInfoList : public Vector<LightInfo*>
{
public:
void sgRegisterLight(LightInfo *light);
void sgUnregisterLight(LightInfo *light);
};
//-----------------------------------------------
// Original name maintained due to widespread use...
class LightManager
{
public:
enum sgSpecialLightTypesEnum
{
sgSunLightType,
sgSpecialLightTypesCount
};
LightManager()
{
dMemset(&sgSpecialLights, 0, sizeof(sgSpecialLights));
sgInit();
}
// registered before scene traversal...
void sgRegisterGlobalLight(LightInfo *light);
void sgUnregisterGlobalLight(LightInfo *light) {sgRegisteredGlobalLights.sgUnregisterLight(light);}
// registered per object...
void sgRegisterLocalLight(LightInfo *light) {sgRegisteredLocalLights.sgRegisterLight(light);}
void sgUnregisterLocalLight(LightInfo *light) {sgRegisteredLocalLights.sgUnregisterLight(light);}
void sgRegisterGlobalLights(bool staticlighting);
void sgUnregisterAllLights();
/// Returns all unsorted and un-scored lights (both global and local).
void sgGetAllUnsortedLights(LightInfoList &list);
/// Copies the best lights list - this DOESN'T find the lights! Call
/// sgSetupLights to populate the list.
void sgGetBestLights(LightInfoList &list)
{
list.clear();
list.merge(sgBestLights);
}
/// For DST objects. Finds the best lights
/// including a composite based on the environmental
/// ambient lighting amount *and installs them in OpenGL*.
void sgSetupLights(SceneObject *obj);
/// For the terrain and Atlas. Finds the best
/// lights in the viewing area based on distance to camera.
void sgSetupLights(SceneObject *obj, const Point3F &camerapos,
const Point3F &cameradir, F32 viewdist, S32 maxlights);
/// Finds the best lights that overlap with the bounding box
/// based on the box center.
void sgSetupLights(SceneObject *obj, const Box3F &box, S32 maxlights);
/// Add the top 8 best lights to OpenGL.
void sgInstallLights();
/// Reset the best lights list and all associated data.
void sgResetLights();
private:
LightInfo *sgSpecialLights[sgSpecialLightTypesCount];
public:
LightInfo *sgGetSpecialLight(sgSpecialLightTypesEnum type);
void sgSetSpecialLight(sgSpecialLightTypesEnum type, LightInfo *light) {sgSpecialLights[type] = light;}
void sgClearSpecialLights();
private:
// registered before scene traversal...
LightInfoList sgRegisteredGlobalLights;
// registered per object...
LightInfoList sgRegisteredLocalLights;
// best lights per object...
LightInfoList sgBestLights;
void sgFindBestLights(SceneObject *obj, const Box3F &box, S32 maxlights, const Point3F &viewdir, bool camerabased);
// used in DTS lighting...
void sgScoreLight(LightInfo *light, SceneObject *obj, const Box3F &box, const SphereF &sphere, bool camerabased);
public:
enum lightingProfileQualityType
{
// highest quality - for in-game and final tweaks...
lpqtProduction = 0,
// medium quality - for lighting layout...
lpqtDesign = 1,
// low quality - for object placement...
lpqtDraft = 2
};
enum dynamicLightingQualityType
{
dlqtSevenSample = 0,
dlqtFourSample = 1,
dlqtCenterSample = 2,
dlqtNoShadows = 3
};
enum sgLightingPropertiesEnum
{
sgReceiveSunLightProp,
sgAdaptiveSelfIlluminationProp,
sgCustomAmbientLightingProp,
sgCustomAmbientForSelfIlluminationProp,
sgPropertyCount
};
static bool sgGetProperty(U32 prop)
{
AssertFatal((prop < sgPropertyCount), "Invalid property type!");
return sgLightingProperties[prop];
}
static void sgSetProperty(U32 prop, bool val)
{
AssertFatal((prop < sgPropertyCount), "Invalid property type!");
sgLightingProperties[prop] = val;
}
static bool sgAllowDiffuseCustomAmbient() {return sgLightingProperties[sgCustomAmbientLightingProp] && (!sgLightingProperties[sgCustomAmbientForSelfIlluminationProp]);}
static bool sgAllowAdaptiveSelfIllumination() {return sgLightingProperties[sgAdaptiveSelfIlluminationProp];}
static bool sgAllowCollectSelfIlluminationColor() {return !sgLightingProperties[sgCustomAmbientLightingProp];}
static bool sgAllowReceiveSunLight() {return sgLightingProperties[sgReceiveSunLightProp] && (!sgAllowDiffuseCustomAmbient());}
private:
static bool sgLightingProperties[sgPropertyCount];
static U32 sgLightingProfileQuality;
static bool sgLightingProfileAllowShadows;
static LightInfo sgDefaultLight;
static bool sgDetailMaps;
static U32 sgDynamicLightingOcclusionQuality;
static bool sgUseDynamicShadows;
static U32 sgDynamicShadowQuality;
static bool sgUseSelfIlluminationColor;
static ColorF sgSelfIlluminationColor;
static bool sgDynamicParticleSystemLighting;
static bool sgBlendedTerrainDynamicLighting;
static bool sgFilterZones;
static S32 sgZones[2];
static S32 sgMaxBestLights;
static bool sgInGUIEditor;
public:
static bool sgMultipleDynamicShadows;
static bool sgAllowDynamicShadows() {return sgUseDynamicShadows;}
static U32 sgGetDynamicShadowQuality() {return sgDynamicShadowQuality;}
static void sgSetDynamicShadowQuality(U32 quality) {sgDynamicShadowQuality = quality;}
static bool sgAllowDynamicParticleSystemLighting() {return sgDynamicParticleSystemLighting;}
static bool sgAllowBlendedTerrainDynamicLighting();
static ColorF sgGetSelfIlluminationColor(ColorF defaultcol)
{
if(sgUseSelfIlluminationColor)
return sgSelfIlluminationColor;
return defaultcol;
}
static void sgInit();
static bool sgAllowDetailMaps();
static bool sgAllowShadows() {return sgLightingProfileAllowShadows;}
static bool sgAllowFullLightMaps() {return (sgLightingProfileQuality == lpqtProduction);}
static U32 sgGetLightMapScale()
{
if(sgLightingProfileQuality == lpqtDesign) return 2;
if(sgLightingProfileQuality == lpqtDraft) return 4;
return 1;
}
static void sgGetFilteredLightColor(ColorF &color, ColorF &ambient, S32 objectzone);
static void sgSetupZoneLighting(bool enable, SimObject *sobj);
static void sgSetupExposureRendering();
static void sgResetExposureRendering();
static void sgSetAmbientSelfIllumination(LightInfo *lightinfo, F32 *lightColor,
F32 *ambientColor);
private:
static S32 QSORT_CALLBACK sgSortLightsByAddress(const void *, const void *);
static S32 QSORT_CALLBACK sgSortLightsByScore(const void *, const void *);
};
class sgRelightFilter
{
public:
static bool sgFilterRelight;
static bool sgFilterRelightVisible;
static bool sgFilterRelightByDistance;
static F32 sgFilterRelightByDistanceRadius;
static Point3F sgFilterRelightByDistancePosition;
static void sgInit();
static bool sgAllowLighting(const Box3F &box, bool forcefilter);
static void sgRenderAllowedObjects(void *worldeditor);
};
class sgStatistics
{
public:
static U32 sgInteriorLexelCount;
static U32 sgInteriorLexelTime;
static U32 sgInteriorLexelDiffuseCount;
static U32 sgInteriorObjectCount;
static U32 sgInteriorObjectIncludedCount;
static U32 sgInteriorObjectIlluminationCount;
static U32 sgInteriorSurfaceIncludedCount;
static U32 sgInteriorSurfaceIlluminationCount;
static U32 sgInteriorSurfaceIlluminatedCount;
static U32 sgInteriorSurfaceSmoothedCount;
static U32 sgInteriorSurfaceSmoothedLexelCount;
static U32 sgInteriorSurfaceSetupTime;
static U32 sgInteriorSurfaceSetupCount;
static U32 sgInteriorSurfaceMergeTime;
static U32 sgInteriorSurfaceMergeCount;
static U32 sgStaticMeshSurfaceOccluderCount;
static U32 sgTerrainLexelCount;
static U32 sgTerrainLexelTime;
static void sgClear();
static void sgPrint();
};
class sgInteriorDynamicLightingCache
{
public:
struct data
{
bool sgAlreadyProcessed;
U32 sgLastMoveSnapshotId;
// internally managed changes...
void *sgInteriorDetail;
U32 sgLightCRC;
};
typedef hash_multimap<U32, data> sgCacheEntry;
private:
static sgCacheEntry sgCache;
public:
static sgCacheEntry *sgFindCacheEntry(void *interiorinstance,
void *interiordetail, LightInfo *light)
{
// get the hash...
U32 val = U32(interiorinstance);
U32 hash = calculateCRC(&val, sizeof(U32));
val = U32(light);
hash = calculateCRC(&val, sizeof(U32), hash);
// get the entry...
sgCacheEntry *entry = sgCache.find(hash);
// verify nothings changed...
U32 lightcrc = calculateCRC(light, sizeof(LightInfo));
if((entry->info.sgInteriorDetail != interiordetail) ||
(entry->info.sgLightCRC != lightcrc))
{
entry->info.sgAlreadyProcessed = false;
entry->info.sgInteriorDetail = interiordetail;
entry->info.sgLightCRC = lightcrc;
entry->object.clear();
}
return entry;
}
};
class sgDTSDynamicLightingCache
{
public:
struct data
{
bool sgAlreadyProcessed;
U32 sgLastObjectMoveSnapshotId;
U32 sgLastLightMoveSnapshotId;
F32 sgCachedLightingMultiplier;
};
typedef hash_multimap<U32, data> sgCacheEntry;
private:
static sgCacheEntry sgCache;
public:
static sgCacheEntry *sgFindCacheEntry(void *sceneobject, LightInfo *light)
{
// get the hash...
U32 val = U32(sceneobject);
U32 hash = calculateCRC(&val, sizeof(U32));
val = U32(light);
hash = calculateCRC(&val, sizeof(U32), hash);
// get the entry...
return sgCache.find(hash);
}
};
//----------------------------------------------
// performance testing
class elapsedTimeAggregate
{
private:
U32 time;
U32 *resultVar;
public:
elapsedTimeAggregate(U32 &timeresultvar)
{
resultVar = &timeresultvar;
time = Platform::getRealMilliseconds();
}
~elapsedTimeAggregate()
{
*resultVar += (Platform::getRealMilliseconds() - time);
}
};
#define SG_PERFORMANCE_TESTING_OUTPUT
#ifdef SG_PERFORMANCE_TESTING_OUTPUT
class elapsedTime
{
private:
char info[256];
U32 time;
public:
elapsedTime(char *infostr)
{
dStrcpy(info, infostr);
time = Platform::getRealMilliseconds();
}
~elapsedTime()
{
Con::printf(info, (Platform::getRealMilliseconds() - time));
}
};
#else
class elapsedTime
{
public:
elapsedTime(char *infostr) {}
};
#endif
#endif//_SGLIGHTMANAGER_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,223 @@
//-----------------------------------------------
// Synapse Gaming - Lighting Code Pack
// Copyright <20> Synapse Gaming 2003 - 2005
// Written by John Kabus
//
// Overview:
// Code from the Lighting Pack's (Torque Lighting Kit)
// lighting system, which was modified for use
// with Constructor.
//-----------------------------------------------
#ifndef _SGLIGHTMAP_H_
#define _SGLIGHTMAP_H_
//#include "constructor/lightingSystem/stockLightingPlugin/stockLightingSchema.h"
//#include "constructor/lightingSystem/stockLightingPlugin/sgLightManager.h"
#include "lightingSystem/sgLighting.h"
#include "lightingSystem/sgBinaryVolumePartitionTree.h"
#include "math/mBox.h"
class sgShadowObjects
{
public:
/// used for storing static mesh geometry for fast shadow detection...
struct sgStaticMeshTri
{
Point3F sgVert[3];
PlaneF sgPlane;
};
/// BVPT to static mesh geometry mapping typedef...
typedef BVPT<sgStaticMeshTri *> sgStaticMeshBVPT;
/// object info...
struct sgObjectInfo
{
MatrixF sgInverseTransform;
sgStaticMeshBVPT sgBVPT;
Vector<sgStaticMeshTri> sgTris;
};
/// static mesh to object mapping typedef...
typedef hash_multimap<void *, sgObjectInfo *> sgStaticMeshBVPTEntry;
/// s and e are in interior space, not static mesh space...
static bool sgCastRayStaticMesh(Point3F s, Point3F e, ConstructorSimpleMesh *staticmesh);
static void sgClearStaticMeshBVPTData();
private:
/// master object info storage...
static Vector<sgObjectInfo *> sgObjectInfoStorage;
/// static mesh to BVPT mapping...
static sgStaticMeshBVPTEntry sgStaticMeshBVPTMap;
public:
static VectorPtr<SceneObject *> sgObjects;
static void sgGetObjects(SceneObject *obj);
};
class sgColorMap
{
public:
U32 sgWidth;
U32 sgHeight;
ColorF *sgData;
sgColorMap(U32 width, U32 height)
{
sgWidth = width;
sgHeight = height;
sgData = new ColorF[(width * height)];
dMemset(sgData, 0, (width * height * sizeof(ColorF)));
}
~sgColorMap() {delete[] sgData;}
void sgFillInLighting();
void sgBlur();
};
/**
* The base class for generating mission level or real-time light maps
* for any sceneObject. All actual work is performed in the descendent
* class' sgLightMap::sgCalculateLighting method.
*/
class sgLightMap
{
protected:
U32 sgWidth;
U32 sgHeight;
/// The light map color buffer.
sgColorMap *sgTexels;
public:
/// The world space position that the texture space coord (0, 0) represents.
Point3D sgWorldPosition;
/// Defines the world space directional change
/// corresponding to a change of (+1, 0) in the light map texture space.
/// Similar to the tangent vector in dot3 bump mapping.
Point3D sgLightMapSVector;
/// Defines the world space directional change
/// corresponding to a change of (0, +1) in the light map texture space.
/// Similar to the binormal vector in dot3 bump mapping.
Point3D sgLightMapTVector;
sgLightMap(U32 width, U32 height)
{
sgWidth = width;
sgHeight = height;
sgWorldPosition.set(0.0f, 0.0f, 0.0f);
sgLightMapSVector.set(0.0f, 0.0f, 0.0f);
sgLightMapTVector.set(0.0f, 0.0f, 0.0f);
sgTexels = new sgColorMap(width, height);
}
~sgLightMap()
{
delete sgTexels;
}
/// Object specific light mapping calculations are done here.
virtual void sgCalculateLighting(LightInfo *light) = 0;
protected:
struct sgStaticMeshInfo
{
ConstructorSimpleMesh *sgStaticMesh;
InteriorInstance *sgInteriorInstance;
};
Vector<SceneObject *> sgIntersectingSceneObjects;
Vector<sgStaticMeshInfo> sgIntersectingStaticMeshObjects;
void sgGetIntersectingObjects(const Box3F &surfacebox, const SceneObject *skipobject);
};
/**
* Used to generate light maps on interiors. This class will
* calculate one surface at a time (using sgPlanarLightMap::sgSurfaceIndex).
*/
class sgPlanarLightMap : public sgLightMap
{
public:
struct sgSmoothingVert
{
Point3F sgVert;
Point3F sgVect;
Point3F sgNorm;
};
struct sgSmoothingTri
{
Point3F sgSDerivative;
Point3F sgTDerivative;
sgSmoothingVert sgVerts[3];
};
struct sgLexel
{
Point2D lmPos;
Point3F worldPos;
Point3F normal;
};
enum sgLightingPass
{
sglpInner = 0,
sglpOuter,
sglpCount
};
struct sgOccluder
{
void *sgObject;
S32 sgSurface;
};
public:
/// Surface to generate light map.
PlaneF surfacePlane;
Vector<sgSmoothingVert> triStrip;
bool sgUseSmoothing;
S32 sgSAxis;
S32 sgTAxis;
Box3F sgSurfaceBox;
Vector<sgLexel> sgInnerLexels;
Vector<sgLexel> sgOuterLexels;
InteriorInstance *sgInteriorInstance;
Interior *sgInteriorDetail;
S32 sgInteriorSurface;
ConstructorSimpleMesh *sgInteriorStaticMesh;
sgPlanarLightMap(U32 width, U32 height, InteriorInstance *interior, Interior *detail,
S32 surface, ConstructorSimpleMesh *staticmesh, PlaneF surfaceplane, const Vector<sgSmoothingVert> &tristrip)
: sgLightMap(width, height)
{
sgDirty = false;
sgUseSmoothing = false;
surfacePlane = surfaceplane;
triStrip.clear();
triStrip.merge(tristrip);
sgSurfaceBox.min.set(F32_MAX, F32_MAX, F32_MAX);
sgSurfaceBox.max.set(-F32_MAX, -F32_MAX, -F32_MAX);
sgInteriorInstance = interior;
sgInteriorDetail = detail;
sgInteriorSurface = surface;
sgInteriorStaticMesh = staticmesh;
}
/// Transfer the light map to a GBitmap and blur.
void sgMergeLighting(GBitmap *lightmap, U32 xoffset, U32 yoffset);
/// See: sgLightMap::sgCalculateLighting.
void sgSetupLighting();
virtual void sgCalculateLighting(LightInfo *light);
bool sgIsDirty() {return sgDirty;}
protected:
bool sgDirty;
static U32 sgCurrentOccluderMaskId;
void sgBuildDerivatives(sgSmoothingTri &tri);
void sgBuildLexels(const Vector<sgSmoothingTri> &tris);
bool sgCastRay(Point3F s, Point3F e, SceneObject *obj, Interior *detail, ConstructorSimpleMesh *sm, sgOccluder &occluderinfo);
bool sgIsValidOccluder(const sgOccluder &occluderinfo, Vector<sgOccluder> &validoccluders, bool isinnerlexel);
};
/**
* Used to generate terrain light maps.
*/
class sgTerrainLightMap : public sgLightMap
{
public:
TerrainBlock *sgTerrain;
sgTerrainLightMap(U32 width, U32 height, TerrainBlock *terrain)
: sgLightMap(width, height)
{
sgTerrain = terrain;
}
void sgMergeLighting(ColorF *lightmap);
/// See: sgLightMap::sgGetBoundingBox.
virtual void sgCalculateLighting(LightInfo *light);
};
#endif//_SGLIGHTMAP_H_

View File

@ -0,0 +1,633 @@
//-----------------------------------------------
// Synapse Gaming - Lighting System
// Copyright <20> Synapse Gaming 2003
// Written by John Kabus
//-----------------------------------------------
#include "lightingSystem/sgLighting.h"
#include "game/fx/particleEngine.h"
#include "console/consoleTypes.h"
#include "core/bitStream.h"
#include "game/gameConnection.h"
#include "sceneGraph/sceneGraph.h"
#include "sim/netConnection.h"
#include "lightingSystem/sgLightObject.h"
#include "lightingSystem/sgLightingModel.h"
extern bool gEditingMission;
extern SceneGraph* gClientSceneGraph;
IMPLEMENT_CO_DATABLOCK_V1(sgLightObjectData);
IMPLEMENT_CO_NETOBJECT_V1(sgLightObject);
sgLightObjectData::sgLightObjectData()
{
sgStatic = false;
sgSpot = false;
sgSpotAngle = 1.0f;
sgAdvancedLightingModel = true;
sgEffectsDTSObjects = true;
sgCastsShadows = true;
sgDiffuseRestrictZone = false;
sgAmbientRestrictZone = false;
sgLocalAmbientAmount = 0.0f;
sgSmoothSpotLight = false;
sgDoubleSidedAmbient = false;
sgLightingModelName = StringTable->insert("");
// needed for TGE...
sgUseNormals = true;
sgMountPoint = 0;
sgMountTransform.identity();
}
void sgLightObjectData::initPersistFields()
{
Parent::initPersistFields();
addField("StaticLight", TypeBool, Offset(sgStatic, sgLightObjectData));
addField("SpotLight", TypeBool, Offset(sgSpot, sgLightObjectData));
addField("SpotAngle", TypeF32, Offset(sgSpotAngle, sgLightObjectData));
addField("AdvancedLightingModel", TypeBool, Offset(sgAdvancedLightingModel, sgLightObjectData));
addField("EffectsDTSObjects", TypeBool, Offset(sgEffectsDTSObjects, sgLightObjectData));
addField("CastsShadows", TypeBool, Offset(sgCastsShadows, sgLightObjectData));
addField("DiffuseRestrictZone", TypeBool, Offset(sgDiffuseRestrictZone, sgLightObjectData));
addField("AmbientRestrictZone", TypeBool, Offset(sgAmbientRestrictZone, sgLightObjectData));
addField("LocalAmbientAmount", TypeF32, Offset(sgLocalAmbientAmount, sgLightObjectData));
addField("SmoothSpotLight", TypeBool, Offset(sgSmoothSpotLight, sgLightObjectData));
addField("DoubleSidedAmbient", TypeBool, Offset(sgDoubleSidedAmbient, sgLightObjectData));
addField("LightingModelName", TypeString, Offset(sgLightingModelName, sgLightObjectData));
addField("UseNormals", TypeBool, Offset(sgUseNormals, sgLightObjectData));
addField("MountPoint", TypeS32, Offset(sgMountPoint, sgLightObjectData));
addField("MountPosition", TypeMatrixPosition, Offset(sgMountTransform, sgLightObjectData));
addField("MountRotation", TypeMatrixRotation, Offset(sgMountTransform, sgLightObjectData));
}
void sgLightObjectData::packData(BitStream *stream)
{
Parent::packData(stream);
stream->write(sgStatic);
stream->write(sgSpot);
stream->write(sgSpotAngle);
stream->write(sgAdvancedLightingModel);
stream->write(sgEffectsDTSObjects);
stream->write(sgCastsShadows);
stream->write(sgDiffuseRestrictZone);
stream->write(sgAmbientRestrictZone);
stream->write(sgLocalAmbientAmount);
stream->write(sgSmoothSpotLight);
stream->write(sgDoubleSidedAmbient);
stream->writeString(sgLightingModelName);
stream->write(sgUseNormals);
stream->write(sgMountPoint);
stream->writeAffineTransform(sgMountTransform);
}
void sgLightObjectData::unpackData(BitStream *stream)
{
Parent::unpackData(stream);
stream->read(&sgStatic);
stream->read(&sgSpot);
stream->read(&sgSpotAngle);
stream->read(&sgAdvancedLightingModel);
stream->read(&sgEffectsDTSObjects);
stream->read(&sgCastsShadows);
stream->read(&sgDiffuseRestrictZone);
stream->read(&sgAmbientRestrictZone);
stream->read(&sgLocalAmbientAmount);
stream->read(&sgSmoothSpotLight);
stream->read(&sgDoubleSidedAmbient);
sgLightingModelName = StringTable->insert(stream->readSTString());
stream->read(&sgUseNormals);
stream->read(&sgMountPoint);
stream->readAffineTransform(&sgMountTransform);
}
//----------------------------------------------
bool sgLightObject::onAdd()
{
Parent::onAdd();
//resend data...
setMaskBits(0xffffffff);
return true;
}
/*void sgLightObject::onDeleteNotify(SimObject *object)
{
Parent::onDeleteNotify(object);
if(object == sgParticleEmitter)
{
sgParticleEmitter = NULL;
sgParticleEmitterGhostIndex = -1;
}
}*/
void sgLightObject::sgCalculateParticleSystemInfo(NetConnection *con)
{
sgValidParticleEmitter = false;
ParticleEmitterNode *node = NULL;
if(sgParticleEmitterName != StringTable->insert(""))
{
node = dynamic_cast<ParticleEmitterNode *>(Sim::findObject(sgParticleEmitterName));
}
else
{
sgParticleEmitterGhostIndex = -1;
}
if(node)
{
// ok we have a valid object...
sgValidParticleEmitter = true;
if(con)
{
// try for the id...
S32 id = con->getGhostIndex(node);
if(id > -1)
sgParticleEmitterGhostIndex = id;
else
{
// this object is key, scope it even if I can't see it...
node->setScopeAlways();
}
}
}
sgAttachedObjectGhostIndex = -1;
if(!sgAttachedObjectPtr.isNull())
{
// try for the id...
S32 id = con->getGhostIndex(sgAttachedObjectPtr);
if(id > -1)
sgAttachedObjectGhostIndex = id;
else
{
// this object is key, scope it even if I can't see it...
// this is bad news for player objects!!!
// don't add back in...
//sgAttachedObjectPtr->setScopeAlways();
}
}
}
bool sgLightObject::onNewDataBlock(GameBaseData *dptr)
{
mDataBlock = dynamic_cast<sgLightObjectData*>(dptr);
if(!mDataBlock || !Parent::onNewDataBlock(dptr))
return false;
return true;
}
void sgLightObject::initPersistFields()
{
Parent::initPersistFields();
addField("ParticleColorAttenuation", TypeF32, Offset(sgParticleColorAttenuation, sgLightObject));
addField("ParticleEmitterName", TypeString, Offset(sgParticleEmitterName, sgLightObject));
}
void sgLightObject::inspectPostApply()
{
Parent::inspectPostApply();
setMaskBits(0xffffffff);
}
void sgLightObject::processTick(const Move* move)
{
Parent::processTick(move);
if(isServerObject() && sgValidParticleEmitter && (sgParticleEmitterGhostIndex == -1))
{
// get the object...
ParticleEmitterNode *node = dynamic_cast<ParticleEmitterNode *>(Sim::findObject(sgParticleEmitterName));
if(node)
{
setMaskBits(sgParticleSystemMask);
}
}
// alright lets fix attachObject...
if(isServerObject() && !sgAttachedObjectPtr.isNull() && (sgAttachedObjectGhostIndex == -1))
{
// no? keep trying...
setMaskBits(sgAttachedObjectMask);
}
}
void sgLightObject::calculateLightPosition()
{
if(sgAttachedObjectGhostIndex == -1)
return;
if(sgAttachedObjectPtr.isNull())
{
// try to find the attached object...
NetConnection *connection = NetConnection::getConnectionToServer();
AssertFatal((connection), "Invalid net connection.");
SimObject *sim = connection->resolveGhost(sgAttachedObjectGhostIndex);
sgAttachedObjectPtr = dynamic_cast<GameBase *>(sim);
if(sgAttachedObjectPtr.isNull())
return;
}
GameBase *obj = sgAttachedObjectPtr;
ShapeBase *shape = dynamic_cast<ShapeBase *>(obj);
if(shape)
{
MatrixF mat;
// this doesn't work well, the object transform
// is updated less frequently than the render
// transform, but luckily they're the same...
//shape->getMountTransform(sgMountPoint, &mat);
// use this instead!!!
shape->getRenderMountTransform(mountPoint, &mat);
mat.mul(mountTransform);
mAnimationPosition = mat.getPosition();
setTransform(mat);
}
else
{
// Yes, so set to attached position.
mAnimationPosition = obj->getPosition();
// Set Current Position.
setPosition(mAnimationPosition);
}
}
U32 sgLightObject::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
{
U32 res = Parent::packUpdate(con, mask, stream);
if(stream->writeFlag(mask & fxLightConfigChangeMask))
stream->write(sgParticleColorAttenuation);
if(stream->writeFlag(mask & sgParticleSystemMask))
{
if(isServerObject())
{
sgCalculateParticleSystemInfo(con);
if(sgParticleEmitterGhostIndex > -1)
{
// transmit the id...
stream->writeFlag(true);
stream->writeInt(sgParticleEmitterGhostIndex, NetConnection::GhostIdBitSize);
}
else
{
stream->writeFlag(false);
}
}
else
{
//for demo recording!!!
//this is called on the client during recording
//and the server should've already provided the ghostid...
stream->writeFlag(true);
stream->writeInt(sgParticleEmitterGhostIndex, NetConnection::GhostIdBitSize);
}
}
if(stream->writeFlag(mask & sgAttachedObjectMask))
{
if(isServerObject())
{
sgCalculateParticleSystemInfo(con);
if(sgAttachedObjectGhostIndex > -1)
{
// transmit the id...
stream->writeFlag(true);
stream->writeInt(sgAttachedObjectGhostIndex, NetConnection::GhostIdBitSize);
}
else
{
stream->writeFlag(false);
}
}
else
{
//for demo recording!!!
//this is called on the client during recording
//and the server should've already provided the ghostid...
stream->writeFlag(true);
stream->writeInt(sgAttachedObjectGhostIndex, NetConnection::GhostIdBitSize);
}
}
return res;
}
void sgLightObject::unpackUpdate(NetConnection *con, BitStream *stream)
{
Parent::unpackUpdate(con, stream);
if(stream->readFlag())
stream->read(&sgParticleColorAttenuation);
if(stream->readFlag())
{
if(stream->readFlag())
sgParticleEmitterGhostIndex = stream->readInt(NetConnection::GhostIdBitSize);
else
sgParticleEmitterGhostIndex = -1;
}
if(stream->readFlag())
{
if(stream->readFlag())
{
sgAttachedObjectGhostIndex = stream->readInt(NetConnection::GhostIdBitSize);
mAttached = true;
}
else
{
sgAttachedObjectGhostIndex = -1;
sgAttachedObjectPtr = NULL;
mAttached = false;
}
}
}
void sgLightObject::setTransform(const MatrixF & mat)
{
Parent::setTransform(mat);
sgMainZone = -1;
}
void sgLightObject::registerLights(LightManager *lightManager, bool lightingScene)
{
sgAnimateState state;
if(!mEnable || !mDataBlock) return;
// copy and disable animation state...
if(lightingScene)
{
state.sgCopyState(mDataBlock);
state.sgDisableState(mDataBlock);
}
// set mount info...
mountPoint = mDataBlock->sgMountPoint;
mountTransform = mDataBlock->sgMountTransform;
// get color etc...
AnimateLight();
// restore animation state...
if(lightingScene)
state.sgRestoreState(mDataBlock);
bool res = (mDataBlock->mLightOn) &&
((mDataBlock->sgStatic && (mDataBlock->sgEffectsDTSObjects || lightingScene)) ||
(((!mDataBlock->sgStatic) && (!lightingScene))));
if(!res)
return;
mLight.mPos = mAnimationPosition;
mLight.mColor = mAnimationColour;
mLight.mAmbient.set(0.0f, 0.0f, 0.0f);
mLight.mRadius = mAnimationRadius;
mLight.sgCastsShadows = mDataBlock->sgCastsShadows;
mLight.sgDiffuseRestrictZone = mDataBlock->sgDiffuseRestrictZone;
mLight.sgAmbientRestrictZone = mDataBlock->sgAmbientRestrictZone;
mLight.sgLocalAmbientAmount = mDataBlock->sgLocalAmbientAmount;
mLight.sgSmoothSpotLight = mDataBlock->sgSmoothSpotLight;
mLight.sgDoubleSidedAmbient = mDataBlock->sgDoubleSidedAmbient;
mLight.sgAssignedToParticleSystem = false;
mLight.sgUseNormals = mDataBlock->sgUseNormals;
mLight.sgTrackMoveSnapshot = true;
mLight.sgLightingTransform = getTransform();
mLight.sgLightingTransform.setPosition(Point3F(0.0f, 0.0f, 0.0f));
//mLight.sgLightingTransform.inverse();
if(mDataBlock->sgLightingModelName && (dStrlen(mDataBlock->sgLightingModelName) > 0))
mLight.sgLightingModelName = mDataBlock->sgLightingModelName;
else
{
// Lighting Pack 1.3 compatibility...
if(mDataBlock->sgAdvancedLightingModel)
mLight.sgLightingModelName = sgLightingModelManager::sgGetAdvancedLightingModelName();
else
mLight.sgLightingModelName = sgLightingModelManager::sgGetStockLightingModelName();
}
// this is heavy, but updates are rare on statics...
if((sgMainZone == -1) && isClientObject())
{
U32 zone = 0;
SceneObject *obj;
gClientSceneGraph->findZone(getPosition(), obj, zone);
sgMainZone = zone;
// track movement...
mLight.sgMoveSnapshotId++;
}
mLight.sgZone[0] = sgMainZone;
mLight.sgZone[1] = -1;
for(U32 i=0; i<getNumCurrZones(); i++)
{
S32 zone = getCurrZone(i);
if(zone != sgMainZone)
{
mLight.sgZone[1] = zone;
break;
}
}
if(sgParticleEmitterGhostIndex > -1)
{
if(sgParticleEmitterPtr.isNull())
{
// try to find the particle emitter...
NetConnection *connection = NetConnection::getConnectionToServer();
AssertFatal((connection), "Invalid net connection.");
SimObject *obj = connection->resolveGhost(sgParticleEmitterGhostIndex);
ParticleEmitterNode *node = dynamic_cast<ParticleEmitterNode *>(obj);
if(node)
sgParticleEmitterPtr = node->getParticleEmitter();
if(!sgParticleEmitterPtr.isNull())
{
mLight.mColor = sgParticleEmitterPtr->getCollectiveColor() * sgParticleColorAttenuation;
mLight.sgAssignedToParticleSystem = true;
}
}
else
{
mLight.mColor = sgParticleEmitterPtr->getCollectiveColor() * sgParticleColorAttenuation;
mLight.mColor.clamp();
mLight.sgAssignedToParticleSystem = true;
}
//if(mLight.mColor.red == 0.0f && mLight.mColor.green == 0.0f && mLight.mColor.blue == 0.0f)
// mLight.mColor = mLight.mColor;
// Con::printf("%f %f %f %f", mLight.mColor.red, mLight.mColor.green, mLight.mColor.blue, mLight.mColor.alpha);
}
// do after finding the particle color...
LightManager::sgGetFilteredLightColor(mLight.mColor, mLight.mAmbient, sgMainZone);
if((mLight.mColor.red == 0.0f) && (mLight.mColor.green == 0.0f) &&
(mLight.mColor.blue == 0.0f))
return;
if(mDataBlock->sgStatic)
{
if(mDataBlock->sgSpot)
{
Point3F origin(0.0f, 0.0f, 0.0f);
mObjToWorld.mulP(origin);
mLight.mDirection = SG_STATIC_SPOT_VECTOR_NORMALIZED;
mObjToWorld.mulP(mLight.mDirection);
mLight.mDirection = origin - mLight.mDirection;
mLight.mType = LightInfo::SGStaticSpot;
mLight.sgSpotAngle = mDataBlock->sgSpotAngle;
mLight.sgSpotPlane = PlaneF(mLight.mPos, -mLight.mDirection);
}
else
mLight.mType = LightInfo::SGStaticPoint;
}
else
{
if(mDataBlock->sgSpot)
{
Point3F origin(0.0f, 0.0f, 0.0f);
mObjToWorld.mulP(origin);
mLight.mDirection = SG_STATIC_SPOT_VECTOR_NORMALIZED;
mObjToWorld.mulP(mLight.mDirection);
mLight.mDirection = origin - mLight.mDirection;
mLight.mType = LightInfo::Spot;
mLight.sgSpotAngle = mDataBlock->sgSpotAngle;
mLight.sgSpotPlane = PlaneF(mLight.mPos, -mLight.mDirection);
}
else
mLight.mType = LightInfo::Point;
}
lightManager->sgRegisterGlobalLight(&mLight);
}
void sgLightObject::renderObject(SceneState *state, SceneRenderImage *image)
{
// render the fxLight?
if(mDataBlock->mFlareOn || gEditingMission)
Parent::renderObject(state, image);
if(!mDataBlock->sgSpot)
return;
if(gEditingMission)
{
// render the spotlight cone...
glBlendFunc(GL_ONE,GL_ZERO);
glEnable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
Point3F vector = SG_STATIC_SPOT_VECTOR_NORMALIZED * mDataBlock->mRadius;
Point3F origin(0.0f, 0.0f, 0.0f);
Point3F point = vector;
mObjToWorld.mulP(origin);
mObjToWorld.mulP(point);
glColor3f(0.0f, 1.0f, 0.0f);
glBegin(GL_LINES);
glVertex3fv(origin);
glVertex3fv(point);
glEnd();
S32 i;
F32 halfangle = mDegToRad(mDataBlock->sgSpotAngle) * 0.5f;
F32 zamount = mCos(halfangle) * vector.z;
F32 otheramount = mSin(halfangle) * vector.z;
for(i=0; i<4; i++)
{
U32 nonzcomponent = (i & 0x1);
Point3F outerpoint = vector;
outerpoint[2] = zamount;
outerpoint[(int)nonzcomponent] = otheramount;
if(i & 2)
outerpoint[(int)nonzcomponent] *= -1.0f;
mObjToWorld.mulP(outerpoint);
glColor3f(1.0f, 1.0f, 0.0f);
glBegin(GL_LINES);
glVertex3fv(origin);
glVertex3fv(outerpoint);
glEnd();
}
}
}
void sgLightObject::attachToObject(GameBase *obj)
{
if(isServerObject())
{
processAfter(obj);
sgAttachedObjectPtr = obj;
setMaskBits(sgAttachedObjectMask);
}
}
void sgLightObject::detachFromObject()
{
if(isServerObject())
{
clearProcessAfter();
sgAttachedObjectPtr = NULL;
setMaskBits(sgAttachedObjectMask);
}
}
ConsoleMethod(sgLightObject, attachToObject, void, 3, 3, "(SimObject obj) Attach to the SimObject obj.")
{
GameBase *obj = dynamic_cast<GameBase*>(Sim::findObject(argv[2]));
if(obj)
object->attachToObject(obj);
}
ConsoleMethod(sgLightObject, detachFromObject, void, 2, 2, "() Detach from the object previously set by attachToObject.")
{
object->detachFromObject();
}
//-----------------------------------------------
//-----------------------------------------------
/* Support for Torque Lighting Kit object types.
*
* Some objects types were renamed, these definitions
* allow porting of existing objects and data.
*/
class sgUniversalStaticLightData : public sgLightObjectData
{
typedef sgLightObjectData Parent;
public:
DECLARE_CONOBJECT(sgUniversalStaticLightData);
};
class sgUniversalStaticLight : public sgLightObject
{
typedef sgLightObject Parent;
public:
DECLARE_CONOBJECT(sgUniversalStaticLight);
};
IMPLEMENT_CO_DATABLOCK_V1(sgUniversalStaticLightData);
IMPLEMENT_CO_NETOBJECT_V1(sgUniversalStaticLight);

View File

@ -0,0 +1,166 @@
//-----------------------------------------------
// Synapse Gaming - Lighting System
// Copyright <20> Synapse Gaming 2003
// Written by John Kabus
//-----------------------------------------------
#ifndef _SGUNIVERSALSTATICLIGHT_H_
#define _SGUNIVERSALSTATICLIGHT_H_
#include "game/fx/fxLight.h"
#include "game/fx/particleEmitter.h"
//#include "game/fx/particleEmitterNode.h"
/**
* The datablock class for sgUniversalStaticLight.
*/
class sgLightObjectData : public fxLightData
{
typedef fxLightData Parent;
public:
/// Enables static lighting (baked into light maps)
/// instead of Torque's default dynamic lighting.
bool sgStatic;
/// Turns this light into a spotlight (only works with static lights).
bool sgSpot;
/// The spotlight spread angle.
F32 sgSpotAngle;
/// Selects the lighting model.
/// The default lighting model uses (rad^2 / dist^2)
/// and creates a distinct drop off.
/// The advanced lighting model uses (1 - (dist^2 / rad^2))
/// and creates gradual / global illumination feel (does not perform radiosity).
bool sgAdvancedLightingModel;
/// Allows this light to illuminate dts objects.
bool sgEffectsDTSObjects;
bool sgCastsShadows;
bool sgDiffuseRestrictZone;
bool sgAmbientRestrictZone;
F32 sgLocalAmbientAmount;
bool sgSmoothSpotLight;
bool sgDoubleSidedAmbient;
StringTableEntry sgLightingModelName;
bool sgUseNormals;
U32 sgMountPoint;
MatrixF sgMountTransform;
sgLightObjectData();
static void initPersistFields();
virtual void packData(BitStream *stream);
virtual void unpackData(BitStream *stream);
DECLARE_CONOBJECT(sgLightObjectData);
};
/**
* This class extends fxLight to provide mission level
* static light objects. These light objects can also
* be used as dynamic lights and linked to mission level
* particle emitters for coordinated particle system
* light sources (flickering,...).
*/
class sgLightObject : public fxLight
{
typedef fxLight Parent;
sgLightObjectData *mDataBlock;
/// The particle emitter's ghost id is used to sync up the client and server.
bool sgValidParticleEmitter;
S32 sgParticleEmitterGhostIndex;
S32 sgAttachedObjectGhostIndex;
/// The resolved (from the ghost id) particle emitter.
SimObjectPtr<ParticleEmitter> sgParticleEmitterPtr;
SimObjectPtr<GameBase> sgAttachedObjectPtr;
S32 sgMainZone;
class sgAnimateState
{
bool mUseColour;
bool mUseBrightness;
bool mUseRadius;
bool mUseOffsets;
bool mUseRotation;
public:
sgAnimateState()
{
mUseColour = false;
mUseBrightness = false;
mUseRadius = false;
mUseOffsets = false;
mUseRotation = false;
}
void sgCopyState(sgLightObjectData *light)
{
mUseColour = light->mUseColour;
mUseBrightness = light->mUseBrightness;
mUseRadius = light->mUseRadius;
mUseOffsets = light->mUseOffsets;
mUseRotation = light->mUseRotation;
}
void sgRestoreState(sgLightObjectData *light)
{
light->mUseColour = mUseColour;
light->mUseBrightness = mUseBrightness;
light->mUseRadius = mUseRadius;
light->mUseOffsets = mUseOffsets;
light->mUseRotation = mUseRotation;
}
void sgDisableState(sgLightObjectData *light)
{
light->mUseColour = false;
light->mUseBrightness = false;
light->mUseRadius = false;
light->mUseOffsets = false;
light->mUseRotation = false;
}
};
public:
enum {
sgLastfxLightMask = fxLightAttachChange,
sgParticleSystemMask = sgLastfxLightMask << 1,
sgAttachedObjectMask = sgLastfxLightMask << 2
};
LightInfo mLight;
/// Used to attenuate the color received from the particle emitter.
F32 sgParticleColorAttenuation;
/// The particle emitter name field.
/// This is the unique mission name of the particle emitter.
StringTableEntry sgParticleEmitterName;
sgLightObject()
{
sgParticleEmitterName = StringTable->insert("");
sgParticleEmitterGhostIndex = -1;
sgAttachedObjectGhostIndex = -1;
sgParticleColorAttenuation = 1.0f;
sgParticleEmitterPtr = NULL;
sgAttachedObjectPtr = NULL;
sgValidParticleEmitter = false;
}
void attachToObject(GameBase *obj);
void detachFromObject();
bool onAdd();
bool onNewDataBlock(GameBaseData *dptr);
void processTick(const Move* move);
virtual void calculateLightPosition();
virtual SceneObject *getAttachedObject() {return sgAttachedObjectPtr;}
void renderObject(SceneState* state, SceneRenderImage*);
virtual void setTransform(const MatrixF & mat);
void registerLights(LightManager *lightManager, bool lightingScene);
static void initPersistFields();
virtual void inspectPostApply();
U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream);
void unpackUpdate(NetConnection *con, BitStream *stream);
/// Tries to turn sgParticleEmitterName into sgParticleEmitterGhostIndex.
void sgCalculateParticleSystemInfo(NetConnection *con);
DECLARE_CONOBJECT(sgLightObject);
};
#endif//_SGUNIVERSALSTATICLIGHT_H_

View File

@ -0,0 +1,99 @@
//-----------------------------------------------
// Synapse Gaming - Lighting System
// Copyright <20> Synapse Gaming 2003
// Written by John Kabus
//-----------------------------------------------
#ifndef _SGLIGHTING_H_
#define _SGLIGHTING_H_
//----------------------------------------------
// lighting preferences...
// comment out line to disable option...
/// harsh or blurred lighting...
#define SG_STATIC_LIGHT_SHADOWS_BLUR
/// avoid washed out dynamic lighting...
#define SG_ADVANCED_INTERIOR_LIGHTING
/// detail maps on interiors...
#define SG_INTERIOR_DETAILMAPPING
/// enable advanced lighting options
#define SG_ADVANCED_DYNAMIC_SHADOWS
#define SG_ADVANCED_DTS_DYNAMIC_LIGHTING
#define SG_ADVANCED_PARTICLE_LIGHTING
#define SG_OVEREXPOSED_SELFILLUMINATION
/// tune advanced lighting options
#define SG_PARTICLESYSTEMLIGHT_FIXED_INTENSITY 0.5f
#define SG_DYNAMIC_SHADOW_INTENSITY 0.5
#define SG_DYNAMIC_SHADOW_STEPS 5.0f
#define SG_DYNAMIC_SHADOW_TIME 20
//----------------------------------------------
// lightmap hint defaults...
// these are NOT used by every implementation of
// the lightmap subclasses...
// these are self-explanatory...
// all used by sgPlanarLightMap...
// SG_CALCULATE_SHADOWS also used by sgTerrainLightMap...
#define SG_CHOOSE_SPEED_OVER_QUALITY false
#define SG_SELF_SHADOWING true
#define SG_CALCULATE_SHADOWS true
#define SG_MIN_LEXEL_INTENSITY 0.0039215f
#define SG_MIN_LEXEL_INTENSITY_SPEED_OVER_QUALITY 0.1f
#define SG_NULL_SURFACE -2
//----------------------------------------------
// don't touch...
#define SG_STATIC_SPOT_VECTOR_NORMALIZED Point3F(0, 0, 1)
//----------------------------------------------
// vibrant lighting amounts...
/// how much glare do we want (must be 1.0, 2.0, or 4.0)...
#define SG_LIGHTING_OVERBRIGHT_AMOUNT 2.0
// do not change...
/// this value resets Torque to a normal lighting value...
#define SG_LIGHTING_NORMAL_AMOUNT 1.0
//----------------------------------------------
// static object 'tailored' lighting...
/// these define the number of universal static
/// lights that can be manually assigned to a static...
#define SG_TSSTATIC_MAX_LIGHT_SHIFT 3
#define SG_TSSTATIC_MAX_LIGHTS ((1 << SG_TSSTATIC_MAX_LIGHT_SHIFT) - 1)
//----------------------------------------------
// prioritized dts lighting
/// these values change the priority of the light objects...
#define SG_LIGHTMANAGER_SUN_PRIORITY 6.0f
#define SG_LIGHTMANAGER_DYNAMIC_PRIORITY 1.0f
#define SG_LIGHTMANAGER_STATIC_PRIORITY 4.0f
#define SG_LIGHTMANAGER_ASSIGNED_PRIORITY 6.0f
//----------------------------------------------
// version info
#define SG_LIGHTINGPACK_CORE_VERSION "2.1"
#define SG_TGE_VERSION "1.0"
#define SG_LIGHTINGPACK_SUB_VERSION "5.1"
#define SG_LIGHTINGPACK_SHOW_ALL_INFORMATION true
char *sgGetLightingPackInformation(bool fullinfo=false);
#endif//_SGLIGHTING_H_

View File

@ -0,0 +1,615 @@
//-----------------------------------------------
// Synapse Gaming - Lighting System
// Copyright <20> Synapse Gaming 2003
// Written by John Kabus
//-----------------------------------------------
#include "dgl/dgl.h"
#include "lightingSystem/sgLighting.h"
#include "lightingSystem/sgLightingModel.h"
#include "lightingSystem/sgLightManager.h"
#include "platform/profiler.h"
//#define SG_TEST_LIGHTING_TEXTURE
#define SG_LIGHTING_MIN_CUTOFF 0.00392f
#define SG_DYNAMIC_LIGHTING_TEXTURE_SIZE 16
#define SG_DYNAMIC_LIGHTING_TEXTURE_HALFSIZE F32(SG_DYNAMIC_LIGHTING_TEXTURE_SIZE / 2)
Vector<sgLightingModel *> sgLightingModelManager::sgLightingModels;
sgLightingModelStock sgLightingModelManager::sgDefaultModel;
sgLightingModelAdvanced sgLightingModelManager::sgAdvancedModel;
sgLightingModelInverseSquare sgLightingModelManager::sgInverseSquare;
sgLightingModelInverseSquareFastFalloff sgLightingModelManager::sgInverseSquareFastFalloff;
sgLightingModelNearLinear sgLightingModelManager::sgNearLinear;
sgLightingModelNearLinearFastFalloff sgLightingModelManager::sgNearLinearFastFalloff;
sgLightingModel *sgLightingModelManager::sgSunlightModel = &sgLightingModelManager::sgAdvancedModel;
#ifdef SG_TEST_LIGHTING_TEXTURE
GFXTexHandle sgTestLightingTexture;
#endif
ConsoleFunction(sgLightingModelCount, S32, 1, 1, "Get the number of Lighting Pack Lighting Models.")
{
return sgLightingModelManager::sgGetLightingModelCount();
}
ConsoleFunction(sgLightingModelName, const char *, 2, 2, "Get the name of the Lighting Pack Lighting Model.")
{
U32 index;
index = dAtoi(argv[1]);
return sgLightingModelManager::sgGetLightingModelName(index);
}
//-----------------------------------------------
//-----------------------------------------------
sgLightingModel::sgLightingModel()
{
sgStateSet = false;
sgStateInitLM = false;
sgLight = NULL;
sgLightingModelName[0] = 0;
sgLightingModelManager::sgRegisterLightingModel(this);
}
//-----------------------------------------------
//-----------------------------------------------
// only for TSE's consistent lighting models...
// TGE's vertex lighting requires the base
// class method sgLightingModelGLBase::sgScoreLight...
/*
F32 sgLightingModelAdvanced::sgScoreLight(LightInfo *light, const SphereF &sphere)
{
sgLightingModel::sgScoreLight(light, sphere);
F32 radsq = (light->mRadius * light->mRadius);
if(radsq <= 0.0f)
return 0.0f;
VectorF dist = light->mPos - sphere.center;
F32 distsq = dist.lenSquared();
return getMax((1 - (distsq / radsq)), 0.0f);
}
*/
bool sgLightingModelAdvanced::sgCanIlluminate(const Box3F &box)
{
AssertFatal((sgStateSet == true), "sgLightingModel: State not properly set.");
// can we skip the hard stuff?
if((sgLight->mType == LightInfo::Vector) || (sgLight->mType == LightInfo::Ambient))
return true;
// get the min dist...
Point3F pos = box.getClosestPoint(sgLight->mPos);
Point3F nor = sgLight->mPos - pos;
F32 distsq = mDot(nor, nor);
bool res = (distsq < (sgLight->mRadius * sgLight->mRadius));
return res;
}
void sgLightingModelAdvanced::sgSetState(LightInfo *light)
{
sgLightingModelGLBase::sgSetState(light);
if(sgLight->mRadius > 0.0f)
sgLinearAttenuation = (6.0f / sgLight->mRadius);
else
sgLinearAttenuation = 0.0f;
}
void sgLightingModelAdvanced::sgInitStateLM()
{
sgLightingModelGLBase::sgInitStateLM();
maxlightdistancesquared = sgLight->mRadius * sgLight->mRadius;
}
void sgLightingModelAdvanced::sgLightingLM(const Point3F &point, VectorF normal, ColorF &diffuse, ColorF &ambient, Point3F &lightingnormal)
{
// do not call sgLightingModelGLBase::sgLightingLM!!!
// we're overriding the method!!!
sgLightingModel::sgLightingLM(point, normal, diffuse, ambient, lightingnormal);
Point3F lightvector;
F32 distsquared;
F32 spotlightingangle;
// do this in lightmap...
//diffuse = ColorF(0.0, 0.0, 0.0);
//ambient = ColorF(0.0, 0.0, 0.0);
//lightingnormal = Point3F(0.0, 0.0, 0.0);
if(sgLight->mType != LightInfo::Vector)
{
// get the distance squared from the light to the
// light map texel world space coord.
lightvector = sgLight->mPos - point;
distsquared = lightvector.lenSquared();
if(distsquared >= maxlightdistancesquared)
return;
}
else
{
// directional lighting is always close enough
// just setup the needed variables...
lightvector = sgLight->mDirection * -1.0f;
}
// step two: find the spotlight amount...
// vector lights are already normallized...
if(sgLight->mType != LightInfo::Vector)
lightvector.normalize();
lightingnormal = lightvector;
// is it a spotlight? is it pointing this way?
if(sgLight->mType == LightInfo::SGStaticSpot)
{
spotlightingangle = mDot(lightvector, sgLight->mDirection);
if(spotlightingangle < spotanglecos)
return;
}
else
spotlightingangle = 1.0f;
// get the lighting angle amount...
// values coming from terrain are not normalized...
normal.normalize();
F32 angleamount = mDot(lightvector, normal);
F32 lightamount = 1.0f;
if(sgLight->sgUseNormals)
lightamount *= angleamount;
F32 lightfalloff = 1.0f;
lightamount = getMax(getMin(lightamount, 1.0f), 0.0f);
if(sgLight->mType != LightInfo::Vector)
{
// apply one of the point light lighting models...
lightfalloff = getMax((1 - (distsquared / maxlightdistancesquared)), 0.0f);
if(sgLight->mType == LightInfo::SGStaticSpot)
{
// apply the spotlight lighting model...
spotlightingangle = mClampF(((spotlightingangle - spotamountouter) / spotamountinner), 0.0f, 1.0f);
if(sgLight->sgSmoothSpotLight)
spotlightingangle *= getMin((spotlightingangle * 1.2f), 1.0f);
lightfalloff *= spotlightingangle;
}
lightamount *= lightfalloff;
}
lightamount *= (1.0f - sgLight->sgLocalAmbientAmount);
lightamount = getMax(getMin(lightamount, 1.0f), 0.0f);
diffuse = sgLight->mColor * lightamount;
if(sgLight->sgDoubleSidedAmbient || (angleamount > 0.0f))
{
lightfalloff *= sgLight->sgLocalAmbientAmount;
lightfalloff = getMax(getMin(lightfalloff, 1.0f), 0.0f);
ambient = sgLight->mColor * lightfalloff;
}
}
//-----------------------------------------------
//-----------------------------------------------
F32 sgLightingModelGLBase::sgScoreLight(LightInfo *light, const SphereF &sphere)
{
sgLightingModel::sgScoreLight(light, sphere);
if((sgLight->mType == LightInfo::Vector) || (sgLight->mType == LightInfo::Ambient))
return 0.5f;
VectorF vect = light->mPos - sphere.center;
F32 distsq = vect.lenSquared();
F32 dist = 0.0f;
if(sgLinearAttenuation > 0.0f)
{
dist = mSqrt(distsq);
}
F32 amount = (sgConstantAttenuation + (sgLinearAttenuation * dist) + (sgQuadraticAttenuation * distsq));
amount = getMax(amount, 0.000001f);
if(amount != 0.0f)
amount = 1.0f / amount;
amount = getMax(amount, 0.0f);
return amount;
}
bool sgLightingModelGLBase::sgCanIlluminate(const Box3F &box)
{
AssertFatal((sgStateSet == true), "sgLightingModel: State not properly set.");
// can we skip the hard stuff?
if((sgLight->mType == LightInfo::Vector) || (sgLight->mType == LightInfo::Ambient))
return true;
// get the min dist...
Point3F pos = box.getClosestPoint(sgLight->mPos);
Point3F nor = sgLight->mPos - pos;
F32 distsq = mDot(nor, nor);
F32 intensity = 0.0f;
if(distsq > 0.0f)
{
// run the basic lighting equation...
intensity = sgConstantAttenuation;
intensity += (sgQuadraticAttenuation * distsq);
if(sgLinearAttenuation > 0.0f)
intensity += (sgLinearAttenuation * mSqrt(distsq));
}
else
{
intensity = 1.0f;
}
// this seems fine...
if(intensity <= 0.0f)
return false;
intensity = 1.0f / intensity;
ColorF col = sgLight->mColor * intensity;
if((col.red < SG_MIN_LEXEL_INTENSITY) && (col.green < SG_MIN_LEXEL_INTENSITY) &&
(col.blue < SG_MIN_LEXEL_INTENSITY))
return false;
return true;
}
F32 sgLightingModelGLBase::sgGetMaxRadius(bool speedoverquality, bool glstyle)
{
AssertFatal((sgStateSet == true), "sgLightingModel: State not properly set.");
if((sgLight->mType == LightInfo::Vector) || (sgLight->mType == LightInfo::Ambient))
return 1000000.0f;
// get started...
// don't use F32_MAX, this value will be added to stuff...
const F32 infinity = 1.0e+6F;
F32 adjustedvalue;
if(speedoverquality)
adjustedvalue = (1.0f / SG_MIN_LEXEL_INTENSITY_SPEED_OVER_QUALITY) - sgConstantAttenuation;
else
adjustedvalue = (1.0f / SG_MIN_LEXEL_INTENSITY) - sgConstantAttenuation;
// early out?
if(adjustedvalue <= 0.0f)
return 0.0f;
// this is the default even when L and Q are both populated...
if(sgLinearAttenuation > 0.0f)
return adjustedvalue / sgLinearAttenuation;
if(sgQuadraticAttenuation > 0.0f)
return mSqrt(adjustedvalue / sgQuadraticAttenuation);
if(sgConstantAttenuation > 0.0f)
return infinity;
return 0.0f;
}
void sgLightingModelGLBase::sgSetState(LightInfo *light)
{
sgLightingModel::sgSetState(light);
sgConstantAttenuation = 0.0f;
sgLinearAttenuation = 0.0f;
sgQuadraticAttenuation = 0.0f;
sgLightParamDiffuse = Point4F(light->mColor.red * light->sgDTSLightingOcclusionAdjust,
light->mColor.green * light->sgDTSLightingOcclusionAdjust,
light->mColor.blue * light->sgDTSLightingOcclusionAdjust,
1.0f);
sgLightParamAmbient = Point4F(light->mAmbient.red, light->mAmbient.green, light->mAmbient.blue, 1.0f);
sgLightParamPosition = Point4F(light->mPos.x, light->mPos.y, light->mPos.z, 1.0f);
sgLightParamDirection = Point4F(-light->mDirection.x, -light->mDirection.y, -light->mDirection.z, 0.0f);
}
void sgLightingModelGLBase::sgLightingGL(S32 gllight)
{
sgLightingModel::sgLightingGL(gllight);
const GLfloat black[] = {0.0f, 0.0f, 0.0f, 0.0f};
if((sgLight->mType == LightInfo::Vector) || (sgLight->mType == LightInfo::Ambient))
{
F32 ambientFactor = (sgLightParamAmbient[0] + sgLightParamAmbient[1] + sgLightParamAmbient[2]) / 3.0f;
F32 factor = mClampF(1.0f - ambientFactor, 0.f, 1.f);
// attenuate (for in shadow...)
sgLightParamDiffuse.x *= factor;
sgLightParamDiffuse.y *= factor;
sgLightParamDiffuse.z *= factor;
glLightfv(gllight, GL_POSITION, (const GLfloat*)&sgLightParamDirection.x);
// do not add this back in!!!
// the DX wrapper is a bastard!!!
//glLightfv(gllight, GL_SPOT_DIRECTION, (const GLfloat*)black);
glLightfv(gllight, GL_DIFFUSE, (const GLfloat*)&sgLightParamDiffuse.x);
glLightfv(gllight, GL_AMBIENT, (const GLfloat*)&sgLightParamAmbient.x);
glLightfv(gllight, GL_SPECULAR, (const GLfloat*)black);
LightManager::sgSetAmbientSelfIllumination(sgLight, &sgLightParamDiffuse.x, &sgLightParamAmbient.x);
glLightf(gllight, GL_SPOT_CUTOFF, 180.f);
glLightf(gllight, GL_CONSTANT_ATTENUATION, 0.0f);
glLightf(gllight, GL_QUADRATIC_ATTENUATION, 0.0f);
glLightf(gllight, GL_LINEAR_ATTENUATION, 1.0f);
}
else
{
glLightfv(gllight, GL_POSITION, (const GLfloat*)&sgLightParamPosition.x);
// must be here and only set spots!!!
// the DX wrapper is a bastard!!!
if((sgLight->mType == LightInfo::SGStaticSpot) || (sgLight->mType == LightInfo::Spot))
glLightfv(gllight, GL_SPOT_DIRECTION, (const GLfloat*)&sgLightParamDirection.x);
glLightfv(gllight, GL_DIFFUSE, (const GLfloat*)&sgLightParamDiffuse.x);
glLightfv(gllight, GL_AMBIENT, (const GLfloat*)black);
glLightfv(gllight, GL_SPECULAR, (const GLfloat*)black);
if((sgLight->mType == LightInfo::SGStaticSpot) || (sgLight->mType == LightInfo::Spot))
glLightf(gllight, GL_SPOT_CUTOFF, (sgLight->sgSpotAngle * 0.5f));
else
glLightf(gllight, GL_SPOT_CUTOFF, 180.f);
glLightf(gllight, GL_CONSTANT_ATTENUATION, sgConstantAttenuation);
glLightf(gllight, GL_QUADRATIC_ATTENUATION, sgQuadraticAttenuation);
glLightf(gllight, GL_LINEAR_ATTENUATION, sgLinearAttenuation);
}
}
void sgLightingModelGLBase::sgInitStateLM()
{
sgLightingModel::sgInitStateLM();
spotanglecos = mCos(mDegToRad(sgLight->sgSpotAngle * 0.5f));
spotamountinner = 1.0f - spotanglecos;
spotamountouter = spotanglecos;
}
void sgLightingModelGLBase::sgLightingLM(const Point3F &point, VectorF normal, ColorF &diffuse, ColorF &ambient, Point3F &lightingnormal)
{
sgLightingModel::sgLightingLM(point, normal, diffuse, ambient, lightingnormal);
F32 anglefalloff = 0.0f;
// for speed set on exit - wrong! too often unset...
// do this in lightmap...
//diffuse = ColorF(0.0, 0.0, 0.0);
//ambient = ColorF(0.0, 0.0, 0.0);
//lightingnormal = Point3F(0.0, 0.0, 0.0);
// get the lighting vector squared...
if(sgLight->mType == LightInfo::Vector)
lightingnormal = sgLight->mDirection * -1.0f;
else
lightingnormal = sgLight->mPos - point;
// early out 1 - is surface facing light without double sided ambient (for terrain)?
anglefalloff = mDot(lightingnormal, normal);
if((anglefalloff <= 0.0f) && !(sgLight->sgDoubleSidedAmbient &&
((sgLight->sgLocalAmbientAmount >= SG_LIGHTING_MIN_CUTOFF) ||
(sgLight->mType == LightInfo::Vector))))
{
// do this in lightmap...
//diffuse = ColorF(0.0, 0.0, 0.0);
//ambient = ColorF(0.0, 0.0, 0.0);
//lightingnormal = Point3F(0.0, 0.0, 0.0);
return;
}
F32 dist = 0.0f;
F32 distsq = 0.0f;
F32 distfalloff = 1.0f;
F32 spotlightangle = 1.0f;
// so far so good - now get the dist falloff...
if(sgLight->mType != LightInfo::Vector)
{
bool didsqrt = false;
// need this...
distsq = lightingnormal.lenSquared();
// only need now for linear...
if(sgLinearAttenuation > 0.0f)
{
dist = mSqrt(distsq);
didsqrt = true;
}
distfalloff = (sgConstantAttenuation + (sgLinearAttenuation * dist) + (sgQuadraticAttenuation * distsq));
if(distfalloff > 0.0f)
distfalloff = 1.0f / distfalloff;
distfalloff = getMax(distfalloff, 0.0f);
// early out 2 - too far away?
if(distfalloff <= SG_LIGHTING_MIN_CUTOFF)
{
// do this in lightmap...
//diffuse = ColorF(0.0, 0.0, 0.0);
//ambient = ColorF(0.0, 0.0, 0.0);
//lightingnormal = Point3F(0.0, 0.0, 0.0);
return;
}
// get it now...
if(!didsqrt)
dist = mSqrt(distsq);
// normalize...
if(dist != 0.0f)
lightingnormal /= dist;
// safe to bailout here, ambient only follows spot...
if(sgLight->mType == LightInfo::SGStaticSpot)
{
spotlightangle = mDot(lightingnormal, sgLight->mDirection);
if(spotlightangle < spotanglecos)
{
//diffuse = ColorF(0.0, 0.0, 0.0);
//ambient = ColorF(0.0, 0.0, 0.0);
//lightingnormal = Point3F(0.0, 0.0, 0.0);
return;
}
}
}
// values coming from terrain are not normalized...
// lightingnormal is already normalized...
if((anglefalloff > 0.0f) && sgLight->sgUseNormals)
{
normal.normalize();
anglefalloff = mDot(lightingnormal, normal);
}
anglefalloff = getMax(getMin(anglefalloff, 1.0f), 0.0f);
if(sgLight->mType == LightInfo::SGStaticSpot)
{
// apply the spotlight lighting model...
spotlightangle = mClampF(((spotlightangle - spotamountouter) / spotamountinner), 0.0f, 1.0f);
if(sgLight->sgSmoothSpotLight)
spotlightangle *= getMin((spotlightangle * 1.2f), 1.0f);
}
if((sgLight->mType == LightInfo::Vector) && (anglefalloff < 0.0f))
anglefalloff = anglefalloff;
F32 ambientlightingamount = distfalloff * spotlightangle;
if(anglefalloff > 0.0f)
{
F32 diffuselightingamount = ambientlightingamount;
if(sgLight->sgUseNormals)
diffuselightingamount *= anglefalloff;
diffuselightingamount *= (1 - sgLight->sgLocalAmbientAmount);
diffuselightingamount = getMax(getMin(diffuselightingamount, 1.0f), 0.0f);
diffuse = sgLight->mColor * diffuselightingamount;
}
if(sgLight->sgDoubleSidedAmbient || (anglefalloff > 0.0f))
{
if(sgLight->mType == LightInfo::Vector)
{
ambient = sgLight->mAmbient;
}
else
{
ambientlightingamount *= sgLight->sgLocalAmbientAmount;
ambientlightingamount = getMax(getMin(ambientlightingamount, 1.0f), 0.0f);
ambient = sgLight->mColor * ambientlightingamount;
}
}
/*Point3F lightvectorsq;
Point3F lightvector;
Point3F lightvectorfordist;
F32 spotlightingangle;
//F32 anglefalloff = 0;
F32 dist;
F32 distsq;
// for speed set on exit...
diffuse = ColorF(0.0, 0.0, 0.0);
ambient = ColorF(0.0, 0.0, 0.0);
lightingnormal = Point3F(0.0, 0.0, 0.0);
// get light vector...
if(sgLight->mType == LightInfo::Vector)
lightvector = sgLight->mDirection * -1;
else
{
lightvector = sgLight->mPos - point;
// need this later...
lightvectorfordist = lightvector;
// vector lights are already normallized...
lightvector.normalize();
}
lightingnormal = lightvector;
// is it a spotlight? is it pointing this way?
if(sgLight->mType == LightInfo::SGStaticSpot)
{
spotlightingangle = mDot(lightvector, sgLight->mDirection);
if(spotlightingangle < spotanglecos)
return;
}
else
{
// default...
spotlightingangle = 1.0;
}
// get the attenuation info...
if(sgLight->mType != LightInfo::Vector)
{
if(sgQuadraticAttenuation > 0.0f)
distsq = lightvectorfordist.lenSquared();
// should never use linear...
if(sgLinearAttenuation > 0.0f)
dist = lightvectorfordist.len();
}
// get the lighting angle amount...
F32 angleamount = mDot(lightvector, normal);
F32 lightamount = angleamount;
F32 lightfalloff = 1.0;
lightamount = getMax(getMin(lightamount, 1.0f), 0.0f);
if(sgLight->mType != LightInfo::Vector)
{
// ahhh the lighting model...
lightfalloff = (sgConstantAttenuation + (sgLinearAttenuation * dist) + (sgQuadraticAttenuation * distsq));
if(lightfalloff != 0.0f)
lightfalloff = 1 / lightfalloff;
lightfalloff = getMax(lightfalloff, 0.0f);
if(sgLight->mType == LightInfo::SGStaticSpot)
{
// apply the spotlight lighting model...
spotlightingangle = mClampF(((spotlightingangle - spotamountouter) / spotamountinner), 0.0f, 1.0f);
if(sgLight->sgLightInfoData.sgSmoothSpotLight)
spotlightingangle *= getMin((spotlightingangle * 1.2), 1.0);
lightfalloff *= spotlightingangle;
}
lightamount *= lightfalloff;
}
lightamount *= (1 - sgLight->sgLightInfoData.sgLocalAmbientAmount);
lightamount = getMax(getMin(lightamount, 1.0f), 0.0f);
diffuse = sgLight->mColor * lightamount;
if(sgLight->sgLightInfoData.sgDoubleSidedAmbient || (angleamount > 0.0f))
{
lightfalloff *= sgLight->sgLightInfoData.sgLocalAmbientAmount;
lightfalloff = getMax(getMin(lightfalloff, 1.0f), 0.0f);
ambient = sgLight->mColor * lightfalloff;
}*/
}

View File

@ -0,0 +1,270 @@
//-----------------------------------------------
// Synapse Gaming - Lighting System
// Copyright <20> Synapse Gaming 2003
// Written by John Kabus
//-----------------------------------------------
#ifndef _SGLIGHTINGMODEL_H_
#define _SGLIGHTINGMODEL_H_
#ifndef _MMATH_H_
#include "math/mMath.h"
#endif
#ifndef _COLOR_H_
#include "core/color.h"
#endif
#ifndef _TVECTOR_H_
#include "core/tVector.h"
#endif
#ifndef _DATACHUNKER_H_
#include "core/dataChunker.h"
#endif
#include "console/console.h"
#include "console/consoleTypes.h"
#include "lightingSystem/sgLightManager.h"
#include "core/stringTable.h"
#include "core/tVector.h"
#define SG_LIGHTINGMODEL_NAME "SG - %s (Lighting Pack)"
#define SG_DYNAMICLIGHTING_TYPE2
class sgLightingModel
{
protected:
bool sgStateSet;
bool sgStateInitLM;
LightInfo *sgLight;
public:
char sgLightingModelName[64];
sgLightingModel();
void sgRegisterLightingModel();
virtual void sgSetState(LightInfo *light)
{
AssertFatal((sgStateSet == false), "sgLightingModel: State not properly reset.");
sgStateSet = true;
sgStateInitLM = false;
sgLight = light;
}
virtual void sgLightingGL(S32 gllight)
{
AssertFatal((sgStateSet == true), "sgLightingModel: State not properly set.");
}
virtual void sgInitStateLM()
{
AssertFatal((sgStateSet == true), "sgLightingModel: State not properly set.");
sgStateInitLM = true;
}
virtual void sgLightingLM(const Point3F &point, VectorF normal, ColorF &diffuse, ColorF &ambient, Point3F &lightingnormal)
{
AssertFatal((sgStateInitLM == true), "sgLightingModel: State not properly init.");
}
virtual void sgResetState()
{
sgStateSet = false;
sgStateInitLM = false;
sgLight = NULL;
}
virtual F32 sgScoreLight(LightInfo *light, const SphereF &sphere)
{
AssertFatal((sgStateSet == true), "sgLightingModel: State not properly set.");
return 0.0f;
}
virtual bool sgCanIlluminate(const Box3F &box) = 0;
virtual F32 sgGetMaxRadius(bool speedoverquality=false, bool glstyle=false) = 0;
virtual Point3F sgGetModelInfo() = 0;
};
class sgLightingModelGLBase : public sgLightingModel
{
protected:
F32 sgConstantAttenuation;
F32 sgLinearAttenuation;
F32 sgQuadraticAttenuation;
F32 spotanglecos;
F32 spotamountinner;
F32 spotamountouter;
Point4F sgLightParamDiffuse;
Point4F sgLightParamAmbient;
Point4F sgLightParamPosition;
Point4F sgLightParamDirection;
public:
virtual void sgSetState(LightInfo *light);
virtual void sgLightingGL(S32 gllight);
virtual void sgInitStateLM();
virtual void sgLightingLM(const Point3F &point, VectorF normal, ColorF &diffuse, ColorF &ambient, Point3F &lightingnormal);
virtual F32 sgScoreLight(LightInfo *light, const SphereF &sphere);
virtual bool sgCanIlluminate(const Box3F &box);
virtual F32 sgGetMaxRadius(bool speedoverquality=false, bool glstyle=false);
virtual Point3F sgGetModelInfo()
{
return Point3F(sgConstantAttenuation,
sgLinearAttenuation, sgQuadraticAttenuation);
}
};
class sgLightingModelAdvanced : public sgLightingModelGLBase
{
protected:
F32 maxlightdistancesquared;
public:
sgLightingModelAdvanced()
{
dSprintf(sgLightingModelName, sizeof(sgLightingModelName),
SG_LIGHTINGMODEL_NAME, "Original Advanced");
}
virtual void sgSetState(LightInfo *light);
virtual void sgInitStateLM();
virtual void sgLightingLM(const Point3F &point, VectorF normal, ColorF &diffuse, ColorF &ambient, Point3F &lightingnormal);
// only for TSE's consistent lighting models...
// TGE's vertex lighting requires the base
// class method sgLightingModelGLBase::sgScoreLight...
//virtual F32 sgScoreLight(LightInfo *light, const SphereF &sphere);
virtual bool sgCanIlluminate(const Box3F &box);
virtual F32 sgGetMaxRadius(bool speedoverquality=false, bool glstyle=false)
{
AssertFatal((sgStateSet == true), "sgLightingModel: State not properly set.");
if(glstyle)
return sgLightingModelGLBase::sgGetMaxRadius(speedoverquality, glstyle);
return sgLight->mRadius;
}
};
class sgLightingModelStock : public sgLightingModelGLBase
{
public:
sgLightingModelStock()
{
dSprintf(sgLightingModelName, sizeof(sgLightingModelName),
SG_LIGHTINGMODEL_NAME, "Original Stock");
}
void sgSetState(LightInfo *light)
{
sgLightingModelGLBase::sgSetState(light);
if(sgLight->mRadius > 0.0f)
sgQuadraticAttenuation = (1.0f / (sgLight->mRadius * sgLight->mRadius));
else
sgQuadraticAttenuation = 0.0f;
}
};
class sgLightingModelInverseSquare : public sgLightingModelGLBase
{
public:
sgLightingModelInverseSquare()
{
dSprintf(sgLightingModelName, sizeof(sgLightingModelName),
SG_LIGHTINGMODEL_NAME, "Inverse Square");
}
void sgSetState(LightInfo *light)
{
sgLightingModelGLBase::sgSetState(light);
sgConstantAttenuation = 1.0f;
if(sgLight->mRadius > 0.0f)
sgQuadraticAttenuation = (1.0f / (sgLight->mRadius * sgLight->mRadius));
else
sgQuadraticAttenuation = 0.0f;
}
};
class sgLightingModelInverseSquareFastFalloff : public sgLightingModelGLBase
{
public:
sgLightingModelInverseSquareFastFalloff()
{
dSprintf(sgLightingModelName, sizeof(sgLightingModelName),
SG_LIGHTINGMODEL_NAME, "Inverse Square Fast Falloff");
}
void sgSetState(LightInfo *light)
{
sgLightingModelGLBase::sgSetState(light);
sgConstantAttenuation = 1.0f;
if(sgLight->mRadius > 0.0f)
sgQuadraticAttenuation = (10.0f / (sgLight->mRadius * sgLight->mRadius));
else
sgQuadraticAttenuation = 0.0f;
}
};
class sgLightingModelNearLinear : public sgLightingModelGLBase
{
public:
sgLightingModelNearLinear()
{
dSprintf(sgLightingModelName, sizeof(sgLightingModelName),
SG_LIGHTINGMODEL_NAME, "Near Linear");
}
void sgSetState(LightInfo *light)
{
sgLightingModelGLBase::sgSetState(light);
sgConstantAttenuation = 1.0f;
if(sgLight->mRadius > 0.0f)
sgLinearAttenuation = (1.0f / sgLight->mRadius);
else
sgLinearAttenuation = 0.0f;
}
};
class sgLightingModelNearLinearFastFalloff : public sgLightingModelGLBase
{
public:
sgLightingModelNearLinearFastFalloff()
{
dSprintf(sgLightingModelName, sizeof(sgLightingModelName),
SG_LIGHTINGMODEL_NAME, "Near Linear Fast Falloff");
}
void sgSetState(LightInfo *light)
{
sgLightingModelGLBase::sgSetState(light);
sgConstantAttenuation = 1.0f;
if(sgLight->mRadius > 0.0f)
sgLinearAttenuation = (10.0f / sgLight->mRadius);
else
sgLinearAttenuation = 0.0f;
}
};
class sgLightingModelManager
{
private:
static Vector<sgLightingModel *> sgLightingModels;
static sgLightingModelStock sgDefaultModel;
static sgLightingModelAdvanced sgAdvancedModel;
static sgLightingModelInverseSquare sgInverseSquare;
static sgLightingModelInverseSquareFastFalloff sgInverseSquareFastFalloff;
static sgLightingModelNearLinear sgNearLinear;
static sgLightingModelNearLinearFastFalloff sgNearLinearFastFalloff;
static sgLightingModel *sgSunlightModel;
public:
sgLightingModelManager() {}
static void sgRegisterLightingModel(sgLightingModel *model) {sgLightingModels.push_back(model);}
static sgLightingModel &sgGetLightingModel() {return sgDefaultModel;}
static sgLightingModel &sgGetLightingModel(const char *name)
{
if((name == NULL) || (name[0] == 0))
return sgDefaultModel;
for(U32 i=0; i<sgLightingModels.size(); i++)
{
if(dStrcmp(sgLightingModels[i]->sgLightingModelName, name) == 0)
return *(sgLightingModels[i]);
}
return sgDefaultModel;
}
static U32 sgGetLightingModelCount() {return sgLightingModels.size();}
static char *sgGetLightingModelName(U32 index)
{
if((index < 0) || (index >= sgLightingModels.size()))
return "";
return sgLightingModels[index]->sgLightingModelName;
}
static const char *sgGetSunlightLightingModelName()
{
if(sgSunlightModel)
return sgSunlightModel->sgLightingModelName;
return NULL;
}
static char *sgGetAdvancedLightingModelName() {return sgAdvancedModel.sgLightingModelName;}
static char *sgGetStockLightingModelName() {return sgDefaultModel.sgLightingModelName;}
};
#endif//_SGLIGHTINGMODEL_H_

View File

@ -0,0 +1,110 @@
//-----------------------------------------------
// Synapse Gaming - Lighting System
// Copyright <20> Synapse Gaming 2003
// Written by John Kabus
//-----------------------------------------------
#include "console/consoleTypes.h"
#include "core/bitStream.h"
#include "sim/netConnection.h"
#include "lightingSystem/sgMissionLightingFilter.h"
#include "lightingSystem/sgLighting.h"
IMPLEMENT_CO_DATABLOCK_V1(sgMissionLightingFilterData);
IMPLEMENT_CO_NETOBJECT_V1(sgMissionLightingFilter);
void sgMissionLightingFilterData::initPersistFields()
{
Parent::initPersistFields();
addField("CinematicFilter", TypeBool, Offset(sgCinematicFilter, sgMissionLightingFilterData));
addField("LightingIntensity", TypeF32, Offset(sgLightingIntensity, sgMissionLightingFilterData));
addField("LightingFilter", TypeColorF, Offset(sgLightingFilter, sgMissionLightingFilterData));
addField("CinematicFilterAmount", TypeF32, Offset(sgCinematicFilterAmount, sgMissionLightingFilterData));
addField("CinematicFilterReferenceIntensity", TypeF32, Offset(sgCinematicFilterReferenceIntensity, sgMissionLightingFilterData));
addField("CinematicFilterReferenceColor", TypeColorF, Offset(sgCinematicFilterReferenceColor, sgMissionLightingFilterData));
}
void sgMissionLightingFilterData::packData(BitStream *stream)
{
Parent::packData(stream);
stream->write(sgCinematicFilter);
stream->write(sgLightingIntensity);
stream->write(sgLightingFilter);
stream->write(sgCinematicFilterAmount);
stream->write(sgCinematicFilterReferenceIntensity);
stream->write(sgCinematicFilterReferenceColor);
}
void sgMissionLightingFilterData::unpackData(BitStream *stream)
{
Parent::unpackData(stream);
stream->read(&sgCinematicFilter);
stream->read(&sgLightingIntensity);
stream->read(&sgLightingFilter);
stream->read(&sgCinematicFilterAmount);
stream->read(&sgCinematicFilterReferenceIntensity);
stream->read(&sgCinematicFilterReferenceColor);
}
void sgMissionLightingFilter::initPersistFields()
{
Parent::initPersistFields();
}
void sgMissionLightingFilter::inspectPostApply()
{
Parent::inspectPostApply();
setMaskBits(0xffffffff);
}
bool sgMissionLightingFilter::onAdd()
{
if(!Parent::onAdd())
return false;
mObjBox.min.set( -0.5, -0.5, -0.5 );
mObjBox.max.set( 0.5, 0.5, 0.5 );
resetWorldBox();
setRenderTransform(mObjToWorld);
SimSet *filters = Sim::getsgMissionLightingFilterSet();
if(filters && isClientObject())
filters->addObject(this);
addToScene();
return true;
}
void sgMissionLightingFilter::onRemove()
{
SimSet *filters = Sim::getsgMissionLightingFilterSet();
if(filters && isClientObject())
filters->removeObject(this);
removeFromScene();
Parent::onRemove();
}
U32 sgMissionLightingFilter::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
{
U32 res = Parent::packUpdate(con, mask, stream);
stream->writeAffineTransform(mObjToWorld);
return res;
}
void sgMissionLightingFilter::unpackUpdate(NetConnection *con, BitStream *stream)
{
Parent::unpackUpdate(con, stream);
MatrixF ObjectMatrix;
stream->readAffineTransform(&ObjectMatrix);
setTransform(ObjectMatrix);
}

View File

@ -0,0 +1,71 @@
//-----------------------------------------------
// Synapse Gaming - Lighting System
// Copyright <20> Synapse Gaming 2003
// Written by John Kabus
//-----------------------------------------------
#ifndef _SGMISSIONLIGHTINGFILTER_H_
#define _SGMISSIONLIGHTINGFILTER_H_
#include "game/gameBase.h"
/**
*/
class sgMissionLightingFilterData : public GameBaseData
{
typedef GameBaseData Parent;
public:
F32 sgLightingIntensity;
ColorF sgLightingFilter;
bool sgCinematicFilter;
F32 sgCinematicFilterAmount;
F32 sgCinematicFilterReferenceIntensity;
ColorF sgCinematicFilterReferenceColor;
sgMissionLightingFilterData()
{
sgCinematicFilter = false;
sgLightingIntensity = 1.0;
sgLightingFilter = ColorF(1.0, 1.0, 1.0);
sgCinematicFilterAmount = 1.0;
sgCinematicFilterReferenceIntensity = 1.0;
sgCinematicFilterReferenceColor = ColorF(1.0, 1.0, 1.0);
}
static void initPersistFields();
virtual void packData(BitStream *stream);
virtual void unpackData(BitStream *stream);
DECLARE_CONOBJECT(sgMissionLightingFilterData);
};
/**
*/
class sgMissionLightingFilter : public GameBase
{
typedef GameBase Parent;
sgMissionLightingFilterData *mDataBlock;
bool onNewDataBlock(GameBaseData* dptr)
{
mDataBlock = dynamic_cast<sgMissionLightingFilterData *>(dptr);
return Parent::onNewDataBlock(dptr);
}
public:
sgMissionLightingFilter()
{
mTypeMask |= StaticObjectType | StaticTSObjectType | StaticRenderedObjectType;
mNetFlags.set(Ghostable | ScopeAlways);
mDataBlock = NULL;
}
static void initPersistFields();
virtual void inspectPostApply();
bool onAdd();
void onRemove();
U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream);
void unpackUpdate(NetConnection *con, BitStream *stream);
DECLARE_CONOBJECT(sgMissionLightingFilter);
};
#endif//_SGMISSIONLIGHTINGFILTER_H_

View File

@ -0,0 +1,524 @@
//-----------------------------------------------
// Synapse Gaming - Lighting System
// Copyright <20> Synapse Gaming 2003
// Written by John Kabus
//-----------------------------------------------
#include "sceneGraph/sceneGraph.h"
#include "math/mathUtils.h"
#include "game/shapeBase.h"
#include "game/vehicles/wheeledVehicle.h"
#include "lightingSystem/sgLighting.h"
#include "lightingSystem/sgLightingModel.h"
#include "lightingSystem/sgObjectShadows.h"
#define SG_UNUSED_TIMEOUT 2000
#define SG_SHADOW_TIMEOUT 6000
// this can be a long time, only used for cleaning
// up texture memory after an intensive scene (TSE only)...
//#define SG_TEXTURE_TIMEOUT 30000
extern SceneGraph* gClientSceneGraph;
Vector<sgObjectShadows *> sgObjectShadowMonitor::sgAllObjectShadows;
F32 sgObjectShadows::sgCurrentFade = 1.0;
bool sgTimeElapsed(U32 currenttime, U32 &lasttime, U32 period)
{
if(currenttime < lasttime)
{
lasttime = 0;
return false;
}
if((currenttime - lasttime) < period)
return false;
lasttime = currenttime;
return true;
}
//-----------------------------------------------
void sgObjectShadowMonitor::sgRegister(sgObjectShadows *shadows)
{
sgAllObjectShadows.push_back(shadows);
}
void sgObjectShadowMonitor::sgUnregister(sgObjectShadows *shadows)
{
for(U32 i=0; i<sgAllObjectShadows.size(); i++)
{
if(sgAllObjectShadows[i] == shadows)
{
sgAllObjectShadows.erase_fast(i);
return;
}
}
}
void sgObjectShadowMonitor::sgCleanupUnused()
{
static U32 lasttime = 0;
U32 time = Platform::getRealMilliseconds();
if(!sgTimeElapsed(time, lasttime, SG_UNUSED_TIMEOUT))
return;
//Con::warnf("Checking for unused shadows...");
for(U32 i=0; i<sgAllObjectShadows.size(); i++)
sgAllObjectShadows[i]->sgCleanupUnused(time);
//Con::warnf("Done.");
}
//-----------------------------------------------
sgObjectShadows::sgObjectShadows()
{
sgRegistered = false;
sgLastRenderTime = 0;
sgSingleShadowSource.mColor = ColorF(0.5, 0.5, 0.5);
//sgEnable = false;
//sgCanMove = false;
//sgCanRTT = false;
//sgCanSelfShadow = false;
//sgRequestedShadowSize = 64;
//sgFrameSkip = 5;
//sgMaxVisibleDistance = 15.0f;
//sgProjectionDistance = 7.0f;
//sgFirstEntry = sgGetFirstShadowEntry();
}
sgObjectShadows::~sgObjectShadows()
{
sgClearMap();
}
void sgObjectShadows::sgClearMap()
{
sgShadowMultimap *entry = sgGetFirstShadowEntry();
while(entry)
{
if(entry->info)
{
delete entry->info;
entry->info = NULL;
}
entry = entry->linkHigh;
}
// all shadows are deleted, so nothing left to monitor...
if(sgRegistered)
{
sgObjectShadowMonitor::sgUnregister(this);
sgRegistered = false;
}
}
void sgObjectShadows::sgRender(SceneObject *parentobject,
TSShapeInstance *shapeinstance, F32 dist, F32 fogamount,
F32 genericshadowlevel, F32 noshadowlevel, U32 shadownode,
bool move, bool animate)
{
if(!LightManager::sgAllowDynamicShadows())
return;
if(Shadow::getGlobalShadowDetailLevel() < noshadowlevel)
return;
if(shapeinstance->getShape()->subShapeFirstTranslucentObject.empty() ||
shapeinstance->getShape()->subShapeFirstTranslucentObject[0] == 0)
return;
// prior to this no shadows exist, so no resources are used...
if(!sgRegistered)
{
sgObjectShadowMonitor::sgRegister(this);
sgRegistered = true;
}
sgLastRenderTime = Platform::getRealMilliseconds();
ShapeBase *shapebase = dynamic_cast<ShapeBase *>(parentobject);
WheeledVehicle *wheeledvehicle = dynamic_cast<WheeledVehicle *>(parentobject);
LightInfoList lights;
LightManager *lm = gClientSceneGraph->getLightManager();
lm->sgGetBestLights(lights);
// env light must be last!
for(U32 i=0; i<lights.size(); i++)
{
LightInfo *light = lights[i];
if((light->mType != LightInfo::Ambient) &&
(light->mType != LightInfo::Vector))
continue;
U32 il = lights.size() - 1;
if(i == il)
continue;
// swap...
LightInfo *last = lights[il];
lights[il] = light;
lights[i] = last;
break;
}
F32 shadowLen = 10.0f * shapeinstance->getShape()->radius;
Point3F pos = shapeinstance->getShape()->center;
// this is a bit of a hack...move generic shadows towards feet/base of shape
if(Shadow::getGlobalShadowDetailLevel() < genericshadowlevel)
pos *= 0.5f;
S32 shadowNode = shadownode;
if(shadowNode >= 0)
{
// adjust for movement of shape outside of bounding box by tracking this node
Point3F offset;
shapeinstance->mNodeTransforms[shadowNode].getColumn(3,&offset);
offset -= shapeinstance->getShape()->defaultTranslations[shadowNode];
offset.z = 0.0f;
pos += offset;
}
pos.convolve(parentobject->getScale());
parentobject->getRenderTransform().mulP(pos);
U32 usedlights = 0;
for(U32 i=0; i<lights.size(); i++)
{
LightInfo *light = lights[i];
// we want the env light!
if((!LightManager::sgMultipleDynamicShadows) &&
(light->mType != LightInfo::Vector) &&
(light->mType != LightInfo::Ambient))
continue;
// cast shadows?
if(!light->sgCastsShadows)
continue;
// avoid overlapping dynamic and static shadows...
if(((light->mType == LightInfo::SGStaticPoint) ||
(light->mType == LightInfo::SGStaticSpot) ||
(light->mType == LightInfo::Vector)) && (parentobject->getTypeMask() & ShadowCasterObjectType))
continue;
// find the shadow...
Shadow *shadow = sgFindShadow(parentobject, light, shapeinstance);
AssertFatal((shadow), "Shadow not found?");
if(Shadow::getGlobalShadowDetailLevel() < genericshadowlevel)
shadow->setGeneric(true);
else
shadow->setGeneric(false);
shadow->setMoving(move);
shadow->setAnimating(animate);
// Get a real light dir...
// keep this default, it makes the sun shadow darker...
F32 fade = 3.0;
Point3F lightDir;
if(LightManager::sgMultipleDynamicShadows)
{
//if(light->mType == LightInfo::Vector)
// lightDir = light->mDirection;
//else if(light->mType == LightInfo::Ambient)
if((light->mType == LightInfo::Vector) ||
(light->mType == LightInfo::Ambient))
{
lightDir = sgGetShadowLightDirection(parentobject, shadow);
if(usedlights > 0)
fade *= 1.0f / F32(usedlights + 1);
}
else
{
lightDir = parentobject->getPosition() - light->mPos;
F32 len = lightDir.len();
if(len == 0.0f)
continue;
lightDir /= len;
sgLightingModel &model = sgLightingModelManager::sgGetLightingModel(
light->sgLightingModelName);
model.sgSetState(light);
//F32 maxrad = model.sgGetMaxRadius(true, true);
SphereF s;
s.center = parentobject->getPosition();
fade = model.sgScoreLight(light, s);
model.sgResetState();
}
}
else
{
lightDir = sgGetShadowLightDirection(parentobject, shadow);
}
// help out dim lights a little...
if(light->sgAssignedToParticleSystem)
fade *= SG_PARTICLESYSTEMLIGHT_FIXED_INTENSITY;
else
fade *= getMax(light->mColor.red, getMax(light->mColor.green, light->mColor.blue));
fade *= 1.5f;
// prevent dark shadows...
fade = mClampF(fade, 0.0f, 1.0f);
if(fade <= 0.1f)
continue;
usedlights++;
sgObjectShadows::sgCurrentFade = fade;
// pos is where shadow will be centered (in world space)
if(wheeledvehicle)
pos -= lightDir;
Point3F scale = parentobject->getScale();
shadow->setRadius(shapeinstance, scale);
if(!shadow->prepare(pos, lightDir, shadowLen, scale, dist, fogamount, shapeinstance))
continue;
F32 maxscale = getMax(scale.x, getMax(scale.y, scale.z));
if(shadow->needBitmap())
{
shadow->beginRenderToBitmap();
shadow->selectShapeDetail(shapeinstance, dist, maxscale);
shadow->renderToBitmap(shapeinstance, parentobject->getRenderTransform(), pos, scale);
if(shapebase)
{
// render mounted items to shadow bitmap
for(U32 i=0; i<ShapeBase::MaxMountedImages; i++)
{
TSShapeInstance *instance = shapebase->getImageShapeInstance(i);
if(instance)
{
MatrixF mat;
shapebase->getRenderImageTransform(i, &mat);
shadow->selectShapeDetail(instance, dist, maxscale);
shadow->renderToBitmap(instance, mat, pos, Point3F(1,1,1));
}
}
// We only render the first mounted object for now...
ShapeBase *mount = shapebase->getMountedObject(0);
if(mount && mount->getShapeInstance())
{
Point3F linkscale = mount->getScale();
maxscale = getMax(linkscale.x, getMax(linkscale.y, linkscale.z));
shadow->selectShapeDetail(mount->getShapeInstance(), dist, maxscale);
shadow->renderToBitmap(mount->getShapeInstance(),
mount->getRenderTransform(), pos, linkscale);
}
}
if(wheeledvehicle)
{
for(U32 w=0; w<wheeledvehicle->getWheelCount(); w++)
{
WheeledVehicle::Wheel *wheel = wheeledvehicle->getWheel(w);
if(wheel->shapeInstance)
{
MatrixF m = parentobject->getRenderTransform();
MatrixF hub(EulerF(0, 0, wheeledvehicle->getSteering().x * wheel->steering));
Point3F p = wheel->data->pos;
p.z -= wheel->spring->length * wheel->extension;
hub.setColumn(3, p);
m.mul(hub);
MatrixF rot(EulerF(wheel->apos * M_2PI,0,0));
m.mul(rot);
MatrixF wrot(EulerF(0, 0, (wheel->data->pos.x > 0)? M_PI/2: -M_PI/2));
m.mul(wrot);
shadow->selectShapeDetail(wheel->shapeInstance, dist, maxscale);
shadow->renderToBitmap(wheel->shapeInstance, m, pos, scale);
}
}
}
shadow->endRenderToBitmap();
}
shadow->render();
shadow->sgLastRenderTime = sgLastRenderTime;
if(!LightManager::sgMultipleDynamicShadows)
{
//only need to render one here...
break;
}
}
}
const Point3F sgObjectShadows::sgGetShadowLightDirection(SceneObject *obj, Shadow *shadow) const
{
// don't want this to run too fast on newer systems (otherwise shadows snap into place)...
U32 time = Platform::getRealMilliseconds();
if((time - shadow->sgPreviousShadowTime) < SG_DYNAMIC_SHADOW_TIME)
return shadow->sgPreviousShadowLightingVector;
shadow->sgPreviousShadowTime = time;
LightManager *lm = gClientSceneGraph->getLightManager();
// ok get started...
U32 zone = obj->getCurrZone(0);
VectorF vectcomposite = VectorF(0, 0, -1.0f);
if(!LightManager::sgMultipleDynamicShadows)
{
U32 score;
U32 maxscore[2] = {0, 0};
LightInfo *light[2] = {NULL, NULL};
VectorF vector[2] = {VectorF(0, 0, 0), VectorF(0, 0, 0)};
LightInfoList lights;
lm->sgGetBestLights(lights);
for(U32 i=0; i<lights.size(); i++)
{
LightInfo *l = lights[i];
if((l->mType == LightInfo::Ambient) || (l->mType == LightInfo::Vector))
score = l->mScore / SG_LIGHTMANAGER_SUN_PRIORITY;
else if((l->mType == LightInfo::SGStaticPoint) || (l->mType == LightInfo::SGStaticSpot))
score = l->mScore / SG_LIGHTMANAGER_STATIC_PRIORITY;
else
score = l->mScore / SG_LIGHTMANAGER_DYNAMIC_PRIORITY;
if(score > maxscore[0])
{
light[1] = light[0];
maxscore[1] = maxscore[0];
light[0] = l;
maxscore[0] = score;
}
else if(score > maxscore[1])
{
light[1] = l;
maxscore[1] = score;
}
}
for(U32 i=0; i<2; i++)
{
if(!light[i])
break;
if((light[i]->mType == LightInfo::Ambient) || (light[i]->mType == LightInfo::Vector))
{
if(zone == 0)
vector[i] = light[i]->mDirection;
else
vector[i] = Point3F(0, 0, -1.0);
}
else
{
VectorF vect = obj->getPosition() - light[i]->mPos;
vect.normalize();
vector[i] = vect;
}
}
if(light[0])
{
if(light[1])
{
F32 ratio = F32(maxscore[0]) / F32(maxscore[0] + maxscore[1]);
vectcomposite = (vector[0] * ratio) + (vector[1] * (1.0f - ratio));
}
else
vectcomposite = vector[0];
}
}
else
{
if(zone != 0)
vectcomposite = VectorF(0.0f, 0.0f, -1.0f);
else
{
LightInfo *sun = lm->sgGetSpecialLight(LightManager::sgSunLightType);
vectcomposite = sun->mDirection;
}
}
VectorF step = (vectcomposite - shadow->sgPreviousShadowLightingVector) / SG_DYNAMIC_SHADOW_STEPS;
shadow->sgPreviousShadowLightingVector += step;
shadow->sgPreviousShadowLightingVector.normalize();
return shadow->sgPreviousShadowLightingVector;
}
void sgObjectShadows::sgCleanupUnused(U32 time)
{
// wrapped around?
if(time < sgLastRenderTime)
{
sgLastRenderTime = 0;
return;
}
// try to ditch the whole thing first...
if((time - sgLastRenderTime) > SG_SHADOW_TIMEOUT)
{
//Con::warnf("Found a whole set...");
sgClearMap();
return;
}
// no? alright lets try to get rid of some old shadows...
sgShadowMultimap *entry = sgGetFirstShadowEntry();
while(entry)
{
if(entry->info)
{
if(sgTimeElapsed(time, entry->info->sgLastRenderTime, SG_SHADOW_TIMEOUT))
{
//Con::warnf("Found one...");
delete entry->info;
entry->info = NULL;
}
}
entry = entry->linkHigh;
}
}
Shadow *sgObjectShadows::sgFindShadow(SceneObject *parentobject,
LightInfo *light, TSShapeInstance *shapeinstance)
{
sgShadowMultimap *entry = sgShadows.find(sgLightToHash(light));
if(entry->info)
return entry->info;
Shadow *shadow = new Shadow();
entry->info = shadow;
return entry->info;
}
sgShadowMultimap *sgObjectShadows::sgGetFirstShadowEntry()
{
return sgShadows.find(sgosFirstEntryHash);
}

View File

@ -0,0 +1,85 @@
//-----------------------------------------------
// Synapse Gaming - Lighting System
// Copyright <20> Synapse Gaming 2003
// Written by John Kabus
//-----------------------------------------------
#ifndef _SGOBJECTSHADOWS_H_
#define _SGOBJECTSHADOWS_H_
#include "game/shadow.h"
#include "lightingSystem/sgHashMap.h"
typedef hash_multimap<U32, Shadow *> sgShadowMultimap;
class sgObjectShadows
{
private:
enum
{
sgosFirstEntryHash = 0
};
bool sgRegistered;
U32 sgLastRenderTime;
//bool sgEnable;
//bool sgCanMove;
//bool sgCanRTT;
//bool sgCanSelfShadow;
//U32 sgRequestedShadowSize;
//U32 sgFrameSkip;
//F32 sgMaxVisibleDistance;
//F32 sgProjectionDistance;
//F32 sgSphereAdjust;
sgShadowMultimap sgShadows;
// for non-multi-shadows...
LightInfo sgSingleShadowSource;
// returns an empty entry (use linkHigh to traverse the list)...
// generally it's a good idea to expect some entries to be empty...
sgShadowMultimap *sgGetFirstShadowEntry();
Shadow *sgFindShadow(SceneObject *parentobject,
LightInfo *light, TSShapeInstance *shapeinstance);
//void sgUpdateShadow(sgShadowProjector *shadow);
//void sgUpdateShadows();
void sgClearMap();
U32 sgLightToHash(LightInfo *light) {return U32(light);}
LightInfo *sgHashToLight(U32 hash) {return (LightInfo *)hash;}
public:
static F32 sgCurrentFade;
sgObjectShadows();
~sgObjectShadows();
void sgRender(SceneObject *parentobject, TSShapeInstance *shapeinstance,
F32 dist, F32 fogamount, F32 genericshadowlevel,
F32 noshadowlevel, U32 shadownode, bool move, bool animate);
const Point3F sgGetShadowLightDirection(SceneObject *obj, Shadow *shadow) const;
void sgCleanupUnused(U32 time);
//void sgSetValues(bool enable, bool canmove, bool canrtt,
// bool selfshadow, U32 shadowsize, U32 frameskip,
// F32 maxvisibledist, F32 projectiondist, F32 adjust);
};
/**
* Someone needs to make sure the resource
* usage doesn't get out of hand...
*/
class sgObjectShadowMonitor
{
private:
// I should be a map!!!
static Vector<sgObjectShadows *> sgAllObjectShadows;
public:
static void sgRegister(sgObjectShadows *shadows);
static void sgUnregister(sgObjectShadows *shadows);
static void sgCleanupUnused();
};
#endif//_SGOBJECTSHADOWS_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,374 @@
//-----------------------------------------------
// Synapse Gaming - Lighting System
// Copyright <20> Synapse Gaming 2003
// Written by John Kabus
//-----------------------------------------------
#ifndef _SGSCENELIGHTING_H_
#define _SGSCENELIGHTING_H_
#ifndef _SCENEOBJECT_H_
#include "sim/sceneObject.h"
#endif
#ifndef _TERRDATA_H_
#include "terrain/terrData.h"
#endif
#ifndef _INTERIORINSTANCE_H_
#include "interior/interiorInstance.h"
#endif
#ifndef _SHADOWVOLUMEBSP_H_
#include "sceneGraph/shadowVolumeBSP.h"
#endif
#include "math/mathUtils.h"
#include "lightingSystem/sgLightManager.h"
#include "lightingSystem/sgScenePersist.h"
#include "lightingSystem/sgLightMap.h"
class SceneLighting : public SimObject
{
typedef SimObject Parent;
public:
S32 sgTimeTemp;
S32 sgTimeTemp2;
void sgNewEvent(U32 light, S32 object, U32 event);
void sgLightingStartEvent();
void sgLightingCompleteEvent();
void sgTGEPassSetupEvent();
void sgTGELightStartEvent(U32 light);
void sgTGELightProcessEvent(U32 light, S32 object);
void sgTGELightCompleteEvent(U32 light);
void sgTGESetProgress(U32 light, S32 object);
void sgSGPassSetupEvent();
void sgSGObjectStartEvent(S32 object);
void sgSGObjectProcessEvent(U32 light, S32 object);
void sgSGObjectCompleteEvent(S32 object);
void sgSGSetProgress(U32 light, S32 object);
bool sgIsCorrectStaticObjectType(SceneObject *obj);
// 'sg' prefix omitted to conform with existing 'addInterior' method...
void addStatic(void *terrainproxy, ShadowVolumeBSP *shadowVolume,
SceneObject *sceneobject, LightInfo *light, S32 level);
// persist objects moved to 'sgScenePersist.h' for clarity...
// everything below this line should be original code...
U32 calcMissionCRC();
bool verifyMissionInfo(PersistInfo::PersistChunk *);
bool getMissionInfo(PersistInfo::PersistChunk *);
bool loadPersistInfo(const char *);
bool savePersistInfo(const char *);
class ObjectProxy;
class TerrainProxy;
class InteriorProxy;
enum {
SHADOW_DETAIL = -1
};
void addInterior(ShadowVolumeBSP *, InteriorProxy &, LightInfo *, S32);
ShadowVolumeBSP::SVPoly * buildInteriorPoly(ShadowVolumeBSP *, InteriorProxy &, Interior *, U32, LightInfo *, bool);
//------------------------------------------------------------------------------
/// Create a proxy for each object to store data.
class ObjectProxy
{
public:
SimObjectPtr<SceneObject> mObj;
U32 mChunkCRC;
ObjectProxy(SceneObject * obj) : mObj(obj){mChunkCRC = 0;}
virtual ~ObjectProxy(){}
SceneObject * operator->() {return(mObj);}
SceneObject * getObject() {return(mObj);}
/// @name Lighting Interface
/// @{
virtual bool loadResources() {return(true);}
virtual void init() {}
virtual bool preLight(LightInfo *) {return(false);}
virtual void light(LightInfo *) {}
virtual void postLight(bool lastLight) {}
/// @}
/// @name Persistence
///
/// We cache lighting information to cut down on load times.
///
/// There are flags such as ForceAlways and LoadOnly which allow you
/// to control this behaviour.
/// @{
bool calcValidation();
bool isValidChunk(PersistInfo::PersistChunk *);
virtual U32 getResourceCRC() = 0;
virtual bool setPersistInfo(PersistInfo::PersistChunk *);
virtual bool getPersistInfo(PersistInfo::PersistChunk *);
/// @}
};
class InteriorProxy : public ObjectProxy
{
private:
typedef ObjectProxy Parent;
bool isShadowedBy(InteriorProxy *);
public:
InteriorProxy(SceneObject * obj);
~InteriorProxy();
InteriorInstance * operator->() {return(static_cast<InteriorInstance*>(static_cast<SceneObject*>(mObj)));}
InteriorInstance * getObject() {return(static_cast<InteriorInstance*>(static_cast<SceneObject*>(mObj)));}
// current light info
ShadowVolumeBSP * mBoxShadowBSP;
Vector<ShadowVolumeBSP::SVPoly*> mLitBoxSurfaces;
Vector<PlaneF> mOppositeBoxPlanes;
Vector<PlaneF> mTerrainTestPlanes;
struct sgSurfaceInfo
{
Interior *sgDetail;
S32 sgSurfaceIndex;// SG_NULL_SURFACE == static mesh...
ConstructorSimpleMesh *sgStaticMesh;
PlaneF sgSurfacePlane;
bool sgSurfaceOutsideVisible;
Vector<sgPlanarLightMap::sgSmoothingVert> sgTriStrip;
Point3D sgWorldPos;
Point3D sgSVector;
Point3D sgTVector;
Point2I sgLightMapExtent;
Point2I sgLightMapOffset;
U32 sgLightMapIndex;
};
U32 sgCurrentSurfaceIndex;
U32 sgSurfacesPerPass;
InteriorInstance *sgInterior;
Vector<LightInfo *> sgLights;
Vector<sgSurfaceInfo *> sgSurfaces;
void sgClearSurfaces()
{
for(U32 s=0; s<sgSurfaces.size(); s++)
{
if(sgSurfaces[s])
delete sgSurfaces[s];
}
sgSurfaces.clear();
}
void sgAddLight(LightInfo *light, InteriorInstance *interior);
//void sgLightUniversalPoint(LightInfo *light);
void sgProcessSurface(sgSurfaceInfo &surfaceinfo);
void sgConvertStaticMeshPrimitiveToSurfaceInfo(const ConstructorSimpleMesh *staticmesh, U32 primitiveindex, Interior *detail, sgSurfaceInfo &surfaceinfo);
void sgConvertInteriorSurfaceToSurfaceInfo(const Interior::Surface &surface, U32 i, Interior *detail, sgSurfaceInfo &surfaceinfo);
void sgReorganizeSurface(sgSurfaceInfo &surfaceinfo);
void sgExtractLightingInformation(const Interior *detail, const PlaneF &lmEqX, const PlaneF &lmEqY,
const PlaneF &surfplane, const Point2I &lmoff, const Point2I &lmext, const Point2I &lmsheetsize,
Point3D &worldpos, Point3D &vectS, Point3D &vectT, Point2I &lmoffactual, Point2I &lmextactual);
// lighting interface
bool loadResources();
void init();
bool preLight(LightInfo *);
void light(LightInfo *);
void postLight(bool lastLight);
// persist
U32 getResourceCRC();
bool setPersistInfo(PersistInfo::PersistChunk *);
bool getPersistInfo(PersistInfo::PersistChunk *);
};
class TerrainProxy : public ObjectProxy
{
private:
typedef ObjectProxy Parent;
BitVector mShadowMask;
ShadowVolumeBSP * mShadowVolume;
ColorF * mLightmap;
ColorF *sgBakedLightmap;
Vector<LightInfo *> sgLights;
void sgAddUniversalPoint(LightInfo *light);
void sgLightUniversalPoint(LightInfo *light, TerrainBlock * terrain);
bool sgMarkStaticShadow(void *terrainproxy, SceneObject *sceneobject, LightInfo *light);
void postLight(bool lastLight);
void lightVector(LightInfo *);
struct SquareStackNode
{
U8 mLevel;
U16 mClipFlags;
Point2I mPos;
};
S32 testSquare(const Point3F &, const Point3F &, S32, F32, const Vector<PlaneF> &);
bool markInteriorShadow(InteriorProxy *);
public:
TerrainProxy(SceneObject * obj);
~TerrainProxy();
TerrainBlock * operator->() {return(static_cast<TerrainBlock*>(static_cast<SceneObject*>(mObj)));}
TerrainBlock * getObject() {return(static_cast<TerrainBlock*>(static_cast<SceneObject*>(mObj)));}
bool getShadowedSquares(const Vector<PlaneF> &, Vector<U16> &);
// lighting
void init();
bool preLight(LightInfo *);
void light(LightInfo *);
// persist
U32 getResourceCRC();
bool setPersistInfo(PersistInfo::PersistChunk *);
bool getPersistInfo(PersistInfo::PersistChunk *);
};
typedef Vector<ObjectProxy*> ObjectProxyList;
ObjectProxyList mSceneObjects;
ObjectProxyList mLitObjects;
LightInfoList mLights;
SceneLighting();
~SceneLighting();
enum Flags {
ForceAlways = BIT(0), ///< Regenerate the scene lighting no matter what.
ForceWritable = BIT(1), ///< Regenerate the scene lighting only if we can write to the lighting cache files.
LoadOnly = BIT(2), ///< Just load cached lighting data.
};
static bool lightScene(const char *, BitSet32 flags = 0);
static bool isLighting();
S32 mStartTime;
char mFileName[1024];
static bool smUseVertexLighting;
bool light(BitSet32);
void completed(bool success);
void processEvent(U32 light, S32 object);
void processCache();
// inlined
bool isAtlas(SceneObject *);
bool isTerrain(SceneObject *);
bool isInterior(SceneObject *);
};
class sgSceneLightingProcessEvent : public SimEvent
{
private:
U32 sgLightIndex;
S32 sgObjectIndex;
U32 sgEvent;
public:
enum sgEventTypes
{
sgLightingStartEventType,
sgLightingCompleteEventType,
sgSGPassSetupEventType,
sgSGObjectStartEventType,
sgSGObjectCompleteEventType,
sgSGObjectProcessEventType,
sgTGEPassSetupEventType,
sgTGELightStartEventType,
sgTGELightCompleteEventType,
sgTGELightProcessEventType
};
sgSceneLightingProcessEvent(U32 lightIndex, S32 objectIndex, U32 event)
{
sgLightIndex = lightIndex;
sgObjectIndex = objectIndex;
sgEvent = event;
}
void process(SimObject * object)
{
AssertFatal(object, "SceneLightingProcessEvent:: null event object!");
if(!object)
return;
SceneLighting *sl = static_cast<SceneLighting*>(object);
switch(sgEvent)
{
case sgLightingStartEventType:
sl->sgLightingStartEvent();
break;
case sgLightingCompleteEventType:
sl->sgLightingCompleteEvent();
break;
case sgTGEPassSetupEventType:
sl->sgTGEPassSetupEvent();
break;
case sgTGELightStartEventType:
sl->sgTGELightStartEvent(sgLightIndex);
break;
case sgTGELightProcessEventType:
sl->sgTGELightProcessEvent(sgLightIndex, sgObjectIndex);
break;
case sgTGELightCompleteEventType:
sl->sgTGELightCompleteEvent(sgLightIndex);
break;
case sgSGPassSetupEventType:
sl->sgSGPassSetupEvent();
break;
case sgSGObjectStartEventType:
sl->sgSGObjectStartEvent(sgObjectIndex);
break;
case sgSGObjectProcessEventType:
sl->sgSGObjectProcessEvent(sgLightIndex, sgObjectIndex);
break;
case sgSGObjectCompleteEventType:
sl->sgSGObjectCompleteEvent(sgObjectIndex);
break;
default:
return;
};
};
};
//------------------------------------------------------------------------------
inline bool SceneLighting::isAtlas(SceneObject * obj)
{
return obj && ((obj->getTypeMask() & AtlasObjectType) != 0);
}
inline bool SceneLighting::isTerrain(SceneObject * obj)
{
return obj && ((obj->getTypeMask() & TerrainObjectType) != 0);
}
inline bool SceneLighting::isInterior(SceneObject * obj)
{
return obj && ((obj->getTypeMask() & InteriorObjectType) != 0);
}
#endif//_SGSCENELIGHTING_H_

View File

@ -0,0 +1,58 @@
//-----------------------------------------------
// Synapse Gaming - Lighting System
// Copyright <20> Synapse Gaming 2003
// Written by John Kabus
//-----------------------------------------------
static const Point3F BoxNormals[] =
{
Point3F( 1, 0, 0),
Point3F(-1, 0, 0),
Point3F( 0, 1, 0),
Point3F( 0,-1, 0),
Point3F( 0, 0, 1),
Point3F( 0, 0,-1)
};
static U32 BoxVerts[][4] = {
{7,6,4,5}, // +x
{0,2,3,1}, // -x
{7,3,2,6}, // +y
{0,1,5,4}, // -y
{7,5,1,3}, // +z
{0,4,6,2} // -z
};
static U32 BoxSharedEdgeMask[][6] = {
{0, 0, 1, 4, 8, 2},
{0, 0, 2, 8, 4, 1},
{8, 2, 0, 0, 1, 4},
{4, 1, 0, 0, 2, 8},
{1, 4, 8, 2, 0, 0},
{2, 8, 4, 1, 0, 0}
};
static U32 TerrainSquareIndices[][3] = {
{2, 1, 0}, // 45
{3, 2, 0},
{3, 1, 0}, // 135
{3, 2, 1}
};
static Point3F BoxPnts[] = {
Point3F(0,0,0),
Point3F(0,0,1),
Point3F(0,1,0),
Point3F(0,1,1),
Point3F(1,0,0),
Point3F(1,0,1),
Point3F(1,1,0),
Point3F(1,1,1)
};
extern SceneLighting *gLighting;
extern F32 gParellelVectorThresh;
extern F32 gPlaneNormThresh;
extern F32 gPlaneDistThresh;

View File

@ -0,0 +1,958 @@
//-----------------------------------------------
// Synapse Gaming - Lighting System
// Copyright <20> Synapse Gaming 2003
// Written by John Kabus
//-----------------------------------------------
#include "editor/editTSCtrl.h"
#include "editor/worldEditor.h"
#include "game/shadow.h"
#include "game/vehicles/wheeledVehicle.h"
#include "game/gameConnection.h"
#include "sceneGraph/sceneGraph.h"
#include "terrain/terrRender.h"
#include "game/shapeBase.h"
#include "gui/core/guiCanvas.h"
#include "ts/tsShape.h"
#include "ts/tsShapeInstance.h"
#include "game/staticShape.h"
#include "game/tsStatic.h"
#include "collision/concretePolyList.h"
#include "lightingSystem/sgSceneLighting.h"
#include "lightingSystem/sgLightMap.h"
#include "lightingSystem/sgSceneLightingGlobals.h"
#include "lightingSystem/sgLightingModel.h"
/// adds the ability to bake point lights into interior light maps.
void SceneLighting::InteriorProxy::sgAddLight(LightInfo *light, InteriorInstance *interior)
{
elapsedTime time = elapsedTime("SceneLighting::InteriorProxy::sgAddLight (%d)");
// need this...
sgInterior = interior;
sgLightingModel &model = sgLightingModelManager::sgGetLightingModel(
light->sgLightingModelName);
model.sgSetState(light);
// test for early out...
if(!model.sgCanIlluminate(interior->getWorldBox()))
{
model.sgResetState();
return;
}
model.sgResetState();
sgLights.push_back(light);
// on first light build surface list...
if(sgLights.size() == 1)
{
// stats...
sgStatistics::sgInteriorObjectIncludedCount++;
// get the global shadow casters...
sgShadowObjects::sgGetObjects(interior);
sgClearSurfaces();
sgCurrentSurfaceIndex = 0;
InteriorResource *res = sgInterior->getResource();
U32 countd = res->getNumDetailLevels();
for(U32 d=0; d<countd; d++)
{
Interior *detail = res->getDetailLevel(d);
U32 counti = detail->getSurfaceCount();
U32 offset = sgSurfaces.size();
sgSurfaces.increment(counti);
for(U32 i=0; i<counti; i++)
{
sgSurfaceInfo *info = new sgSurfaceInfo();
sgSurfaces[i + offset] = info;
sgConvertInteriorSurfaceToSurfaceInfo(detail->getSurface(i), i, detail, *info);
}
U32 countsm = detail->getStaticMeshCount();
for(U32 sm=0; sm<countsm; sm++)
{
const ConstructorSimpleMesh *mesh = detail->getStaticMesh(sm);
if(!mesh)
continue;
counti = mesh->primitives.size();
offset = sgSurfaces.size();
sgSurfaces.increment(counti);
for(U32 i=0; i<counti; i++)
{
sgSurfaceInfo *info = new sgSurfaceInfo();
sgSurfaces[i + offset] = info;
sgConvertStaticMeshPrimitiveToSurfaceInfo(mesh, i, detail, *info);
}
}
}
}
// recalc number of surfaces per pass based on new light count...
sgSurfacesPerPass = sgSurfaces.size() / sgLights.size();
}
void SceneLighting::InteriorProxy::light(LightInfo *light)
{
elapsedTime time = elapsedTime("SceneLighting::InteriorProxy::light (%d)");
U32 i;
U32 countthispass = 0;
// stats...
sgStatistics::sgInteriorObjectIlluminationCount++;
for(i=sgCurrentSurfaceIndex; i<sgSurfaces.size(); i++)
{
sgProcessSurface(*sgSurfaces[i]);
countthispass++;
sgCurrentSurfaceIndex++;
if((countthispass >= sgSurfacesPerPass) && (sgLights.last() != light))
break;
}
}
void SceneLighting::InteriorProxy::sgConvertStaticMeshPrimitiveToSurfaceInfo(const ConstructorSimpleMesh *staticmesh, U32 primitiveindex,
Interior *detail, sgSurfaceInfo &surfaceinfo)
{
const ConstructorSimpleMesh::primitive &prim = staticmesh->primitives[primitiveindex];
const MatrixF &transform = sgInterior->getTransform();
const Point3F &scale = sgInterior->getScale();
// need to generate the plane...
AssertFatal((prim.count >= 3), "Primitive with only 2 verts?!?");
Point3F p0 = staticmesh->verts[prim.start];
Point3F p1 = staticmesh->verts[prim.start+1];
Point3F p2 = staticmesh->verts[prim.start+2];
// and it needs to be in interior/object space, not static mesh space...
p0.convolve(staticmesh->scale);
p1.convolve(staticmesh->scale);
p2.convolve(staticmesh->scale);
staticmesh->transform.mulP(p0);
staticmesh->transform.mulP(p1);
staticmesh->transform.mulP(p2);
// generate the plane...
PlaneF plane = PlaneF(p0, p1, p2);
// also need a world space version...
PlaneF projPlane;
mTransformPlane(transform, scale, plane, &projPlane);
//-----------------------------
// get the generic instance 0 lm...
GBitmap *lm = gInteriorLMManager.getBitmap(detail->getLMHandle(), 0, prim.lightMapIndex);
AssertFatal((lm), "Why was there no base light map??");
sgExtractLightingInformation(detail, prim.lightMapEquationX, prim.lightMapEquationY, plane,
Point2I(prim.lightMapOffset.x, prim.lightMapOffset.y), Point2I(prim.lightMapSize.x, prim.lightMapSize.y), Point2I(lm->getWidth(), lm->getHeight()),
surfaceinfo.sgWorldPos,
surfaceinfo.sgSVector,
surfaceinfo.sgTVector,
surfaceinfo.sgLightMapOffset,
surfaceinfo.sgLightMapExtent);
surfaceinfo.sgDetail = detail;
surfaceinfo.sgSurfaceIndex = SG_NULL_SURFACE;
surfaceinfo.sgStaticMesh = (ConstructorSimpleMesh *)staticmesh;
surfaceinfo.sgSurfacePlane = projPlane;
// currently ctor export has no zones...
// when it does this needs to be fixed - also static mesh zone lighting...
surfaceinfo.sgSurfaceOutsideVisible = true;
surfaceinfo.sgLightMapIndex = prim.lightMapIndex;
surfaceinfo.sgTriStrip.clear();
surfaceinfo.sgTriStrip.increment(prim.count);
for(U32 v=0; v<prim.count; v++)
{
U32 index = prim.start + v;
surfaceinfo.sgTriStrip[v].sgVert = staticmesh->verts[index];
surfaceinfo.sgTriStrip[v].sgNorm = staticmesh->norms[index];
surfaceinfo.sgTriStrip[v].sgVert.convolve(staticmesh->scale);
staticmesh->transform.mulP(surfaceinfo.sgTriStrip[v].sgVert);
staticmesh->transform.mulV(surfaceinfo.sgTriStrip[v].sgNorm);
surfaceinfo.sgTriStrip[v].sgVert.convolve(scale);
transform.mulP(surfaceinfo.sgTriStrip[v].sgVert);
transform.mulV(surfaceinfo.sgTriStrip[v].sgNorm);
}
sgReorganizeSurface(surfaceinfo);
}
void SceneLighting::InteriorProxy::sgConvertInteriorSurfaceToSurfaceInfo(const Interior::Surface &surface, U32 i,
Interior *detail, sgSurfaceInfo &surfaceinfo)
{
// points right way?
PlaneF plane = detail->getPlane(surface.planeIndex);
if(Interior::planeIsFlipped(surface.planeIndex))
plane.neg();
const MatrixF &transform = sgInterior->getTransform();
const Point3F &scale = sgInterior->getScale();
PlaneF projPlane;
mTransformPlane(transform, scale, plane, &projPlane);
const Interior::TexGenPlanes & lmTexGenEQ = detail->getLMTexGenEQ(i);
// get the generic instance 0 lm...
U32 lmindex = detail->getNormalLMapIndex(i);
GBitmap *lm = gInteriorLMManager.getBitmap(detail->getLMHandle(), 0, lmindex);
AssertFatal((lm), "Why was there no base light map??");
sgExtractLightingInformation(detail, lmTexGenEQ.planeX, lmTexGenEQ.planeY, plane,
Point2I(surface.mapOffsetX, surface.mapOffsetY), Point2I(surface.mapSizeX, surface.mapSizeY), Point2I(lm->getWidth(), lm->getHeight()),
surfaceinfo.sgWorldPos,
surfaceinfo.sgSVector,
surfaceinfo.sgTVector,
surfaceinfo.sgLightMapOffset,
surfaceinfo.sgLightMapExtent);
surfaceinfo.sgDetail = detail;
surfaceinfo.sgSurfaceIndex = i;
surfaceinfo.sgStaticMesh = NULL;
surfaceinfo.sgSurfacePlane = projPlane;
surfaceinfo.sgSurfaceOutsideVisible = (surface.surfaceFlags & Interior::SurfaceOutsideVisible);
surfaceinfo.sgLightMapIndex = lmindex;
surfaceinfo.sgTriStrip.clear();
surfaceinfo.sgTriStrip.increment(surface.windingCount);
for(U32 v=0; v<surface.windingCount; v++)
{
Point3F &vert = surfaceinfo.sgTriStrip[v].sgVert;
Point3F &norm = surfaceinfo.sgTriStrip[v].sgNorm;
U32 index = detail->getWinding(surface.windingStart + v);
vert = detail->getPoint(index);
norm = detail->getPointNormal(i, v);
vert.convolve(scale);
transform.mulP(vert);
transform.mulV(norm);
}
sgReorganizeSurface(surfaceinfo);
}
void SceneLighting::InteriorProxy::sgReorganizeSurface(sgSurfaceInfo &surfaceinfo)
{
if(surfaceinfo.sgTriStrip.size() < 3)
return;
// create plane from tri...
Vector<sgPlanarLightMap::sgSmoothingVert> &originalstrip = surfaceinfo.sgTriStrip;
PlaneF plane = PlaneF(originalstrip[0].sgVert, originalstrip[1].sgVert, originalstrip[2].sgVert);
Point3F norm = (originalstrip[0].sgNorm + originalstrip[1].sgNorm + originalstrip[2].sgNorm) * 0.3333;
// compare to average normal for reverse winding test...
// if ok then return...
if(mDot(plane, norm) > 0.0f)
return;
// reverse windings...
U32 vertcount = originalstrip.size();
sgPlanarLightMap::sgSmoothingVert tempvert;
// pull verts in pairs and swap...
for(U32 i=2; i<vertcount; i+=2)
{
dMemcpy(&tempvert, &originalstrip[i-1], sizeof(sgPlanarLightMap::sgSmoothingVert));
dMemcpy(&originalstrip[i-1], &originalstrip[i], sizeof(sgPlanarLightMap::sgSmoothingVert));
dMemcpy(&originalstrip[i], &tempvert, sizeof(sgPlanarLightMap::sgSmoothingVert));
}
// if static mesh regenerate the plane...
if(!surfaceinfo.sgStaticMesh)
return;
surfaceinfo.sgSurfacePlane = PlaneF(originalstrip[0].sgVert, originalstrip[1].sgVert, originalstrip[2].sgVert);
}
void SceneLighting::InteriorProxy::sgExtractLightingInformation(const Interior *detail, const PlaneF &lmEqX, const PlaneF &lmEqY, const PlaneF &surfplane,
const Point2I &lmoff, const Point2I &lmext, const Point2I &lmsheetsize,
Point3D &worldpos, Point3D &vectS, Point3D &vectT, Point2I &lmoffactual, Point2I &lmextactual)
{
const MatrixF &transform = sgInterior->getTransform();
const Point3F &scale = sgInterior->getScale();
S32 xlen, ylen, xoff, yoff;
S32 lmborder = detail->getLightMapBorderSize();
xlen = lmext.x + (lmborder * 2);
ylen = lmext.y + (lmborder * 2);
xoff = lmoff.x - lmborder;
yoff = lmoff.y - lmborder;
// very important check!!!
AssertFatal((
((xoff >= 0) && ((xlen + xoff) < lmsheetsize.x)) &&
((yoff >= 0) && ((ylen + yoff) < lmsheetsize.y))), "Light map extents exceeded bitmap size!");
lmoffactual = Point2I(xoff, yoff);
lmextactual = Point2I(xlen, ylen);
const F32 * const lGenX = lmEqX;
const F32 * const lGenY = lmEqY;
AssertFatal((lGenX[0] * lGenX[1] == 0.f) &&
(lGenX[0] * lGenX[2] == 0.f) &&
(lGenX[1] * lGenX[2] == 0.f), "Bad lmTexGen!");
AssertFatal((lGenY[0] * lGenY[1] == 0.f) &&
(lGenY[0] * lGenY[2] == 0.f) &&
(lGenY[1] * lGenY[2] == 0.f), "Bad lmTexGen!");
// get the axis index for the texgens (could be swapped)
S32 si;
S32 ti;
S32 axis = -1;
if(lGenX[0] == 0.f && lGenY[0] == 0.f) // YZ
{
axis = 0;
if(lGenX[1] == 0.f) { // swapped?
si = 2;
ti = 1;
} else {
si = 1;
ti = 2;
}
}
else if(lGenX[1] == 0.f && lGenY[1] == 0.f) // XZ
{
axis = 1;
if(lGenX[0] == 0.f) { // swapped?
si = 2;
ti = 0;
} else {
si = 0;
ti = 2;
}
}
else if(lGenX[2] == 0.f && lGenY[2] == 0.f) // XY
{
axis = 2;
if(lGenX[0] == 0.f) { // swapped?
si = 1;
ti = 0;
} else {
si = 0;
ti = 1;
}
}
AssertFatal(!(axis == -1), "SceneLighting::lightInterior: bad TexGen!");
const F32 * pNormal = ((const F32*)surfplane);
Point3F start;
F32 *pStart = (F32 *)start;
// get the start point on the lightmap
F32 lumelScale = 1 / (lGenX[si] * lmsheetsize.x);
pStart[si] = (((xoff * lumelScale) / (1 / lGenX[si])) - lGenX[3]) / lGenX[si];
pStart[ti] = (((yoff * lumelScale) / (1 / lGenY[ti])) - lGenY[3]) / lGenY[ti];
pStart[axis] = ((pNormal[si] * pStart[si]) + (pNormal[ti] * pStart[ti]) + surfplane.d) / -pNormal[axis];
start.convolve(scale);
transform.mulP(start);
worldpos = Point3D(start.x, start.y, start.z);
// get the s/t vecs oriented on the surface
Point3F vS, vT;
F32 * pSVec = ((F32*)vS);
F32 * pTVec = ((F32*)vT);
// s
pSVec[si] = 1.f;
pSVec[ti] = 0.f;
F32 angle;
Point3F planeNormal = surfplane;
((F32*)planeNormal)[ti] = 0.f;
planeNormal.normalize();
angle = mAcos(mClampF(((F32*)planeNormal)[axis], -1.f, 1.f));
pSVec[axis] = (((F32*)planeNormal)[si] < 0.f) ? mTan(angle) : -mTan(angle);
// t
pTVec[ti] = 1.f;
pTVec[si] = 0.f;
planeNormal = surfplane;
((F32*)planeNormal)[si] = 0.f;
planeNormal.normalize();
angle = mAcos(mClampF(((F32*)planeNormal)[axis], -1.f, 1.f));
pTVec[axis] = (((F32*)planeNormal)[ti] < 0.f) ? mTan(angle) : -mTan(angle);
Point3D vS64 = Point3D(vS.x, vS.y, vS.z);
Point3D vT64 = Point3D(vT.x, vT.y, vT.z);
// scale the vectors
vS64 *= lumelScale;
vT64 *= lumelScale;
Point3D m0 = Point3D(transform[0], transform[1], transform[2]);
Point3D m1 = Point3D(transform[4], transform[5], transform[6]);
Point3D m2 = Point3D(transform[8], transform[9], transform[10]);
Point3D scale64 = Point3D(scale.x, scale.y, scale.z);
vectS.x = mDot(vS64, m0);
vectS.y = mDot(vS64, m1);
vectS.z = mDot(vS64, m2);
vectS.convolve(scale64);
vectT.x = mDot(vT64, m0);
vectT.y = mDot(vT64, m1);
vectT.z = mDot(vT64, m2);
vectT.convolve(scale64);
// project vecs
//transform.mulV(vectS);
//vectS.convolve(scale);
//transform.mulV(vectT);
//vectT.convolve(scale);
}
void SceneLighting::InteriorProxy::sgProcessSurface(sgSurfaceInfo &surfaceinfo)
{
sgPlanarLightMap *lightmap = new sgPlanarLightMap(surfaceinfo.sgLightMapExtent.x, surfaceinfo.sgLightMapExtent.y,
sgInterior, surfaceinfo.sgDetail, surfaceinfo.sgSurfaceIndex, surfaceinfo.sgStaticMesh, surfaceinfo.sgSurfacePlane, surfaceinfo.sgTriStrip);
lightmap->sgWorldPosition = surfaceinfo.sgWorldPos;
lightmap->sgLightMapSVector = surfaceinfo.sgSVector;
lightmap->sgLightMapTVector = surfaceinfo.sgTVector;
lightmap->sgSetupLighting();
for(U32 ii=0; ii<sgLights.size(); ii++)
{
// should we even bother?
LightInfo *light = sgLights[ii];
if(light->mType != LightInfo::Vector)
{
bool valid = false;
if(light->sgLocalAmbientAmount > SG_MIN_LEXEL_INTENSITY)
valid = true;
if(surfaceinfo.sgSurfacePlane.distToPlane(light->mPos) > 0)
valid = true;
for(U32 v=0; v<surfaceinfo.sgTriStrip.size(); v++)
{
sgPlanarLightMap::sgSmoothingVert &vert = surfaceinfo.sgTriStrip[v];
if(mDot(vert.sgNorm, (light->mPos - vert.sgVect)) > 0)
valid = true;
}
if(!valid)
continue;
}
else
{
if(!surfaceinfo.sgSurfaceOutsideVisible)
continue;
}
lightmap->sgCalculateLighting(light);
}
if(lightmap->sgIsDirty())
{
TextureHandle *normHandle = gInteriorLMManager.duplicateBaseLightmap(
surfaceinfo.sgDetail->getLMHandle(), sgInterior->getLMHandle(), surfaceinfo.sgLightMapIndex);
GBitmap *normLightmap = normHandle->getBitmap();
lightmap->sgMergeLighting(normLightmap, surfaceinfo.sgLightMapOffset.x, surfaceinfo.sgLightMapOffset.y);
}
delete lightmap;
}
void SceneLighting::addInterior(ShadowVolumeBSP * shadowVolume, InteriorProxy & interior, LightInfo * light, S32 level)
{
if(light->mType != LightInfo::Vector)
return;
ColorF ambient = light->mAmbient;
bool shadowedTree = true;
// check if just getting shadow detail
if(level == SHADOW_DETAIL)
{
shadowedTree = false;
level = interior->mInteriorRes->getNumDetailLevels() - 1;
}
Interior * detail = interior->mInteriorRes->getDetailLevel(level);
bool hasAlarm = detail->hasAlarmState();
// make sure surfaces do not get processed more than once
BitVector surfaceProcessed;
surfaceProcessed.setSize(detail->mSurfaces.size());
surfaceProcessed.clear();
bool isoutside = false;
for(U32 zone=0; zone<interior->getNumCurrZones(); zone++)
{
if(interior->getCurrZone(zone) == 0)
{
isoutside = true;
break;
}
}
if(!isoutside)
return;
for(U32 i = 0; i < detail->getNumZones(); i++)
{
Interior::Zone & zone = detail->mZones[i];
for(U32 j = 0; j < zone.surfaceCount; j++)
{
U32 surfaceIndex = detail->mZoneSurfaces[zone.surfaceStart + j];
// dont reprocess a surface
if(surfaceProcessed.test(surfaceIndex))
continue;
surfaceProcessed.set(surfaceIndex);
Interior::Surface & surface = detail->mSurfaces[surfaceIndex];
// outside visible?
if(!(surface.surfaceFlags & Interior::SurfaceOutsideVisible))
continue;
// good surface?
PlaneF plane = detail->getPlane(surface.planeIndex);
if(Interior::planeIsFlipped(surface.planeIndex))
plane.neg();
// project the plane
PlaneF projPlane;
mTransformPlane(interior->getTransform(), interior->getScale(), plane, &projPlane);
// fill with ambient? (need to do here, because surface will not be
// added to the SVBSP tree)
F32 dot = mDot(projPlane, light->mDirection);
if(dot > -gParellelVectorThresh)
continue;
ShadowVolumeBSP::SVPoly * poly = buildInteriorPoly(shadowVolume, interior, detail,
surfaceIndex, light, shadowedTree);
// insert it into the SVBSP tree
shadowVolume->insertPoly(poly);
}
}
}
//------------------------------------------------------------------------------
ShadowVolumeBSP::SVPoly * SceneLighting::buildInteriorPoly(ShadowVolumeBSP * shadowVolumeBSP,
InteriorProxy & interior, Interior * detail, U32 surfaceIndex, LightInfo * light,
bool createSurfaceInfo)
{
// transform and add the points...
const MatrixF & transform = interior->getTransform();
const VectorF & scale = interior->getScale();
const Interior::Surface & surface = detail->mSurfaces[surfaceIndex];
ShadowVolumeBSP::SVPoly * poly = shadowVolumeBSP->createPoly();
poly->mWindingCount = surface.windingCount;
// project these points
for(U32 j = 0; j < poly->mWindingCount; j++)
{
Point3F iPnt = detail->mPoints[detail->mWindings[surface.windingStart + j]].point;
Point3F tPnt;
iPnt.convolve(scale);
transform.mulP(iPnt, &tPnt);
poly->mWinding[j] = tPnt;
}
// convert from fan
U32 tmpIndices[ShadowVolumeBSP::SVPoly::MaxWinding];
Point3F fanIndices[ShadowVolumeBSP::SVPoly::MaxWinding];
tmpIndices[0] = 0;
U32 idx = 1;
U32 i;
for(i = 1; i < poly->mWindingCount; i += 2)
tmpIndices[idx++] = i;
for(i = ((poly->mWindingCount - 1) & (~0x1)); i > 0; i -= 2)
tmpIndices[idx++] = i;
idx = 0;
for(i = 0; i < poly->mWindingCount; i++)
if(surface.fanMask & (1 << i))
fanIndices[idx++] = poly->mWinding[tmpIndices[i]];
// set the data
poly->mWindingCount = idx;
for(i = 0; i < poly->mWindingCount; i++)
poly->mWinding[i] = fanIndices[i];
// flip the plane - shadow volumes face inwards
PlaneF plane = detail->getPlane(surface.planeIndex);
if(!Interior::planeIsFlipped(surface.planeIndex))
plane.neg();
// transform the plane
mTransformPlane(transform, scale, plane, &poly->mPlane);
shadowVolumeBSP->buildPolyVolume(poly, light);
// do surface info?
if(createSurfaceInfo)
{
ShadowVolumeBSP::SurfaceInfo * surfaceInfo = new ShadowVolumeBSP::SurfaceInfo;
shadowVolumeBSP->mSurfaces.push_back(surfaceInfo);
// fill it
surfaceInfo->mSurfaceIndex = surfaceIndex;
surfaceInfo->mShadowVolume = shadowVolumeBSP->getShadowVolume(poly->mShadowVolume);
// POLY and POLY node gets it too
ShadowVolumeBSP::SVNode * traverse = shadowVolumeBSP->getShadowVolume(poly->mShadowVolume);
while(traverse->mFront)
{
traverse->mSurfaceInfo = surfaceInfo;
traverse = traverse->mFront;
}
// get some info from the poly node
poly->mSurfaceInfo = traverse->mSurfaceInfo = surfaceInfo;
surfaceInfo->mPlaneIndex = traverse->mPlaneIndex;
}
return(poly);
}
SceneLighting::InteriorProxy::InteriorProxy(SceneObject * obj) :
Parent(obj)
{
mBoxShadowBSP = 0;
sgCurrentSurfaceIndex = 0;
sgSurfacesPerPass = 0;
}
SceneLighting::InteriorProxy::~InteriorProxy()
{
sgClearSurfaces();
delete mBoxShadowBSP;
}
bool SceneLighting::InteriorProxy::loadResources()
{
InteriorInstance * interior = getObject();
if(!interior)
return(false);
Resource<InteriorResource> & interiorRes = interior->getResource();
if(!bool(interiorRes))
return(false);
if(!gInteriorLMManager.loadBaseLightmaps(interiorRes->getDetailLevel(0)->getLMHandle(),
interior->getLMHandle()))
return(false);
return(true);
}
void SceneLighting::InteriorProxy::init()
{
InteriorInstance * interior = getObject();
if(!interior)
return;
// clear out the lightmaps
for(U32 i = 0; i < interior->getResource()->getNumDetailLevels(); i++)
{
Interior * detail = interior->getResource()->getDetailLevel(i);
gInteriorLMManager.clearLightmaps(detail->getLMHandle(), interior->getLMHandle());
}
}
/// reroutes InteriorProxy::preLight for point light and TSStatic support.
bool SceneLighting::InteriorProxy::preLight(LightInfo * light)
{
// create shadow volume of the bounding box of this object
InteriorInstance * interior = getObject();
if(!interior)
return(false);
if(!sgRelightFilter::sgAllowLighting(interior->getWorldBox(), false))
return false;
// build light list...
sgAddLight(light, interior);
return(true);
}
bool SceneLighting::InteriorProxy::isShadowedBy(InteriorProxy * test)
{
// add if overlapping world box
if((*this)->getWorldBox().isOverlapped((*test)->getWorldBox()))
return(true);
// test the box shadow volume
for(U32 i = 0; i < mLitBoxSurfaces.size(); i++)
{
ShadowVolumeBSP::SVPoly * poly = mBoxShadowBSP->copyPoly(mLitBoxSurfaces[i]);
if(test->mBoxShadowBSP->testPoly(poly))
return(true);
}
return(false);
}
void SceneLighting::InteriorProxy::postLight(bool lastLight)
{
delete mBoxShadowBSP;
mBoxShadowBSP = 0;
InteriorInstance * interior = getObject();
if(!interior)
return;
// only rebuild the vertex colors after the last light
if(lastLight)
interior->rebuildVertexColors();
}
//------------------------------------------------------------------------------
U32 SceneLighting::InteriorProxy::getResourceCRC()
{
InteriorInstance * interior = getObject();
if(!interior)
return(0);
return(interior->getCRC());
}
//------------------------------------------------------------------------------
bool SceneLighting::InteriorProxy::setPersistInfo(PersistInfo::PersistChunk * info)
{
if(!Parent::setPersistInfo(info))
return(false);
PersistInfo::InteriorChunk * chunk = dynamic_cast<PersistInfo::InteriorChunk*>(info);
AssertFatal(chunk, "SceneLighting::InteriorProxy::setPersistInfo: invalid info chunk!");
InteriorInstance * interior = getObject();
if(!interior)
return(false);
U32 numDetails = interior->getNumDetailLevels();
// check the lighting method
AssertFatal(SceneLighting::smUseVertexLighting == Interior::smUseVertexLighting, "SceneLighting::InteriorProxy::setPersistInfo: invalid vertex lighting state");
if(SceneLighting::smUseVertexLighting != Interior::smUseVertexLighting)
return(false);
// process the vertex lighting...
if(chunk->mDetailVertexCount.size() != numDetails)
return(false);
AssertFatal(chunk->mVertexColorsNormal.size(), "SceneLighting::InteriorProxy::setPersistInfo: invalid chunk info");
AssertFatal(!chunk->mHasAlarmState || chunk->mVertexColorsAlarm.size(), "SceneLighting::InteriorProxy::setPersistInfo: invalid chunk info");
AssertFatal(!(chunk->mHasAlarmState ^ interior->getDetailLevel(0)->hasAlarmState()), "SceneLighting::InteriorProxy::setPersistInfo: invalid chunk info");
U32 curPos = 0;
for(U32 i = 0; i < numDetails; i++)
{
U32 count = chunk->mDetailVertexCount[i];
Vector<ColorI>* normal = interior->getVertexColorsNormal(i);
Vector<ColorI>* alarm = interior->getVertexColorsAlarm(i);
AssertFatal(normal != NULL && alarm != NULL, "Error, bad vectors returned!");
normal->setSize(count);
dMemcpy(normal->address(), &chunk->mVertexColorsNormal[curPos], count * sizeof(ColorI));
if(chunk->mHasAlarmState)
{
alarm->setSize(count);
dMemcpy(alarm->address(), &chunk->mVertexColorsAlarm[curPos], count * sizeof(ColorI));
}
curPos += count;
}
// need lightmaps?
if(!SceneLighting::smUseVertexLighting)
{
if(chunk->mDetailLightmapCount.size() != numDetails)
return(false);
LM_HANDLE instanceHandle = interior->getLMHandle();
U32 idx = 0;
for(U32 i = 0; i < numDetails; i++)
{
Interior * detail = interior->getDetailLevel(i);
LM_HANDLE interiorHandle = detail->getLMHandle();
Vector<TextureHandle *> & baseHandles = gInteriorLMManager.getHandles(interiorHandle, 0);
if(chunk->mDetailLightmapCount[i] > baseHandles.size())
return(false);
for(U32 j = 0; j < chunk->mDetailLightmapCount[i]; j++)
{
U32 baseIndex = chunk->mDetailLightmapIndices[idx];
if(baseIndex >= baseHandles.size())
return(false);
AssertFatal(chunk->mLightmaps[idx], "SceneLighting::InteriorProxy::setPersistInfo: bunk bitmap!");
if(chunk->mLightmaps[idx]->getWidth() != baseHandles[baseIndex]->getWidth() ||
chunk->mLightmaps[idx]->getHeight() != baseHandles[baseIndex]->getHeight())
return(false);
TextureHandle *tHandle = gInteriorLMManager.duplicateBaseLightmap(interiorHandle, instanceHandle, baseIndex);
// create the diff bitmap
U8 * pDiff = chunk->mLightmaps[idx]->getAddress(0,0);
U8 * pBase = baseHandles[baseIndex]->getBitmap()->getAddress(0,0);
U8 * pDest = tHandle->getBitmap()->getAddress(0,0);
Point2I extent(tHandle->getWidth(), tHandle->getHeight());
for(U32 y = 0; y < extent.y; y++)
{
for(U32 x = 0; x < extent.x; x++)
{
*pDest++ = *pBase++ + *pDiff++;
*pDest++ = *pBase++ + *pDiff++;
*pDest++ = *pBase++ + *pDiff++;
}
}
idx++;
}
}
}
return(true);
}
bool SceneLighting::InteriorProxy::getPersistInfo(PersistInfo::PersistChunk * info)
{
if(!Parent::getPersistInfo(info))
return(false);
PersistInfo::InteriorChunk * chunk = dynamic_cast<PersistInfo::InteriorChunk*>(info);
AssertFatal(chunk, "SceneLighting::InteriorProxy::getPersistInfo: invalid info chunk!");
InteriorInstance * interior = getObject();
if(!interior)
return(false);
LM_HANDLE instanceHandle = interior->getLMHandle();
AssertFatal(!chunk->mDetailLightmapCount.size(), "SceneLighting::InteriorProxy::getPersistInfo: invalid array!");
AssertFatal(!chunk->mDetailLightmapIndices.size(), "SceneLighting::InteriorProxy::getPersistInfo: invalid array!");
AssertFatal(!chunk->mLightmaps.size(), "SceneLighting::InteriorProxy::getPersistInfo: invalid array!");
U32 numDetails = interior->getNumDetailLevels();
U32 i;
for(i = 0; i < numDetails; i++)
{
Interior * detail = interior->getDetailLevel(i);
LM_HANDLE interiorHandle = detail->getLMHandle();
Vector<TextureHandle*> & baseHandles = gInteriorLMManager.getHandles(interiorHandle, 0);
Vector<TextureHandle*> & instanceHandles = gInteriorLMManager.getHandles(interiorHandle, instanceHandle);
U32 litCount = 0;
// walk all the instance lightmaps and grab diff lighting from them
for(U32 j = 0; j < instanceHandles.size(); j++)
{
if(!instanceHandles[j])
continue;
litCount++;
chunk->mDetailLightmapIndices.push_back(j);
GBitmap * baseBitmap = baseHandles[j]->getBitmap();
GBitmap * instanceBitmap = instanceHandles[j]->getBitmap();
Point2I extent(baseBitmap->getWidth(), baseBitmap->getHeight());
GBitmap * diffLightmap = new GBitmap(extent.x, extent.y, false, GBitmap::RGB);
U8 * pBase = baseBitmap->getAddress(0,0);
U8 * pInstance = instanceBitmap->getAddress(0,0);
U8 * pDest = diffLightmap->getAddress(0,0);
// fill the diff lightmap
for(U32 y = 0; y < extent.y; y++)
for(U32 x = 0; x < extent.x; x++)
{
*pDest++ = *pInstance++ - *pBase++;
*pDest++ = *pInstance++ - *pBase++;
*pDest++ = *pInstance++ - *pBase++;
}
chunk->mLightmaps.push_back(diffLightmap);
}
chunk->mDetailLightmapCount.push_back(litCount);
}
// process the vertex lighting...
AssertFatal(!chunk->mDetailVertexCount.size(), "SceneLighting::InteriorProxy::getPersistInfo: invalid chunk info");
AssertFatal(!chunk->mVertexColorsNormal.size(), "SceneLighting::InteriorProxy::getPersistInfo: invalid chunk info");
AssertFatal(!chunk->mVertexColorsAlarm.size(), "SceneLighting::InteriorProxy::getPersistInfo: invalid chunk info");
chunk->mHasAlarmState = interior->getDetailLevel(0)->hasAlarmState();
chunk->mDetailVertexCount.setSize(numDetails);
U32 size = 0;
for(i = 0; i < numDetails; i++)
{
Interior * detail = interior->getDetailLevel(i);
U32 count = detail->getWindingCount();
chunk->mDetailVertexCount[i] = count;
size += count;
}
chunk->mVertexColorsNormal.setSize(size);
if(chunk->mHasAlarmState)
chunk->mVertexColorsAlarm.setSize(size);
U32 curPos = 0;
for(i = 0; i < numDetails; i++)
{
Vector<ColorI>* normal = interior->getVertexColorsNormal(i);
Vector<ColorI>* alarm = interior->getVertexColorsAlarm(i);
AssertFatal(normal != NULL && alarm != NULL, "Error, no normal or alarm vertex colors!");
U32 count = chunk->mDetailVertexCount[i];
dMemcpy(&chunk->mVertexColorsNormal[curPos], normal->address(), count * sizeof(ColorI));
if(chunk->mHasAlarmState)
dMemcpy(&chunk->mVertexColorsAlarm[curPos], alarm->address(), count * sizeof(ColorI));
curPos += count;
}
return(true);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,449 @@
//-----------------------------------------------
// Synapse Gaming - Lighting System
// Copyright <20> Synapse Gaming 2003
// Written by John Kabus
//-----------------------------------------------
#include "dgl/gBitmap.h"
#include "terrain/terrData.h"
#include "lightingSystem/sgScenePersist.h"
#include "lightingSystem/sgSceneLighting.h"
//------------------------------------------------------------------------------
// Class SceneLighting::PersistInfo
//------------------------------------------------------------------------------
U32 PersistInfo::smFileVersion = 0x11;
PersistInfo::~PersistInfo()
{
for(U32 i = 0; i < mChunks.size(); i++)
delete mChunks[i];
}
//------------------------------------------------------------------------------
bool PersistInfo::read(Stream & stream)
{
U32 version;
if(!stream.read(&version) || version != smFileVersion)
return(false);
U32 numChunks;
if(!stream.read(&numChunks))
return(false);
if(numChunks == 0)
return(false);
// read in all the chunks
for(U32 i = 0; i < numChunks; i++)
{
U32 chunkType;
if(!stream.read(&chunkType))
return(false);
// MissionChunk must be first chunk
if(i == 0 && chunkType != PersistChunk::MissionChunkType)
return(false);
if(i != 0 && chunkType == PersistChunk::MissionChunkType)
return(false);
// create the chunk
switch(chunkType)
{
case PersistChunk::MissionChunkType:
mChunks.push_back(new PersistInfo::MissionChunk);
break;
case PersistChunk::InteriorChunkType:
mChunks.push_back(new PersistInfo::InteriorChunk);
break;
case PersistChunk::TerrainChunkType:
mChunks.push_back(new PersistInfo::TerrainChunk);
break;
default:
return(false);
break;
}
// load the chunk info
if(!mChunks[i]->read(stream))
return(false);
}
return(true);
}
bool PersistInfo::write(Stream & stream)
{
if(!stream.write(smFileVersion))
return(false);
if(!stream.write((U32)mChunks.size()))
return(false);
for(U32 i = 0; i < mChunks.size(); i++)
{
if(!stream.write(mChunks[i]->mChunkType))
return(false);
if(!mChunks[i]->write(stream))
return(false);
}
return(true);
}
//------------------------------------------------------------------------------
// Class SceneLighting::PersistInfo::PersistChunk
//------------------------------------------------------------------------------
bool PersistInfo::PersistChunk::read(Stream & stream)
{
if(!stream.read(&mChunkCRC))
return(false);
return(true);
}
bool PersistInfo::PersistChunk::write(Stream & stream)
{
if(!stream.write(mChunkCRC))
return(false);
return(true);
}
//------------------------------------------------------------------------------
// Class SceneLighting::PersistInfo::MissionChunk
//------------------------------------------------------------------------------
PersistInfo::MissionChunk::MissionChunk()
{
mChunkType = PersistChunk::MissionChunkType;
}
//------------------------------------------------------------------------------
// Class SceneLighting::PersistInfo::InteriorChunk
//------------------------------------------------------------------------------
PersistInfo::InteriorChunk::InteriorChunk()
{
mChunkType = PersistChunk::InteriorChunkType;
}
PersistInfo::InteriorChunk::~InteriorChunk()
{
for(U32 i = 0; i < mLightmaps.size(); i++)
delete mLightmaps[i];
}
//------------------------------------------------------------------------------
// - always read in vertex lighting, lightmaps may not be needed
bool PersistInfo::InteriorChunk::read(Stream & stream)
{
if(!Parent::read(stream))
return(false);
U32 size;
U32 i;
// lightmaps->vertex-info
if(!SceneLighting::smUseVertexLighting)
{
// size of this minichunk
if(!stream.read(&size))
return(false);
// lightmaps
stream.read(&size);
mDetailLightmapCount.setSize(size);
for(i = 0; i < size; i++)
if(!stream.read(&mDetailLightmapCount[i]))
return(false);
stream.read(&size);
mDetailLightmapIndices.setSize(size);
for(i = 0; i < size; i++)
if(!stream.read(&mDetailLightmapIndices[i]))
return(false);
if(!stream.read(&size))
return(false);
mLightmaps.setSize(size);
for(i = 0; i < size; i++)
{
mLightmaps[i] = new GBitmap;
if(LightManager::sgAllowFullLightMaps())
{
if(!mLightmaps[i]->readPNG(stream))
return(false);
}
else
{
if(!mLightmaps[i]->read(stream))
return(false);
}
}
}
else
{
// step past the lightmaps
if(!stream.read(&size))
return(false);
if(!stream.setPosition(stream.getPosition() + size))
return(false);
}
// size of the vertex lighting: need to reset stream position after zipStream reading
U32 zipStreamEnd;
if(!stream.read(&zipStreamEnd))
return(false);
zipStreamEnd += stream.getPosition();
// vertex lighting
ZipSubRStream zipStream;
if(!zipStream.attachStream(&stream))
return(false);
if(!zipStream.read(&size))
return(false);
mHasAlarmState = bool(size);
if(!zipStream.read(&size))
return(false);
mDetailVertexCount.setSize(size);
for(i = 0; i < size; i++)
if(!zipStream.read(&mDetailVertexCount[i]))
return(false);
size = 0;
for(i = 0; i < mDetailVertexCount.size(); i++)
size += mDetailVertexCount[i];
mVertexColorsNormal.setSize(size);
if(mHasAlarmState)
mVertexColorsAlarm.setSize(size);
U32 curPos = 0;
for(i = 0; i < mDetailVertexCount.size(); i++)
{
U32 count = mDetailVertexCount[i];
for(U32 j = 0; j < count; j++)
if(!zipStream.read(&mVertexColorsNormal[curPos + j]))
return(false);
// read in the alarm info
if(mHasAlarmState)
{
// same?
if(!zipStream.read(&size))
return(false);
if(bool(size))
dMemcpy(&mVertexColorsAlarm[curPos], &mVertexColorsNormal[curPos], count * sizeof(ColorI));
else
{
for(U32 j = 0; j < count; j++)
if(!zipStream.read(&mVertexColorsAlarm[curPos + j]))
return(false);
}
}
curPos += count;
}
zipStream.detachStream();
// since there is no resizeFilterStream the zipStream happily reads
// off the end of the compressed block... reset the position
stream.setPosition(zipStreamEnd);
return(true);
}
bool PersistInfo::InteriorChunk::write(Stream & stream)
{
if(!Parent::write(stream))
return(false);
// lightmaps
U32 startPos = stream.getPosition();
if(!stream.write(U32(0)))
return(false);
U32 i;
if(!stream.write(U32(mDetailLightmapCount.size())))
return(false);
for(i = 0; i < mDetailLightmapCount.size(); i++)
if(!stream.write(mDetailLightmapCount[i]))
return(false);
if(!stream.write(U32(mDetailLightmapIndices.size())))
return(false);
for(i = 0; i < mDetailLightmapIndices.size(); i++)
if(!stream.write(mDetailLightmapIndices[i]))
return(false);
if(!stream.write(U32(mLightmaps.size())))
return(false);
for(i = 0; i < mLightmaps.size(); i++)
{
AssertFatal(mLightmaps[i], "SceneLighting::SceneLighting::PersistInfo::InteriorChunk::Write: Invalid bitmap!");
if(LightManager::sgAllowFullLightMaps())
{
if(!mLightmaps[i]->writePNG(stream))
return(false);
}
else
{
if(!mLightmaps[i]->write(stream))
return(false);
}
}
// write out the lightmap portions size
U32 endPos = stream.getPosition();
if(!stream.setPosition(startPos))
return(false);
// don't include the offset in the size
if(!stream.write(U32(endPos - startPos - sizeof(U32))))
return(false);
if(!stream.setPosition(endPos))
return(false);
// vertex lighting: needs the size of the vertex info because the
// zip stream may read off the end of the chunk
startPos = stream.getPosition();
if(!stream.write(U32(0)))
return(false);
ZipSubWStream zipStream;
if(!zipStream.attachStream(&stream))
return(false);
if(!zipStream.write(U32(mHasAlarmState)))
return(false);
if(!zipStream.write(U32(mDetailVertexCount.size())))
return(false);
for(U32 i = 0; i < mDetailVertexCount.size(); i++)
if(!zipStream.write(mDetailVertexCount[i]))
return(false);
U32 curPos = 0;
for(i = 0; i < mDetailVertexCount.size(); i++)
{
U32 count = mDetailVertexCount[i];
for(U32 j = 0; j < count; j++)
if(!zipStream.write(mVertexColorsNormal[curPos + j]))
return(false);
// do alarm.. check if the same
if(mHasAlarmState)
{
if(!dMemcmp(&mVertexColorsNormal[curPos], &mVertexColorsAlarm[curPos], count * sizeof(ColorI)))
{
if(!zipStream.write(U32(1)))
return(false);
}
else
{
if(!zipStream.write(U32(0)))
return(false);
for(U32 j = 0; j < count; j++)
if(!zipStream.write(mVertexColorsAlarm[curPos + j]))
return(false);
}
}
curPos += count;
}
zipStream.detachStream();
// write out the vertex lighting portions size
endPos = stream.getPosition();
if(!stream.setPosition(startPos))
return(false);
// don't include the offset in the size
if(!stream.write(U32(endPos - startPos - sizeof(U32))))
return(false);
if(!stream.setPosition(endPos))
return(false);
return(true);
}
//------------------------------------------------------------------------------
// Class SceneLighting::PersistInfo::TerrainChunk
//------------------------------------------------------------------------------
PersistInfo::TerrainChunk::TerrainChunk()
{
mChunkType = PersistChunk::TerrainChunkType;
mLightmap = NULL;
}
PersistInfo::TerrainChunk::~TerrainChunk()
{
if(mLightmap)
delete[] mLightmap;
}
//------------------------------------------------------------------------------
bool PersistInfo::TerrainChunk::read(Stream & stream)
{
if(!Parent::read(stream))
return(false);
GBitmap bitmap;
if(!bitmap.readPNG(stream))
return(false);
if((bitmap.getWidth() != TerrainBlock::LightmapSize) ||
(bitmap.getHeight() != TerrainBlock::LightmapSize) ||
(bitmap.getFormat() != GBitmap::RGB))
return(false);
mLightmap = new U16[TerrainBlock::LightmapSize * TerrainBlock::LightmapSize];
dMemset(mLightmap, 0, sizeof(U16) * TerrainBlock::LightmapSize * TerrainBlock::LightmapSize);
// copy the bitmap: bits should already be clamped
U8 * bp = bitmap.getAddress(0,0);
for(U32 i = 0; i < TerrainBlock::LightmapSize * TerrainBlock::LightmapSize; i++)
{
mLightmap[i] = (U16(bp[0]) << 11) | (U16(bp[1]) << 6) | (U16(bp[2]) << 1) | 1;
bp += 3;
}
return(true);
}
bool PersistInfo::TerrainChunk::write(Stream & stream)
{
if(!Parent::write(stream))
return(false);
if(!mLightmap)
return(false);
// write out an RGB bitmap so it can be PNG compressed
GBitmap bitmap(TerrainBlock::LightmapSize, TerrainBlock::LightmapSize, false, GBitmap::RGB);
U8 * bp = bitmap.getAddress(0,0);
for(U32 i = 0; i < TerrainBlock::LightmapSize * TerrainBlock::LightmapSize; i++)
{
bp[0] = mLightmap[i] >> 11;
bp[1] = (mLightmap[i] >> 6) & 0x1f;
bp[2] = (mLightmap[i] >> 1) & 0x1f;
bp += 3;
}
if(!bitmap.writePNG(stream))
return(false);
return(true);
}

View File

@ -0,0 +1,83 @@
//-----------------------------------------------
// Synapse Gaming - Lighting System
// Copyright <20> Synapse Gaming 2003
// Written by John Kabus
//-----------------------------------------------
#ifndef _SGSCENEPERSIST_H_
#define _SGSCENEPERSIST_H_
#ifndef _SHADOWVOLUMEBSP_H_
#include "sceneGraph/shadowVolumeBSP.h"
#endif
struct PersistInfo
{
struct PersistChunk
{
enum {
MissionChunkType = 0,
InteriorChunkType,
TerrainChunkType,
AtlasLightMapChunkType
};
U32 mChunkType;
U32 mChunkCRC;
virtual ~PersistChunk() {}
virtual bool read(Stream &);
virtual bool write(Stream &);
};
struct MissionChunk : public PersistChunk
{
typedef PersistChunk Parent;
MissionChunk();
};
struct InteriorChunk : public PersistChunk
{
typedef PersistChunk Parent;
InteriorChunk();
~InteriorChunk();
Vector<U32> mDetailLightmapCount;
Vector<U32> mDetailLightmapIndices;
Vector<GBitmap*> mLightmaps;
bool mHasAlarmState;
Vector<U32> mDetailVertexCount;
Vector<ColorI> mVertexColorsNormal;
Vector<ColorI> mVertexColorsAlarm;
bool read(Stream &);
bool write(Stream &);
};
struct TerrainChunk : public PersistChunk
{
typedef PersistChunk Parent;
TerrainChunk();
~TerrainChunk();
U16 *mLightmap;
bool read(Stream &);
bool write(Stream &);
};
~PersistInfo();
Vector<PersistChunk*> mChunks;
static U32 smFileVersion;
bool read(Stream &);
bool write(Stream &);
};
#endif//_SGSCENEPERSIST_H_

673
engine/lightingSystem/volLight.cc Executable file
View File

@ -0,0 +1,673 @@
/////////////////////////////////////////////////////////////////
// Parashar Krishnamachari
// Volume Light class for integration into Torque Game Engine
/////////////////////////////////////////////////////////////////
#include "console/consoleTypes.h"
#include "dgl/dgl.h"
#include "core/bitStream.h"
#include "game/gameConnection.h"
#include "sceneGraph/sceneGraph.h"
#include "volLight.h"
#include "platform/event.h"
#include "platform/gameInterface.h"
IMPLEMENT_CO_NETOBJECT_V1(volumeLight);
volumeLight::volumeLight()
{
// Setup NetObject.
mTypeMask |= StaticObjectType | StaticTSObjectType | StaticRenderedObjectType;
mNetFlags.set(Ghostable | ScopeAlways);
mAddedToScene = false;
mLastRenderTime = 0;
mLightHandle = NULL;
mLTextureName = StringTable->insert("");
mlpDistance = 8.0f;
mShootDistance = 15.0f;
mXextent = 6.0f;
mYextent = 6.0f;
mSubdivideU = 32;
mSubdivideV = 32;
mfootColour = ColorF(1.f, 1.f, 1.f, 0.2f);
mtailColour = ColorF(0.f, 0.f, 0.f, 0.0f);
}
volumeLight::~volumeLight()
{
}
///////////////////////////////////////////////////////////////////////////////
// NetObject functions
///////////////////////////////////////////////////////////////////////////////
U32 volumeLight::packUpdate(NetConnection * con, U32 mask, BitStream * stream)
{
// Pack Parent.
U32 retMask = Parent::packUpdate(con, mask, stream);
// Position.and rotation from Parent
stream->writeAffineTransform(mObjToWorld);
// Light Field Image
stream->writeString(mLTextureName);
// Dimensions
stream->write(mlpDistance);
stream->write(mShootDistance);
stream->write(mXextent);
stream->write(mYextent);
// Subdivisions
stream->write(mSubdivideU);
stream->write(mSubdivideV);
// Colors
stream->write(mfootColour);
stream->write(mtailColour);
return retMask;
}
void volumeLight::unpackUpdate(NetConnection * con, BitStream * stream)
{
// Unpack Parent.
Parent::unpackUpdate(con, stream);
MatrixF ObjectMatrix;
// Position.and rotation
stream->readAffineTransform(&ObjectMatrix);
// Light Field Image
setLtexture(stream->readSTString());
// Dimensions
stream->read(&mlpDistance);
stream->read(&mShootDistance);
stream->read(&mXextent);
stream->read(&mYextent);
// Subdivisions
stream->read(&mSubdivideU);
stream->read(&mSubdivideV);
// Colors
stream->read(&mfootColour);
stream->read(&mtailColour);
// Set Transform.
setTransform(ObjectMatrix);
// Very rough, and not complete estimate of the bounding box.
// A complete one would actually shoot out rays from the hypothetical lightpoint
// through the vertices to find the extents of the light volume.
// But there's no point doing so here. There's no real collision with
// beams of light.
buildObjectBox();
// Set the Render Transform.
setRenderTransform(mObjToWorld);
}
///////////////////////////////////////////////////////////////////////////////
// Set Value functions (internal to class)
///////////////////////////////////////////////////////////////////////////////
void volumeLight::setLtexture(const char *name)
{
mLTextureName = StringTable->insert(name);
mLightHandle = NULL;
if (*mLTextureName)
{
mLightHandle = TextureHandle(mLTextureName, BitmapTexture, true);
}
// Set Config Change Mask.
if (isServerObject()) setMaskBits(volLightMask);
}
void volumeLight::setlpDistance(F32 Dist)
{
mlpDistance = Dist;
// Set Config Change Mask.
if (isServerObject()) setMaskBits(volLightMask);
}
void volumeLight::setShootDistance(F32 Dist)
{
mShootDistance = Dist;
buildObjectBox();
// Set the Render Transform.
setRenderTransform(mObjToWorld);
// Set Config Change Mask.
if (isServerObject()) setMaskBits(volLightMask);
}
void volumeLight::setXextent(F32 extent)
{
mXextent = extent;
buildObjectBox();
// Set the Render Transform.
setRenderTransform(mObjToWorld);
// Set Config Change Mask.
if (isServerObject()) setMaskBits(volLightMask);
}
void volumeLight::setYextent(F32 extent)
{
mYextent = extent;
buildObjectBox();
// Set the Render Transform.
setRenderTransform(mObjToWorld);
// Set Config Change Mask.
if (isServerObject()) setMaskBits(volLightMask);
}
void volumeLight::setSubdivideU(U32 val)
{
mSubdivideU = val;
// Set Config Change Mask.
if (isServerObject()) setMaskBits(volLightMask);
}
void volumeLight::setSubdivideV(U32 val)
{
mSubdivideV = val;
// Set Config Change Mask.
if (isServerObject()) setMaskBits(volLightMask);
}
void volumeLight::setfootColour(ColorF col)
{
mfootColour = col;
// Set Config Change Mask.
if (isServerObject()) setMaskBits(volLightMask);
}
void volumeLight::settailColour(ColorF col)
{
mtailColour = col;
// Set Config Change Mask.
if (isServerObject()) setMaskBits(volLightMask);
}
///////////////////////////////////////////////////////////////////////////////
// Set Value functions (external interfaces for scripts)
///////////////////////////////////////////////////////////////////////////////
static void csetLTexture(SimObject * obj, S32, const char ** argv)
{
volumeLight *vlight = static_cast<volumeLight*>(obj);
if (!vlight) return;
vlight->setLtexture(argv[2]);
}
static void csetlpDistance(SimObject * obj, S32, const char ** argv)
{
volumeLight *vlight = static_cast<volumeLight*>(obj);
if (!vlight)
return;
vlight->setlpDistance(dAtof(argv[2]));
}
static void csetShootDistance(SimObject * obj, S32, const char ** argv)
{
volumeLight *vlight = static_cast<volumeLight*>(obj);
if (!vlight)
return;
vlight->setShootDistance(dAtof(argv[2]));
}
static void csetXextent(SimObject * obj, S32, const char ** argv)
{
volumeLight *vlight = static_cast<volumeLight*>(obj);
if (!vlight)
return;
vlight->setXextent(dAtof(argv[2]));
}
static void csetYextent(SimObject * obj, S32, const char ** argv)
{
volumeLight *vlight = static_cast<volumeLight*>(obj);
if (!vlight)
return;
vlight->setYextent(dAtof(argv[2]));
}
static void csetSubdivideU(SimObject * obj, S32, const char ** argv)
{
volumeLight *vlight = static_cast<volumeLight*>(obj);
if (!vlight)
return;
vlight->setSubdivideU(dAtoi(argv[2]));
}
static void csetSubdivideV(SimObject * obj, S32, const char ** argv)
{
volumeLight *vlight = static_cast<volumeLight*>(obj);
if (!vlight)
return;
vlight->setSubdivideV(dAtoi(argv[2]));
}
static void csetfootColour(SimObject * obj, S32, const char ** argv)
{
volumeLight *vlight = static_cast<volumeLight*>(obj);
if (!vlight)
return;
vlight->setfootColour(ColorF(dAtof(argv[2]),dAtof(argv[3]),dAtof(argv[4]),dAtof(argv[5])));
}
static void csettailColour(SimObject * obj, S32, const char ** argv)
{
volumeLight *vlight = static_cast<volumeLight*>(obj);
if (!vlight)
return;
vlight->settailColour(ColorF(dAtof(argv[2]),dAtof(argv[3]),dAtof(argv[4]),dAtof(argv[5])));
}
///////////////////////////////////////////////////////////////////////////////
// SimObject functions
///////////////////////////////////////////////////////////////////////////////
bool volumeLight::onAdd()
{
// Add Parent.
if(!Parent::onAdd())
return(false);
buildObjectBox();
// Set the Render Transform.
setRenderTransform(mObjToWorld);
mAddedToScene = true;
return true;
}
void volumeLight::onRemove()
{
mAddedToScene = false;
// remove the texture handle
mLightHandle = NULL;
// Do Parent.
Parent::onRemove();
}
void volumeLight::inspectPostApply()
{
// Reset the World Box.
resetWorldBox();
// Set the Render Transform.
setRenderTransform(mObjToWorld);
// Set Parent.
Parent::inspectPostApply();
setMaskBits(volLightMask);
}
///////////////////////////////////////////////////////////////////////////////
// SceneObject functions -- The only meaty part
///////////////////////////////////////////////////////////////////////////////
bool volumeLight::prepRenderImage(SceneState *state, const U32 stateKey, const U32 startZone, const bool modifyBaseZoneState)
{
// Return if last state.
if (isLastState(state, stateKey))
return false;
// Set Last State.
setLastState(state, stateKey);
// no need to render if it isn't enabled
if((!mEnable) || (!mLightHandle))
return false;
// Is Object Rendered?
if (state->isObjectRendered(this))
{
// Yes, so get a SceneRenderImage.
SceneRenderImage* image = new SceneRenderImage;
// Populate it.
image->obj = this;
image->isTranslucent = true;
image->sortType = SceneRenderImage::Point;
state->setImageRefPoint(this, image);
// Insert it into the scene images.
state->insertRenderImage(image);
}
return false;
}
void volumeLight::renderObject(SceneState *state, SceneRenderImage *image)
{
Parent::renderObject(state, image);
// Check we are in Canonical State.
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on entry");
// Check that we have a texture
AssertFatal(mLightHandle, "Error : No texture loaded or file failed to open");
//////////////////////////// -- Entry assertions
// Calculate Elapsed Time and take new Timestamp.
S32 Time = Platform::getVirtualMilliseconds();
// F32 ElapsedTime = (Time - mLastRenderTime) * 0.001f;
mLastRenderTime = Time;
RectI viewport;
MatrixF RXF;
Point3F position;
// Setup out the Projection Matrix/Viewport.
glMatrixMode(GL_PROJECTION);
glPushMatrix();
dglGetViewport(&viewport);
state->setupBaseProjection();
// Remember -- SetupBaseProjection leaves current matrix mode as MODELVIEW when done.
// Save ModelView Matrix so we can restore Canonical state at exit.
glPushMatrix();
// Transform by the objects' transform e.g move it.
RXF = getTransform();
RXF.getColumn(3, &position);
dglMultMatrix(&RXF);
// Draw the damn thing
renderGL(state, image);
//////////////////////////// -- Exit assertions
// Restore rendering state.
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glEnable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
// Restore our nice, friendly and dull canonical state.
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
dglSetViewport(viewport);
// Check we have restored Canonical State.
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on exit");
}
void volumeLight::sgRenderY(const Point3F &near1, const Point3F &far1, const Point3F &far2,
const ColorF &nearcol, const ColorF &farcol, F32 offset)
{
glBegin(GL_QUADS);
glColor4f(nearcol.red, nearcol.green, nearcol.blue, nearcol.alpha);
glTexCoord2f(offset, 0.0);
glVertex3f(near1.x, -near1.y, 0.0f);
glColor4f(nearcol.red, nearcol.green, nearcol.blue, nearcol.alpha);
glTexCoord2f(offset, 0.5);
glVertex3f(near1.x, 0.0f, 0.0f);
glColor4f(farcol.red, farcol.green, farcol.blue, farcol.alpha);
glTexCoord2f(offset, 0.5);
glVertex3f(far1.x, 0.0, far1.z);
glColor4f(farcol.red, farcol.green, farcol.blue, farcol.alpha);
glTexCoord2f(offset, 0.0);
glVertex3f(far1.x, far1.y, far1.z);
glEnd();
glBegin(GL_QUADS);
glColor4f(farcol.red, farcol.green, farcol.blue, farcol.alpha);
glTexCoord2f(offset, 0.5);
glVertex3f(far1.x, 0.0, far1.z);
glColor4f(nearcol.red, nearcol.green, nearcol.blue, nearcol.alpha);
glTexCoord2f(offset, 0.5);
glVertex3f(near1.x, 0.0f, 0.0f);
glColor4f(nearcol.red, nearcol.green, nearcol.blue, nearcol.alpha);
glTexCoord2f(offset, 1.0);
glVertex3f(near1.x, near1.y, 0.0f);
glColor4f(farcol.red, farcol.green, farcol.blue, farcol.alpha);
glTexCoord2f(offset, 1.0);
glVertex3f(far2.x, far2.y, far2.z);
glEnd();
}
void volumeLight::sgRenderX(const Point3F &near1, const Point3F &far1, const Point3F &far2,
const ColorF &nearcol, const ColorF &farcol, F32 offset)
{
glBegin(GL_QUADS);
glColor4f(nearcol.red, nearcol.green, nearcol.blue, nearcol.alpha);
glTexCoord2f(0.0, offset);
glVertex3f(-near1.x, near1.y, 0.0f);
glColor4f(nearcol.red, nearcol.green, nearcol.blue, nearcol.alpha);
glTexCoord2f(0.5, offset);
glVertex3f(0.0f, near1.y, 0.0f);
glColor4f(farcol.red, farcol.green, farcol.blue, farcol.alpha);
glTexCoord2f(0.5, offset);
glVertex3f(0.0, far1.y, far1.z);
glColor4f(farcol.red, farcol.green, farcol.blue, farcol.alpha);
glTexCoord2f(0.0, offset);
glVertex3f(far1.x, far1.y, far1.z);
glEnd();
glBegin(GL_QUADS);
glColor4f(farcol.red, farcol.green, farcol.blue, farcol.alpha);
glTexCoord2f(0.5, offset);
glVertex3f(0.0, far1.y, far1.z);
glColor4f(nearcol.red, nearcol.green, nearcol.blue, nearcol.alpha);
glTexCoord2f(0.5, offset);
glVertex3f(0.0f, near1.y, 0.0f);
glColor4f(nearcol.red, nearcol.green, nearcol.blue, nearcol.alpha);
glTexCoord2f(1.0, offset);
glVertex3f(near1.x, near1.y, 0.0f);
glColor4f(farcol.red, farcol.green, farcol.blue, farcol.alpha);
glTexCoord2f(1.0, offset);
glVertex3f(far2.x, far2.y, far2.z);
glEnd();
}
///////////////////////////////////////////////////////////////////////////////
// GL Render function...
///////////////////////////////////////////////////////////////////////////////
void volumeLight::renderGL(SceneState *state, SceneRenderImage *image)
{
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glBindTexture(GL_TEXTURE_2D, mLightHandle.getGLName());
Point3F lightpoint;
// This is where the hypothetical point source of the spot will be
// The volume slices are projected along the lines from
lightpoint.x = lightpoint.y = 0.0f;
lightpoint.z = -mlpDistance;
F32 ax = mXextent / 2;
F32 ay = mYextent / 2;
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
// Draw the bottom foot... this is basically the glowing region.
glBegin(GL_QUADS);
glColor4f(mfootColour.red, mfootColour.green, mfootColour.blue, 1.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-ax, -ay, 0.0f);
glColor4f(mfootColour.red, mfootColour.green, mfootColour.blue, 1.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(ax, -ay, 0.0f);
glColor4f(mfootColour.red, mfootColour.green, mfootColour.blue, 1.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(ax, ay, 0.0f);
glColor4f(mfootColour.red, mfootColour.green, mfootColour.blue, 1.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-ax, ay, 0.0f);
glEnd();
S32 i;
glDepthMask(GL_FALSE);
// Slices in X/U space
for(i = mSubdivideU; i >= 0; i--)
{
F32 k = ((F32)i) / mSubdivideU; // use for the texture coord
F32 bx = i * mXextent / mSubdivideU - ax; // use for point positions
// These are the two endpoints for a slice at the foot
Point3F end1(bx, -ay, 0.0f);
Point3F end2(bx, ay, 0.0f);
end1 -= lightpoint; // get a vector from point to lightsource
end1.normalize(); // normalize vector
end1 *= mShootDistance; // multiply it out by shootlength
end1.x += bx; // Add the original point location to the vector
end1.y -= ay;
// Do it again for the other point.
end2 -= lightpoint;
end2.normalize();
end2 *= mShootDistance;
end2.x += bx;
end2.y += ay;
sgRenderY(Point3F(bx, ay, 0.0f), end1, end2, mfootColour, mtailColour, k);
}
// Slices in Y/V space
for(i = 0; i <= mSubdivideV; i++)
{
F32 k = ((F32)i) / mSubdivideV; // use for the texture coord
F32 by = i * mXextent / mSubdivideV - ay; // use for point positions
// These are the two endpoints for a slice at the foot
Point3F end1(-ax, by, 0.0f);
Point3F end2(ax, by, 0.0f);
end1 -= lightpoint; // get a vector from point to lightsource
end1.normalize(); // normalize vector
end1 *= mShootDistance; // extend it out by shootlength
end1.x -= ax; // Add the original point location to the vector
end1.y += by;
// Do it again for the other point.
end2 -= lightpoint;
end2.normalize();
end2 *= mShootDistance;
end2.x += ax;
end2.y += by;
sgRenderX(Point3F(ax, by, 0.0f), end1, end2, mfootColour, mtailColour, k);
}
glDepthMask(GL_TRUE);
}
///////////////////////////////////////////////////////////////////////////////
// ConObject functions
///////////////////////////////////////////////////////////////////////////////
void volumeLight::initPersistFields()
{
// Initialise parents' persistent fields.
Parent::initPersistFields();
// Our own persistent fields
// Light Field Image
addField( "Texture", TypeFilename, Offset( mLTextureName, volumeLight ) );
// Dimensions
addField( "lpDistance", TypeF32, Offset( mlpDistance, volumeLight ) );
addField( "ShootDistance", TypeF32, Offset( mShootDistance, volumeLight ) );
addField( "Xextent", TypeF32, Offset( mXextent, volumeLight ) );
addField( "Yextent", TypeF32, Offset( mYextent, volumeLight ) );
// Subdivisions
addField( "SubdivideU", TypeS32, Offset( mSubdivideU, volumeLight ) );
addField( "SubdivideV", TypeS32, Offset( mSubdivideV, volumeLight ) );
// Colors
addField( "FootColour", TypeColorF, Offset( mfootColour, volumeLight ) );
addField( "TailColour", TypeColorF, Offset( mtailColour, volumeLight ) );
}
void volumeLight::consoleInit()
{
// Light Field Image
Con::addCommand("volumeLight", "setLTexture", csetLTexture, "vlight.setTexture(bitmap)", 3, 3);
// Dimensions
Con::addCommand("volumeLight", "setlpDistance", csetlpDistance, "vlight.setlpDistance(value)", 3, 3);
Con::addCommand("volumeLight", "setShootDistance", csetShootDistance, "vlight.setShootDistance(value)", 3, 3);
Con::addCommand("volumeLight", "setXextent", csetXextent, "vlight.setXextent(value)", 3, 3);
Con::addCommand("volumeLight", "setYextent", csetYextent, "vlight.setYextent(value)", 3, 3);
// Subdivisions
Con::addCommand("volumeLight", "setSubdivideU", csetSubdivideU, "vlight.setSubdivideU(value)", 3, 3);
Con::addCommand("volumeLight", "setSubdivideV", csetSubdivideV, "vlight.setSubdivideV(value)", 3, 3);
// Colors
Con::addCommand("volumeLight", "setfootColour", csetfootColour, "vlight.setfootColour(r, g, b, a)", 6, 6);
Con::addCommand("volumeLight", "settailColour", csetfootColour, "vlight.settailColour(r, g, b, a)", 6, 6);
}

103
engine/lightingSystem/volLight.h Executable file
View File

@ -0,0 +1,103 @@
/////////////////////////////////////////////////////////////////
// Parashar Krishnamachari
// Volume Light class for integration into Torque Game Engine
/////////////////////////////////////////////////////////////////
#ifndef _VOLLIGHT_H_
#define _VOLLIGHT_H_
#ifndef _SCENEOBJECT_H_
#include "sim/sceneObject.h"
#endif
#include "lightingSystem/sgLightObject.h"
class volumeLight : public sgLightObject
{
private:
typedef sgLightObject Parent;
public:
void buildObjectBox()
{
mObjBox.min.set(-mXextent, -mYextent, -mShootDistance);
mObjBox.max.set(mXextent, mYextent, mShootDistance);
resetWorldBox();
}
void sgRenderX(const Point3F &near1, const Point3F &far1, const Point3F &far2,
const ColorF &nearcol, const ColorF &farcol, F32 offset);
void sgRenderY(const Point3F &near1, const Point3F &far1, const Point3F &far2,
const ColorF &nearcol, const ColorF &farcol, F32 offset);
protected :
enum { volLightMask = (1 << 0),
volLightOther = (1 << 1) };
bool mAddedToScene;
S32 mLastRenderTime;
TextureHandle mLightHandle; // Light beam texture used.
public :
volumeLight();
~volumeLight();
// SceneObject functions
void renderObject(SceneState*, SceneRenderImage*);
void renderGL(SceneState*, SceneRenderImage*);
virtual bool prepRenderImage(SceneState*, const U32 stateKey, const U32 startZone, const bool modifyBaseZoneState = false);
// SimObject functions
bool onAdd();
void onRemove();
void inspectPostApply();
// NetObject functions
U32 packUpdate(NetConnection *, U32, BitStream *);
void unpackUpdate(NetConnection *, BitStream *);
// ConObject functions
static void consoleInit();
static void initPersistFields();
void setLtexture(const char *name);
void setlpDistance(F32 Dist);
void setShootDistance(F32 Dist);
void setXextent(F32 extent);
void setYextent(F32 extent);
void setSubdivideU(U32 val);
void setSubdivideV(U32 val);
void setfootColour(ColorF col);
void settailColour(ColorF col);
DECLARE_CONOBJECT(volumeLight);
StringTableEntry mLTextureName; // Filename for light texture
F32 mlpDistance; // Distance to hypothetical lightsource point -- affects fov angle
F32 mShootDistance; // Distance of shooting -- Length of beams
F32 mXextent; // xExtent and yExtent determine the size/dimension of the plane
F32 mYextent;
U32 mSubdivideU; // Number of subdivisions in U and V space.
U32 mSubdivideV; // Controls the number of "slices" in the volume.
// NOTE : Total number of polygons = 2 + ((mSubdiveU + 1) + (mSubdivideV + 1)) * 2
// Each slice being a quad plus the rectangular plane at the bottom.
ColorF mfootColour; // Color at the source
ColorF mtailColour; // Color at the end.
// For normal operation, we'll just have white with alpha 0.2 at the source
// and white with alpha 0 at the ends. Moreover, we can have individual color in
// the texture, but this will allow us to affect things ever so slightly and
// tint the beams a little bit.
};
#endif // _VOLLIGHT_H_