added everything
This commit is contained in:
36
engine/lightingSystem/sgBinaryVolumePartitionTree.cc
Executable file
36
engine/lightingSystem/sgBinaryVolumePartitionTree.cc
Executable 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"
|
||||
|
||||
|
||||
|
||||
|
276
engine/lightingSystem/sgBinaryVolumePartitionTree.h
Executable file
276
engine/lightingSystem/sgBinaryVolumePartitionTree.h
Executable 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_
|
||||
|
188
engine/lightingSystem/sgD3DCompatibility.cc
Executable file
188
engine/lightingSystem/sgD3DCompatibility.cc
Executable 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];
|
||||
}
|
47
engine/lightingSystem/sgD3DCompatibility.h
Executable file
47
engine/lightingSystem/sgD3DCompatibility.h
Executable 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_
|
308
engine/lightingSystem/sgDecalProjector.cc
Executable file
308
engine/lightingSystem/sgDecalProjector.cc
Executable 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);
|
||||
}
|
||||
|
16
engine/lightingSystem/sgDecalProjector.h
Executable file
16
engine/lightingSystem/sgDecalProjector.h
Executable 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_
|
228
engine/lightingSystem/sgDetailMapping.cc
Executable file
228
engine/lightingSystem/sgDetailMapping.cc
Executable 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);
|
||||
}
|
||||
|
31
engine/lightingSystem/sgDetailMapping.h
Executable file
31
engine/lightingSystem/sgDetailMapping.h
Executable 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_
|
92
engine/lightingSystem/sgHashMap.h
Executable file
92
engine/lightingSystem/sgHashMap.h
Executable 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_
|
882
engine/lightingSystem/sgLightManager.cc
Executable file
882
engine/lightingSystem/sgLightManager.cc
Executable 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);
|
||||
}
|
||||
}
|
||||
|
426
engine/lightingSystem/sgLightManager.h
Executable file
426
engine/lightingSystem/sgLightManager.h
Executable 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_
|
1286
engine/lightingSystem/sgLightMap.cc
Executable file
1286
engine/lightingSystem/sgLightMap.cc
Executable file
File diff suppressed because it is too large
Load Diff
223
engine/lightingSystem/sgLightMap.h
Executable file
223
engine/lightingSystem/sgLightMap.h
Executable 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_
|
633
engine/lightingSystem/sgLightObject.cc
Executable file
633
engine/lightingSystem/sgLightObject.cc
Executable 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);
|
||||
|
166
engine/lightingSystem/sgLightObject.h
Executable file
166
engine/lightingSystem/sgLightObject.h
Executable 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_
|
99
engine/lightingSystem/sgLighting.h
Executable file
99
engine/lightingSystem/sgLighting.h
Executable 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_
|
615
engine/lightingSystem/sgLightingModel.cc
Executable file
615
engine/lightingSystem/sgLightingModel.cc
Executable 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;
|
||||
}*/
|
||||
}
|
270
engine/lightingSystem/sgLightingModel.h
Executable file
270
engine/lightingSystem/sgLightingModel.h
Executable 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_
|
110
engine/lightingSystem/sgMissionLightingFilter.cc
Executable file
110
engine/lightingSystem/sgMissionLightingFilter.cc
Executable 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);
|
||||
}
|
||||
|
||||
|
71
engine/lightingSystem/sgMissionLightingFilter.h
Executable file
71
engine/lightingSystem/sgMissionLightingFilter.h
Executable 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_
|
524
engine/lightingSystem/sgObjectShadows.cc
Executable file
524
engine/lightingSystem/sgObjectShadows.cc
Executable 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);
|
||||
}
|
||||
|
85
engine/lightingSystem/sgObjectShadows.h
Executable file
85
engine/lightingSystem/sgObjectShadows.h
Executable 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_
|
1111
engine/lightingSystem/sgSceneLighting.cc
Executable file
1111
engine/lightingSystem/sgSceneLighting.cc
Executable file
File diff suppressed because it is too large
Load Diff
374
engine/lightingSystem/sgSceneLighting.h
Executable file
374
engine/lightingSystem/sgSceneLighting.h
Executable 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_
|
58
engine/lightingSystem/sgSceneLightingGlobals.h
Executable file
58
engine/lightingSystem/sgSceneLightingGlobals.h
Executable 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;
|
||||
|
958
engine/lightingSystem/sgSceneLightingInterior.cc
Executable file
958
engine/lightingSystem/sgSceneLightingInterior.cc
Executable 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);
|
||||
}
|
1025
engine/lightingSystem/sgSceneLightingTerrain.cc
Executable file
1025
engine/lightingSystem/sgSceneLightingTerrain.cc
Executable file
File diff suppressed because it is too large
Load Diff
449
engine/lightingSystem/sgScenePersist.cc
Executable file
449
engine/lightingSystem/sgScenePersist.cc
Executable 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);
|
||||
}
|
||||
|
||||
|
||||
|
83
engine/lightingSystem/sgScenePersist.h
Executable file
83
engine/lightingSystem/sgScenePersist.h
Executable 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
673
engine/lightingSystem/volLight.cc
Executable 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
103
engine/lightingSystem/volLight.h
Executable 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_
|
Reference in New Issue
Block a user