123
This commit is contained in:
8
Editor/LightmapCompiler/GLMInfo.cpp
Normal file
8
Editor/LightmapCompiler/GLMInfo.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// Crytek CryENGINE source code
|
||||
// History:
|
||||
// - Created by Michael Glueck
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "GLMInfo.h"
|
||||
33
Editor/LightmapCompiler/GLMInfo.h
Normal file
33
Editor/LightmapCompiler/GLMInfo.h
Normal file
@@ -0,0 +1,33 @@
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// Crytek CryENGINE source code
|
||||
// History:
|
||||
// - Created by Michael Glueck
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
#pragma once
|
||||
|
||||
class GLMInfo
|
||||
{
|
||||
protected:
|
||||
//info for one particular patch
|
||||
typedef struct GLMInfoPatch
|
||||
{
|
||||
unsigned int uiOffsetX;
|
||||
unsigned int uiOffsetY;
|
||||
unsigned int uiWidth;
|
||||
unsigned int uiHeight;
|
||||
}GLMInfoPatch;
|
||||
|
||||
//info struct for one GLM
|
||||
typedef struct GLMInfoMesh
|
||||
{
|
||||
CString GLMName;
|
||||
unsigned int uiLMIndex;
|
||||
std::vector<GLMInfoPatch> vPatchInfos;
|
||||
}GLMInfoMesh;
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
852
Editor/LightmapCompiler/IndoorLightPatches.h
Normal file
852
Editor/LightmapCompiler/IndoorLightPatches.h
Normal file
@@ -0,0 +1,852 @@
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// Crytek CryENGINE source code
|
||||
// History:
|
||||
// - Created by Marco Corbetta
|
||||
// - Changed by Tim Schroeder
|
||||
// - Partial rewrite for editor integration
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
#pragma once
|
||||
|
||||
#ifndef __INDOOR_LIGHT_PATCHES_H__
|
||||
#define __INDOOR_LIGHT_PATCHES_H__
|
||||
|
||||
//#define REDUCE_DOT3LIGHTMAPS_TO_CLASSIC // for debugging
|
||||
//#define DISPLAY_MORE_INFO
|
||||
|
||||
//typedef float real;
|
||||
typedef double real;//typedef controlling the accuracy
|
||||
|
||||
#define HDR_EXP_BASE (1.04)
|
||||
#define HDR_EXP_OFFSET (64.0)
|
||||
#define HDR_LOG(a, b) ( log(b) / log(a) )
|
||||
|
||||
#include <float.h>
|
||||
#include "LMCompCommon.h"
|
||||
#include "LMCompStructures.h"
|
||||
#include "IEntityRenderstate.h"
|
||||
#include "LMLightCollection.h"
|
||||
#include "..\Objects\BrushObject.h"
|
||||
#include "I3dEngine.h"
|
||||
#include <direct.h>
|
||||
|
||||
static const float scfMaxGridSize = 2.f;
|
||||
|
||||
#define MIN_LIGHTMAP_SIZE 4
|
||||
|
||||
//flags for CRadPoly
|
||||
#define NOLIGHTMAP_FLAG 1
|
||||
#define MERGE_FLAG 2
|
||||
#define SHARED_FLAG 4
|
||||
#define MERGE_SOURCE_FLAG 8
|
||||
#define DECAL_FLAG 64
|
||||
#define DO_NOT_COMPRESS_FLAG 128 //flag for patches
|
||||
|
||||
|
||||
#define WRONG_NORMALS_FLAG 16
|
||||
#define NOT_NORMALIZED_NORMALS_FLAG 32
|
||||
#define ONLY_SUNLIGHT 256 //flag for mesh
|
||||
#define DOUBLE_SIDED_MAT 512 //flag for mesh
|
||||
#define REBUILD_USED 1024 //flag for mesh
|
||||
#define CAST_LIGHTMAP 2048 //flag for mesh
|
||||
#define RECEIVES_SUNLIGHT 4096 //flag for mesh
|
||||
#define HASH_CHANGED 8192 //flag for mesh
|
||||
#define RECEIVES_LIGHTMAP (8192<<1) //flag for mesh
|
||||
|
||||
//forces the patches to align on 4 pixel boundaries
|
||||
#define MAKE_BLOCK_ALIGN
|
||||
|
||||
struct SUV
|
||||
{
|
||||
float u,v; //texture coordinates
|
||||
};
|
||||
|
||||
inline const AABB MakeSafeAABB(const Vec3& rMin, const Vec3& rMax)
|
||||
{
|
||||
static const float scfMargin = 0.1f;//margin to add
|
||||
Vec3 vMin(rMin); Vec3 vMax(rMax);
|
||||
if(vMin.x == vMax.x) vMax.x += scfMargin;
|
||||
if(vMin.y == vMax.y) vMax.y += scfMargin;
|
||||
if(vMin.z == vMax.z) vMax.z += scfMargin;
|
||||
return AABB(vMin, vMax);
|
||||
}
|
||||
|
||||
//used for warning gathering
|
||||
typedef enum
|
||||
{
|
||||
EWARNING_EXPORT_FAILED = 0, //!< export of lightmaps has failed
|
||||
EWARNING_LIGHT_EXPORT_FAILED, //!< export of lightsources has failed
|
||||
EWARNING_DOUBLE_SIDED, //!< double sided material
|
||||
EWARNING_TOO_MANY_OCCL_LIGHTS, //!< more than 4 active occlusion map light sources at the same time on glm
|
||||
EWARNING_NO_FIT, //!< glm does not fit into a single lightmap
|
||||
EWARNING_HUGE_PATCH, //!< has patch(es) which are larger than halve a lightmap wide or high
|
||||
EWARNING_WRONG_NORMALS, //!< glm has wrong normals
|
||||
EWARNING_DENORM_NORMALS, //!< glm has denormalized normals
|
||||
EWARNING_LIGHT_RADIUS, //!< light has a too little radius
|
||||
EWARNING_LIGHT_INTENSITY, //!< light has a too little intensity
|
||||
EWARNING_LIGHT_FRUSTUM //!< spotlight has invalid frustum
|
||||
}EWARNING_TYPE;
|
||||
|
||||
static const unsigned int scuiWarningTextAllocation = 300;//number of chars allocated on stack for warning string
|
||||
|
||||
static inline const bool IsNormalized(const float cfSqLen)
|
||||
{
|
||||
static const float scfThreshold = 0.1f;
|
||||
if(fabs(cfSqLen - 1.f) < scfThreshold)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//supports flexible subsampling patterns, but for simplicity just use 9x or nothing for now
|
||||
class CAASettings
|
||||
{
|
||||
protected:
|
||||
unsigned int m_uiScale;
|
||||
float m_fInvScale;
|
||||
public:
|
||||
bool m_bEnabled;
|
||||
CAASettings():m_bEnabled(false),m_uiScale(1),m_fInvScale(1.0f){}
|
||||
void SetScale(const unsigned int cuiScale)
|
||||
{
|
||||
assert(cuiScale != 0);
|
||||
m_uiScale = cuiScale;
|
||||
m_fInvScale = 1.0f / (float)cuiScale;
|
||||
}
|
||||
const float GetInvScale()const{return m_fInvScale;}
|
||||
const unsigned int GetScale()const{return m_uiScale;}
|
||||
const float RetrieveRealSamplePos(const real cfOrig)
|
||||
{
|
||||
switch(m_uiScale)
|
||||
{
|
||||
case 1:
|
||||
return cfOrig;
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
const real cfNumber = (real)((int)(cfOrig * 0.5f));
|
||||
return (cfNumber - (real)1.0f/(real)3.0 + (real)2.0/(real)3.0 * (cfOrig - cfNumber * (real)2.0));//map onto -1/3, 1/3, 2/3, 4/3,...
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
return ((real)1.0f/(real)3.0 * cfOrig - (real)1.0f/(real)3.0);//map onto -1/3, 0/3, 1/3, 2/3, 3/3, 4/3,...
|
||||
break;
|
||||
default:
|
||||
return m_fInvScale * cfOrig;
|
||||
}
|
||||
}
|
||||
//returns the middle index, or tells whether this is the one or not
|
||||
const bool IsMiddle(const unsigned int cuiX, const unsigned int cuiY)
|
||||
{
|
||||
switch(m_uiScale)
|
||||
{
|
||||
case 1:
|
||||
return true;
|
||||
case 2:
|
||||
return (cuiX == 1 && cuiY == 1);
|
||||
case 3:
|
||||
return (cuiX == 1 && cuiY == 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class CLightPatch;
|
||||
class CRadPoly;
|
||||
class CRadVertex;
|
||||
class CRadMesh;
|
||||
struct IStatObj;
|
||||
class CLightScene;
|
||||
|
||||
typedef std::vector<CRadPoly *> radpolylist;
|
||||
typedef std::vector<CRadPoly *>::iterator radpolyit;
|
||||
typedef std::vector<CRadVertex> radvertexlist;
|
||||
typedef std::vector<CRadVertex>::iterator radvertexit;
|
||||
typedef std::list<CLightPatch *> lightpatchlist;
|
||||
typedef std::list<CLightPatch *>::iterator lightpatchit;
|
||||
typedef std::list<CRadMesh *> radmeshlist;
|
||||
typedef std::list<CRadMesh *>::iterator radmeshit;
|
||||
|
||||
typedef std::vector<std::pair<CRadPoly*,unsigned int> >::iterator SharedIter;
|
||||
typedef std::vector<CRadVertex *> radpvertexlist;
|
||||
typedef std::vector<CRadVertex *>::iterator radpvertexit;
|
||||
|
||||
#define PLANE_MX 3
|
||||
#define PLANE_MY 4
|
||||
#define PLANE_MZ 5
|
||||
|
||||
const float cfNormalizeThreshold = 0.00001f;
|
||||
|
||||
//need this shitty class because it is a bit too late to use a smart pointer and let it reference
|
||||
//use a map and the address as key
|
||||
class CRasterCubeManager
|
||||
{
|
||||
public:
|
||||
CRasterCubeManager(){};
|
||||
~CRasterCubeManager();
|
||||
void AddReference(const CRadMesh* cpRadMesh);
|
||||
CRasterCubeImpl* CreateRasterCube();
|
||||
const bool RemoveReference(CRadMesh* cpRadMesh);
|
||||
void Clear();
|
||||
|
||||
protected:
|
||||
std::map<CRasterCubeImpl*, std::set<const CRadMesh*> > m_mRasterCubeMap; //keeps track of each rastercube allocation
|
||||
};
|
||||
|
||||
// contains all information which a certain dot3 dominant light dir texel was stored with
|
||||
// also controls subsampling
|
||||
typedef struct SComplexOSDot3Texel
|
||||
{
|
||||
Vec3d vDot3Light; //!< world space light vector
|
||||
CRadPoly *pSourcePatch; //!< pointer to triangle where tangent space comes from, is always on this patch
|
||||
float fAlpha; //!< barycentric alpha value
|
||||
float fBeta; //!< barycentric beta value
|
||||
unsigned int uiLightMask; //!< lightmask
|
||||
unsigned int bNotHit; //!< true if this was a snapped texel
|
||||
SComplexOSDot3Texel():vDot3Light(),pSourcePatch(NULL),fAlpha(0.f),fBeta(0.f),uiLightMask(0),bNotHit(false){}
|
||||
const Vec3d TransformIntoTS(Vec3d& rSource)const;
|
||||
}SComplexOSDot3Texel;
|
||||
|
||||
//calc the area of a triangle using texture coords
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
inline float CalcTriangleArea( const Vec3d &A, const Vec3d &B, const Vec3d &C )
|
||||
{
|
||||
return( GetLength( (C-A).Cross(B-A) )*0.5f );
|
||||
}
|
||||
|
||||
__inline int CalcPlaneType2(const Vec3d& n)
|
||||
{
|
||||
if (((1.0f-n.x)<0.001f) && ((1.0f-n.x)>=0))
|
||||
return PLANE_X;
|
||||
else
|
||||
if (((1.0f-n.y)<0.001f) && ((1.0f-n.y)>=0))
|
||||
return PLANE_Y;
|
||||
else
|
||||
if (((1.0f-n.z)<0.001f) && ((1.0f-n.x)>=0))
|
||||
return PLANE_Z;
|
||||
else
|
||||
{
|
||||
float ax = fabs(n[0]);
|
||||
float ay = fabs(n[1]);
|
||||
float az = fabs(n[2]);
|
||||
|
||||
if (ax>=ay && ax>=az)
|
||||
return PLANE_MX;
|
||||
else
|
||||
if (ay>=ax && ay>=az)
|
||||
return PLANE_MY;
|
||||
else
|
||||
return PLANE_MZ;
|
||||
}
|
||||
}
|
||||
|
||||
const float DistToLine(const Vec3d& rX0, const Vec3d& rX1, const Vec3d& rPoint);
|
||||
const Vec3d ProjectOntoEdge(const Vec3d& rX0, const Vec3d& rX1, const Vec3d& rPoint, const float cfDistLV);
|
||||
|
||||
inline const unsigned int RoundFromFloat(const float cfTex)
|
||||
{
|
||||
unsigned int uiNumber = (unsigned int)cfTex;
|
||||
if(cfTex - (float)uiNumber >= 0.5f)
|
||||
uiNumber++;
|
||||
return uiNumber;
|
||||
}
|
||||
|
||||
const Vec3d RotateIntoPlane(const Vec3d& vPlaneNormal0, const Vec3d& vPlaneNormal1, const Vec3d& rInPosition, const Vec3d& rSource0);
|
||||
|
||||
//! \brief used local during generation of light clustering arrangement
|
||||
struct GLMCluster
|
||||
{
|
||||
Vec3d vMin;
|
||||
Vec3d vMax;
|
||||
std::set<IEntityRender *> vGLMsAffectingCluster;
|
||||
};
|
||||
|
||||
class CRadVertex
|
||||
{
|
||||
public:
|
||||
Vec3d m_vPos; //!< in world space
|
||||
Vec3d m_vNormal; //!< vertex normal for smooth lighting calulation
|
||||
float m_fpX,m_fpY; //!< used as projection coordinates and final texture coordinates as well
|
||||
|
||||
Vec3d m_vTNormal; //!<
|
||||
Vec3d m_vBinormal; //!<
|
||||
Vec3d m_vTangent; //!<
|
||||
|
||||
CRadVertex() : m_vPos(0.f,0.f,0.f), m_vNormal(0.f,0.f,0.f), m_fpX(0.f), m_fpY(0.f), m_vTNormal(0.f,0.f,0.f), m_vBinormal(0.f,0.f,0.f), m_vTangent(0.f,0.f,0.f)
|
||||
{}
|
||||
};
|
||||
|
||||
class CRadPoly
|
||||
{
|
||||
private:
|
||||
void FreeLightmaps( void );
|
||||
|
||||
//! used by GetNearestPolyAt()
|
||||
const float PointInTriangle(const Vec3d &point, const int ciIndex0, const int ciIndex1);
|
||||
|
||||
public:
|
||||
static const unsigned int scuiOneVertexShareFlag = 0x7F;
|
||||
//calculates the tangent space from the face information and applies it
|
||||
void CalculateTangentSpace(SUV uv[3]);
|
||||
|
||||
//passes pointer to all contained polys to give them access for averaging
|
||||
void SynchronizeLightmaps();
|
||||
|
||||
static void ApplyBaryCoordsToVertex(CRadVertex& rDest, const CRadVertex& rSource0, const CRadVertex& rSource1, const CRadVertex& rSource2, float cfAlpha, float cfBeta, const bool cbCOmputeTS = true);
|
||||
const bool CheckPointInTriangle(Vec3d &inPosition, const Vec3d &rVert0, const Vec3d &rVert1, const Vec3d &rVert2, float &rOutfAlpha, float &rOutfBeta, float &rfArea3d);
|
||||
|
||||
//! construtor
|
||||
CRadPoly();
|
||||
|
||||
//! construtor
|
||||
CRadPoly(CRadPoly *pSource);
|
||||
|
||||
//! destructor
|
||||
~CRadPoly();
|
||||
|
||||
//! /return true=the given polys have at least one vertex in common
|
||||
bool Connected(CRadPoly *pOther);
|
||||
|
||||
//! copy the data to the give patch, the poly lightmap data is removed from memory, too
|
||||
//! /param inpDestLightPatch destination
|
||||
//! /param nMapS
|
||||
//! /param nMapT
|
||||
//! /param inpSrcPoly pointer to the poly, must not be 0
|
||||
//! /param sw source pitch = width in bytes
|
||||
//! /param sh number of lines
|
||||
//! /param dw destination pitch
|
||||
void CopyData( CLightPatch *inpDestLightPatch, int dw );
|
||||
|
||||
bool IsTextureUniform(const int nTreshold);
|
||||
|
||||
//! compress patch to 1x1 if constant value
|
||||
void Compress( const unsigned int cuiMinBlockSize );
|
||||
|
||||
//! gather all subsamples for on etexel and sets the new value
|
||||
//! /param cuiX x-coord for texel to subsample
|
||||
//! /param cuiY y-coord for texel to subsample
|
||||
//! /param cuiSubSamples subsample count excluding center texel
|
||||
//! /param cpaIndicator pointer to indicator array indicating which subsample has received values
|
||||
//! /param cpfColours pointer to colour subsample array
|
||||
//! /param pDot3 pointer to dot3 subsample values
|
||||
//! /param ruiMaxComponent current max of colour patch components
|
||||
#ifdef APPLY_COLOUR_FIX
|
||||
void GatherSubSamples(
|
||||
const unsigned int cuiX, const unsigned int cuiY, const unsigned int cuiSubSamples,
|
||||
const unsigned int *cpaIndicator, const float *cpfColours, const SComplexOSDot3Texel *pDot3,
|
||||
unsigned int& ruiMaxComponent, const SOcclusionMapTexel *cpfOccl, const GLMOcclLightInfo& rOcclInfo);
|
||||
#else
|
||||
void GatherSubSamples(
|
||||
const unsigned int cuiX, const unsigned int cuiY, const unsigned int cuiSubSamples,
|
||||
const unsigned int *cpaIndicator, const float *cpfColours, const SComplexOSDot3Texel *pDot3, const SOcclusionMapTexel *cpfOccl, const GLMOcclLightInfo& rOcclInfo);
|
||||
#endif
|
||||
//!
|
||||
//! /return true=polygon has 3 vertices - calculation is ok, false=its not a triangle (degenerated - or wrong vertex count) calculation failed
|
||||
//! alters inPosition by projecting it into the triangls area
|
||||
bool ApplyBarycentricCoordinates( Vec3d &inPosition, CRadVertex &outVertex, SComplexOSDot3Texel& rDot3Texel, const bool cbImmedReturn = false, const bool cbSnap = true);
|
||||
|
||||
//!
|
||||
//! /param inPosition
|
||||
//! /return could be 0
|
||||
CRadPoly *GetNearestPolyAt( const Vec3d &inPosition );
|
||||
|
||||
//lighpatch
|
||||
void AddWarningBorders( void );
|
||||
|
||||
#ifndef DISPLAY_MORE_INFO
|
||||
const unsigned int CalcExtent(CLightScene *pScene, const CString& rGLMName, const CString& rCGFName, bool bOriginal, const float fGridSize, const UINT iMinBlockSize, const UINT iMaxBlockSize, unsigned int& rHugePatchFoundNumber);
|
||||
#else
|
||||
const unsigned int CalcExtent(CLightScene *pScene, const CString& rGLMName, const CString& rCGFName, bool bOriginal, const float fGridSize, const UINT iMinBlockSize, const UINT iMaxBlockSize);
|
||||
#endif
|
||||
|
||||
//!
|
||||
void GenerateImage( void );
|
||||
|
||||
//!
|
||||
//! m_nW and m_nH is used
|
||||
void AllocateDot3Lightmap(const bool cbGenerateHDRMaps, const bool cbGenerateOcclMaps = false);
|
||||
|
||||
bool InterpolateVertexAt( const float infX, const float infY, CRadVertex &outVertex, SComplexOSDot3Texel& rDot3Texel, const bool cbSubSample, const bool cbSnap=true) ;
|
||||
|
||||
/**
|
||||
* snaps a vertex which lies outside a triangle onto the nearest edge to get some valid barycentric coordinates
|
||||
* it does not extrapolate
|
||||
* @param inPosition vertex outside the triangle
|
||||
* @param outfAlpha alpha value for barycentric coordinate
|
||||
* @param outfBeta beta value for barycentric coordinate
|
||||
* @param cfTriangleArea area of triangle for computation of the new barycentric cooridnates
|
||||
*/
|
||||
const bool SnapVertex(Vec3d &inPosition, float &outfAlpha, float &outfBeta, const float cfTriangleArea);
|
||||
|
||||
/**
|
||||
* tries to map coordinates into triangles sharing at least one vertex of this triangle, performs the smoothing
|
||||
* @param outVertex output vertex interpolated from shared triangles
|
||||
* @param inPosition vertex outside the triangle
|
||||
* @param cfArea3d traingle area for snapping call
|
||||
* @param rDot3Texel information for dot3 texel to set up
|
||||
* @return true if one shared triangle has been found, false otherwise
|
||||
*/
|
||||
const bool SmoothVertex(CRadVertex &outVertex, const Vec3d &inPosition, const float cfArea3d, SComplexOSDot3Texel& rDot3Texel);
|
||||
|
||||
/**
|
||||
* applies tangent space vectors from this patch to a vertex having a pos outside this triangle
|
||||
* @param outVertex output vertex interpolated from shared triangles
|
||||
* @param outfAlpha alpha value for barycentric coordinate
|
||||
* @param outfBeta beta value for barycentric coordinate
|
||||
*/
|
||||
void ApplyTangentSpaceToVertex(CRadVertex &outVertex, float cfAlpha, float cfBeta);
|
||||
|
||||
void SetHDRLightmapTexel( const float infX, const float infY, const float lr, const float lg, const float lb);
|
||||
void SetOcclLightmapTexel(const float infX, const float infY, const SOcclusionMapTexel& rTexel);
|
||||
//!
|
||||
//! /param infX [0..m_nW[
|
||||
//! /param infY [0..m_nH[
|
||||
//! /param r 0.. , is automatic clamped to 0..255, usual lightmap color
|
||||
//! /param g 0.. , is automatic clamped to 0..255, usual lightmap color
|
||||
//! /param b 0.. , is automatic clamped to 0..255, usual lightmap color
|
||||
void SetSimpleLightmapTexel( const float infX, const float infY, const int lr, const int lg, const int lb, unsigned char iDP3Fac);
|
||||
//! stores the world space dot3 light vector and calls SetSimpleLightmapTexel
|
||||
#ifdef APPLY_COLOUR_FIX
|
||||
const unsigned int SetDot3LightmapTexel(const CRadVertex& rVertex,
|
||||
const float fColorRLamb, const float fColorGLamb, const float fColorBLamb,
|
||||
Vec3d &inLightDir, const float cfLM_DP3LerpFactor,
|
||||
SComplexOSDot3Texel& rDot3Texel, const SOcclusionMapTexel& rTexel, bool bHDR);
|
||||
#else
|
||||
void SetDot3LightmapTexel(const CRadVertex& rVertex,
|
||||
const float fColorRLamb, const float fColorGLamb, const float fColorBLamb,
|
||||
Vec3d &inLightDir, const float cfLM_DP3LerpFactor,
|
||||
SComplexOSDot3Texel& rDot3Texel, const SOcclusionMapTexel& rTexel, bool bHDR);
|
||||
#endif
|
||||
//! stores the tangent space light vector as colour
|
||||
#ifdef APPLY_COLOUR_FIX
|
||||
void SetDot3TSLightmapTexel(const unsigned int cuiX, const unsigned int cuiY, const unsigned int cuiColourFixAlpha, const float cfColourScale);
|
||||
#else
|
||||
void SetDot3TSLightmapTexel(const unsigned int cuiX, const unsigned int cuiY);
|
||||
#endif
|
||||
//unsigned int consists of 4 chars as follows: [0]=1st shared vertex of this [1]=2nd shared vertex of this [2]=1st shared vertex of shared triangle [3]=2nd shared vertex of shared triangle
|
||||
std::vector<std::pair<CRadPoly*,unsigned int> > m_SharingPolygons; //!< vertex sharing polygons
|
||||
|
||||
radpolylist m_lstMerged; //!< only patches merge
|
||||
|
||||
radvertexlist m_lstOriginals; //!<
|
||||
|
||||
Plane m_Plane; //!<
|
||||
|
||||
CRadPoly * m_pSource; //!<
|
||||
|
||||
CRadPoly * m_pMergeSource; //!< the source for this radpoly where it is contained in m_lstMerged
|
||||
|
||||
float m_fX1,m_fY1,m_fX2,m_fY2; //!<
|
||||
|
||||
int16 m_nX1,m_nY1,m_nX2,m_nY2; //!<
|
||||
|
||||
uint16 m_nW,m_nH; //!< really occupied width and height in the lightmap (always >=0)
|
||||
|
||||
uint8 m_nAx1,m_nAx2; //!<
|
||||
|
||||
uint8 m_nAxis; //!<
|
||||
|
||||
uint8 m_dwFlags; //!<
|
||||
|
||||
Vec3 *m_pHDRLightmapData; //! RGBE8 Lightmap
|
||||
unsigned char *m_pLightmapData; //! Lightmap / or colormap when using dot3
|
||||
unsigned char *m_pDominantDirData; //!< used for Dot3Lightmaps (normalized tangent space direction to the dominant lightsource, dot3 factor in alpha channel)
|
||||
SComplexOSDot3Texel *m_pWSDominantDirData; //!< used for Dot3Lightmaps, stores the world space vector and where the tangent space comes from
|
||||
SOcclusionMapTexel *m_pOcclMapData; //!< used for occlusionmap data
|
||||
|
||||
uint16 m_nOffsetW, m_nOffsetH; //!< offset into big lightmap
|
||||
|
||||
friend class CLightScene;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
class CRadMesh
|
||||
{
|
||||
public:
|
||||
//! destructor
|
||||
~CRadMesh();
|
||||
|
||||
//! call after putting in the light sources to get the right HashValue
|
||||
void CreateEmpty( IEntityRender *pIEtyRend, const Matrix44& matEtyMtx );
|
||||
const bool FillInValues( IEntityRender *pIEtyRend, const CBrushObject *pBrushObject, const Matrix44& matEtyMtx );
|
||||
void PrepareLightmaps(CLightScene *pScene, bool bMergePolys,const float fGridSize, const Vec3d& vMinBB, const Vec3d& vMaxBB);
|
||||
bool SaveLightmaps(CLightScene *pScene,bool bDebug=false);
|
||||
|
||||
//! /return hashing value to detect changes in the data
|
||||
DWORD GetHashValue( void ) const {return(m_dwHashValue);};
|
||||
|
||||
void UpdateHash(const DWORD newHash){CalcNCombineHash(newHash,m_dwHashValue);}
|
||||
|
||||
// --------------------------------------------------
|
||||
|
||||
IEntityRender * m_pESource; //!<
|
||||
|
||||
radpolylist m_lstOldPolys; //!< this class is the owner of these objects (delete is called)
|
||||
|
||||
Vec3d m_vCenter; //!<
|
||||
float m_fRadius,m_fRadius2; //!<
|
||||
|
||||
std::vector<LMCompLight *> m_LocalLights; //!< the lights that may affect this RadMesh (this class is not the owner = delete will not be called)
|
||||
|
||||
std::vector<LMCompLight *> m_LocalOcclLights; //!< the occlusion map lights types that may affect this RadMesh (this class is not the owner = delete will not be called)
|
||||
|
||||
CString m_sGLMName; //!< name of glm corresponding to this mesh
|
||||
|
||||
CRasterCubeImpl *m_pClusterRC; //!< Raster cube of the cluster in which this mesh is in
|
||||
|
||||
float m_fLMAccuracy; //!< individual GLM accuracy ranging from 0.. with 1 = default global world<->texel ratio
|
||||
|
||||
bool m_bReceiveLightmap; //!< indicates whether an object will receive lightmaps or not
|
||||
|
||||
unsigned int m_uiFlags; //!< flags, currently used during normal check and triangle initialisation
|
||||
|
||||
float m_fMaxVariance; //!< variance in normal length (purely for information)
|
||||
|
||||
IVariable *pLightmapQualityVar; //!< lightmap quality variable to adjust it if necessary
|
||||
|
||||
unsigned int m_uiTexCoordsRequired; //!< required texture coordinates by engine, should always match number of indices
|
||||
|
||||
GLMOcclLightInfo m_OcclInfo; //!< required information what light corresponds to which colour channel
|
||||
|
||||
//! constructor
|
||||
CRadMesh() :
|
||||
m_uiCoarseTexelCount(0), pLightmapQualityVar(NULL), m_fMaxVariance(0.f), m_fLMAccuracy(1.f), m_pESource(NULL),
|
||||
m_dwHashValue(0), m_pClusterRC(NULL), m_bReceiveLightmap(true), m_uiFlags(0), m_uiTexCoordsRequired(0){}
|
||||
|
||||
private:
|
||||
unsigned int m_uiCoarseTexelCount; //!< texel count required (simple summation over all patches after CalcExtent)
|
||||
|
||||
DWORD m_dwHashValue; //!< for selective recomputation
|
||||
|
||||
DWORD CalcLocalLightHashValue( void ) const;
|
||||
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
class CLightPatch
|
||||
{
|
||||
public:
|
||||
CLightPatch(UINT iPatchResolution) : m_pLightmapImage(0),m_pHDRLightmapImage(0),m_pDominantDirImage(0),m_pOcclMapImage(NULL),m_nTextureNum(0)
|
||||
{
|
||||
m_nPatchSpace.resize(iPatchResolution);
|
||||
}
|
||||
|
||||
~CLightPatch()
|
||||
{
|
||||
if(m_pLightmapImage) { delete [] m_pLightmapImage;m_pLightmapImage=NULL; }
|
||||
if(m_pHDRLightmapImage) { delete [] m_pHDRLightmapImage;m_pHDRLightmapImage=NULL; }
|
||||
if(m_pDominantDirImage) { delete [] m_pDominantDirImage;m_pDominantDirImage=NULL; }
|
||||
if(m_pOcclMapImage) { delete [] m_pOcclMapImage;m_pOcclMapImage=NULL; }
|
||||
}
|
||||
|
||||
//! /param nSizeX 1..
|
||||
//! /param nSizey 1..
|
||||
void CreateDot3Lightmap( int nSizeX, int nSizeY,const bool cbGenerateHDRMaps, const bool cbGenerateOcclMaps = false );
|
||||
void Reset();
|
||||
|
||||
//!
|
||||
const bool GetSpace(int w,int h, uint16 &x, uint16 &y);
|
||||
|
||||
std::vector<int> m_nPatchSpace; //!<
|
||||
int m_nTextureNum; //!<
|
||||
int m_nWidth,m_nHeight; //!<
|
||||
std::string m_szFilename; //!<
|
||||
|
||||
unsigned char *m_pHDRLightmapImage; //!< HDR Lightmap texture (in Dot3Lightmaps this is used for the non dominant light sources)
|
||||
unsigned char *m_pLightmapImage; //!< Lightmap texture (in Dot3Lightmaps this is used for the non dominant light sources)
|
||||
unsigned char *m_pDominantDirImage; //!< only used for Dot3Lightmaps (normalized worldspace direction to the dominant lightsource)
|
||||
SOcclusionMapTexel *m_pOcclMapImage; //!< used for occlusionmap data
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
class CLightScene
|
||||
{
|
||||
public:
|
||||
CLightScene();
|
||||
~CLightScene();
|
||||
|
||||
bool CreateFromEntity(
|
||||
const IndoorBaseInterface &pInterface,
|
||||
LMGenParam sParam,
|
||||
std::vector<std::pair<IEntityRender*, CBrushObject*> >& vNodes,
|
||||
CLMLightCollection& cLights,
|
||||
struct ICompilerProgress *pIProgress,
|
||||
const ELMMode Mode,
|
||||
volatile SSharedLMEditorData* pSharedData,
|
||||
const std::set<const CBrushObject*>& vSelectionIndices,
|
||||
bool &rErrorsOccured);
|
||||
|
||||
radmeshlist m_lstRadMeshes; //!< this class is the owner of these objects (delete is called)
|
||||
radpolylist m_lstScenePolys; //!<
|
||||
unsigned int m_uiCurrentPatchNumber; //!< to number the current lightmap
|
||||
CLightPatch * m_pCurrentPatch; //!<
|
||||
LMGenParam m_sParam;
|
||||
|
||||
void CreateNewLightmap( void );
|
||||
|
||||
// The assign queue system
|
||||
struct LMAssignQueueItem
|
||||
{
|
||||
IEntityRender * pI_GLM; //!
|
||||
std::vector<struct TexCoord2Comp> vSortedTexCoords; //!
|
||||
DWORD m_dwHashValue; //!< hashing value to detect changes in the data
|
||||
std::vector<std::pair<EntityId, EntityId> > vOcclIDs; //!< occlusion indices corresponding to the 0..4 colour channels
|
||||
};
|
||||
|
||||
std::list<LMAssignQueueItem> m_lstAssignQueue; //!
|
||||
|
||||
std::vector<CString>& GetLogInfo()
|
||||
{
|
||||
return m_LogInfo;
|
||||
}
|
||||
|
||||
std::multimap<unsigned int,std::string>& GetWarningInfo()
|
||||
{
|
||||
return m_WarningInfo;
|
||||
}
|
||||
|
||||
const float ComputeHalvedLightmapQuality(const float fOldValue);
|
||||
|
||||
protected:
|
||||
void DoLightCalculation(
|
||||
unsigned int &ruiMaxColourComp,
|
||||
const std::vector<LMCompLight*>& vLights,
|
||||
const std::vector<LMCompLight*>& vOcclLights,
|
||||
SComplexOSDot3Texel& dot3Texel,
|
||||
CRadMesh *pMesh,
|
||||
CRadPoly *pSource,
|
||||
const CRadVertex& Vert,
|
||||
const bool cbFirstPass,
|
||||
const unsigned int cuiSubSampleIndex = 0);
|
||||
void CheckLight(LMCompLight& rLight, const int iCurLightIdx);
|
||||
void GenerateTexCoords(const CRadMesh& rRadMesh, LMAssignQueueItem& rNewGLMQueueItm);
|
||||
void SelectObjectLMReceiverAndShadowCasterForChanges(
|
||||
std::vector<std::pair<IEntityRender*, CBrushObject*> >& vNodes,
|
||||
const std::vector<AABB>& vAABBs,
|
||||
const Matrix33& rMatSunBasis,
|
||||
const std::vector<unsigned int>& rvNodeRadMeshIndices,
|
||||
const ELMMode Mode);
|
||||
void SelectObjectsFromChangedLMShadowCaster(
|
||||
std::vector<std::pair<IEntityRender*, CBrushObject*> >&vNodes,
|
||||
const std::vector<AABB>& vAABBs,
|
||||
const Matrix33& rMatSunBasis,
|
||||
const std::vector<unsigned int>& rvNodeRadMeshIndices);
|
||||
void ComputeSmoothingInformation(const unsigned int uiSmoothAngle = 45, const bool cbTSGeneratedByLM = false); //computes the sharing information and stores it into the respective per polygon vectors
|
||||
void MergeTangentSpace(CRadVertex& rVertex1, CRadVertex& rVertex2); //merges two tangent spaces according to normal
|
||||
const unsigned int CheckNormals(float& rfMaxVariance, const CRadMesh* const pMesh);//returns true if some normals are not normalized, rfMaxVariance is the max variance encountered
|
||||
bool Create(const IndoorBaseInterface &pInterface, const Vec3d& vMinBB, const Vec3d& vMaxBB, volatile SSharedLMEditorData *pSharedData, const ELMMode Mode, const unsigned int cuiMeshesToProcessCount);
|
||||
void FlushAssignQueue();
|
||||
#ifdef APPLY_COLOUR_FIX
|
||||
void PerformAdaptiveSubSampling(
|
||||
CRadMesh *pMesh,
|
||||
CRadPoly *pSource,
|
||||
const std::vector<LMCompLight*>& vLights,
|
||||
const std::vector<LMCompLight*>& vOcclLights,
|
||||
unsigned int uiMaxComponent);
|
||||
#else
|
||||
void PerformAdaptiveSubSampling(
|
||||
CRadMesh *pMesh,
|
||||
CRadPoly *pSource,
|
||||
const std::vector<LMCompLight*>& vLights,
|
||||
const std::vector<LMCompLight*>& vOcclLights);
|
||||
#endif
|
||||
void SetSubSampleDot3LightmapTexel(
|
||||
const unsigned int cuiSubSampleIndex,
|
||||
const float fColorRLamb, const float fColorGLamb, const float fColorBLamb,
|
||||
Vec3d &inLightDir, const float cfLM_DP3LerpFactor,
|
||||
SComplexOSDot3Texel& rDot3Texel,
|
||||
const SOcclusionMapTexel& rOcclTexel, bool bHDR);
|
||||
void GatherSubSampleTexel(const CRadPoly *pSource, const int ciX, const int ciY, std::set<std::pair<unsigned int, unsigned int> >& rvSubTexels);
|
||||
const bool FlushAndSave(volatile SSharedLMEditorData *pSharedData, const ELMMode Mode);
|
||||
void Reset()
|
||||
{
|
||||
//i need this definitely to be deallocated, thats why clear and resize call (implementations differ to much which really deallocates)
|
||||
m_lstRadMeshes.clear();
|
||||
m_lstScenePolys.clear();
|
||||
m_lstAssignQueue.clear();
|
||||
m_lstRadMeshes.resize(0);
|
||||
m_lstScenePolys.resize(0);
|
||||
m_lstAssignQueue.resize(0);
|
||||
m_lstClusters.clear();
|
||||
m_lstClusters.resize(0);
|
||||
};
|
||||
|
||||
void WriteLogInfo();
|
||||
|
||||
void Init()
|
||||
{
|
||||
Reset();
|
||||
MEMORYSTATUS sStats;
|
||||
GlobalMemoryStatus(&sStats);
|
||||
m_uiStartMemoryConsumption = ((sStats.dwTotalVirtual - sStats.dwAvailVirtual) / 1024/1024);
|
||||
}
|
||||
const unsigned int GetUsedMemory()
|
||||
{
|
||||
MEMORYSTATUS sStats;
|
||||
GlobalMemoryStatus(&sStats);
|
||||
const unsigned int cuiCurrentTotal((sStats.dwTotalVirtual - sStats.dwAvailVirtual) / 1024/1024);
|
||||
if(cuiCurrentTotal <= m_uiStartMemoryConsumption)
|
||||
return 0;
|
||||
return (cuiCurrentTotal - m_uiStartMemoryConsumption);
|
||||
};
|
||||
void DumpSysMemStats()
|
||||
{
|
||||
_TRACE(m_LogInfo, true, "System memory usage: %iMB\r\n", GetUsedMemory());
|
||||
};
|
||||
void DisplayMemStats(volatile SSharedLMEditorData *pSharedData)
|
||||
{
|
||||
if(pSharedData != NULL)
|
||||
{
|
||||
::SendMessage( pSharedData->hwnd, pSharedData->uiMemUsageMessage, min(GetUsedMemory(),1000), 0 );//update progress bar
|
||||
::SendMessage( pSharedData->hwnd, pSharedData->uiMemUsageStatic, min(GetUsedMemory(),1000), 0 );//update progress bar static element
|
||||
MSG msg;
|
||||
while( FALSE != ::PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) )
|
||||
{
|
||||
::TranslateMessage( &msg );
|
||||
::DispatchMessage( &msg );
|
||||
}
|
||||
}
|
||||
else
|
||||
DumpSysMemStats();
|
||||
}
|
||||
static bool CastsLightmap(const CBrushObject *pBrushObject)
|
||||
{
|
||||
bool bCastLightmap = true;
|
||||
if(pBrushObject)
|
||||
{
|
||||
CVarBlock *pVarBlock = pBrushObject->GetVarBlock();
|
||||
if(pVarBlock)
|
||||
{
|
||||
IVariable *pVar = pVarBlock->FindVariable("CastLightmap");
|
||||
if(pVar && (pVar->GetType() == IVariable::BOOL))
|
||||
{
|
||||
pVar->Get(bCastLightmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
return bCastLightmap;
|
||||
}
|
||||
void InitSubSampling(const unsigned int cuiSampleCount)
|
||||
{
|
||||
m_puiIndicator = new unsigned int[cuiSampleCount]; assert(m_puiIndicator);
|
||||
m_pSubSamples = new SComplexOSDot3Texel[cuiSampleCount]; assert(m_pSubSamples);
|
||||
m_pfColours = new float [cuiSampleCount * 4/*4 colour components*/]; assert(m_pfColours);
|
||||
if(m_sParam.m_bGenOcclMaps)
|
||||
{
|
||||
m_pOcclSamples = new SOcclusionMapTexel[cuiSampleCount]; assert(m_pOcclSamples);
|
||||
}
|
||||
m_uiSampleCount = cuiSampleCount;
|
||||
}
|
||||
|
||||
private:
|
||||
std::multimap<unsigned int,std::string> m_WarningInfo; //!< will contain warning summary for logfile
|
||||
std::vector<CString> m_LogInfo; //!< will contain some logging info
|
||||
|
||||
struct ILMSerializationManager *m_pISerializationManager;
|
||||
std::list<GLMCluster> m_lstClusters;
|
||||
CRasterCubeManager m_RasterCubeManager;
|
||||
|
||||
unsigned int *m_puiIndicator; //!< index of each pixel whether a value has been set or not
|
||||
SComplexOSDot3Texel *m_pSubSamples; //!< subsamples for one texel
|
||||
SOcclusionMapTexel *m_pOcclSamples; //!< subsamples for occl map texel
|
||||
float *m_pfColours; //!< colours
|
||||
unsigned int m_uiSampleCount; //!< subsample count for one single texel
|
||||
|
||||
unsigned int m_uiStartMemoryConsumption;
|
||||
|
||||
IndoorBaseInterface m_IndInterface;
|
||||
|
||||
bool ComputeRasterCube(CRasterCubeImpl *pRasterCube, const std::set<IEntityRender *>& vGeom, const Matrix33 *pDirLightTransf = NULL);
|
||||
|
||||
void Shadow(LMCompLight& cLight, UINT& iNumHit, CRadMesh *pMesh, CRadPoly *pSource, const CRadVertex& Vert, const Vec3d& vSamplePos);
|
||||
|
||||
#define ALREADY_TESTED_ARRARY_SIZE 1024
|
||||
|
||||
class CEveryObjectOnlyOnce :public CPossibleIntersectionSink<RasterCubeUserT>
|
||||
{
|
||||
public:
|
||||
//! /param invFrom
|
||||
//! /param invDir
|
||||
//! /param infRayLength
|
||||
//! /param inpIgnore for bias free rayshooting from object surface, may be 0
|
||||
void SetupRay( const Vec3d& vRayDir, const Vec3d& vRayOrigin, float fRayLen, CRadPoly* pRayDest)
|
||||
{
|
||||
m_vRayDir = vRayDir;
|
||||
m_vRayOrigin = vRayOrigin;
|
||||
m_fRayLen = fRayLen;
|
||||
m_pRayDest = pRayDest;
|
||||
m_dwAlreadyTested=0;
|
||||
}
|
||||
|
||||
// --------------------------------------------
|
||||
|
||||
protected:
|
||||
Vec3d m_vRayOrigin; //!< position in world space
|
||||
Vec3d m_vRayDir; //!< direction in world space
|
||||
DWORD m_dwAlreadyTested; //!< 0..ALREADY_TESTED_ARRARY_SIZE
|
||||
float m_fRayLen; //!<
|
||||
const RasterCubeUserT * m_arrAlreadyTested[ALREADY_TESTED_ARRARY_SIZE]; //!< [0..ALREADY_TESTED_ARRARY_SIZE-1], this is faster than a set<> at least for typical amounts
|
||||
CRadPoly* m_pRayDest; //!< ray destination polygon
|
||||
|
||||
//! /return true=object is already tested, false otherwise
|
||||
bool InsertAlreadyTested( RasterCubeUserT *inObject )
|
||||
{
|
||||
const RasterCubeUserT * *ptr=m_arrAlreadyTested;
|
||||
|
||||
for(DWORD i=0;i<m_dwAlreadyTested;i++)
|
||||
if(*ptr++==inObject)return(true);
|
||||
|
||||
if(m_dwAlreadyTested<ALREADY_TESTED_ARRARY_SIZE-1) m_arrAlreadyTested[m_dwAlreadyTested++]=inObject;
|
||||
else assert(0); // ALREADY_TESTED_ARRARY_SIZE is not big enougth
|
||||
|
||||
return(false);
|
||||
}
|
||||
};//CEveryObjectOnlyOnce
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// Intersection sink
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
class CAnyHit : public CEveryObjectOnlyOnce
|
||||
{
|
||||
public:
|
||||
|
||||
void SetupRay(const Vec3d& vRayDir, const Vec3d& vRayOrigin, float fRayLen, const float infGridSize, CRadPoly* pRayDest = NULL)
|
||||
{
|
||||
CEveryObjectOnlyOnce::SetupRay(vRayDir,vRayOrigin,fRayLen, pRayDest);
|
||||
m_pHitResult = 0;
|
||||
m_fClosest = FLT_MAX;
|
||||
m_fGridSize=infGridSize;
|
||||
};
|
||||
bool IsIntersecting() const { return(m_pHitResult!=0); }
|
||||
|
||||
// TODO
|
||||
float m_fD;
|
||||
Vec3d m_vPNormal;
|
||||
float m_fGridSize;
|
||||
|
||||
const bool ReturnElement(RasterCubeUserT &inObject, float &inoutfRayMaxDist);
|
||||
|
||||
RasterCubeUserT *m_pHitResult;
|
||||
protected:
|
||||
float m_fClosest;
|
||||
|
||||
// Still intersect with backfacing triangles. While this fixes a few false shadow cases, it
|
||||
// adds ugly bright seems between caster and shadow, which looks far worse
|
||||
int intersect_triangle( float orig[3], float dir[3],
|
||||
float vert0[3], float vert1[3], float vert2[3],
|
||||
float *t, float *u, float *v);
|
||||
};//CAnyHit
|
||||
friend class CRadPoly;
|
||||
};//CLightScene
|
||||
|
||||
//computes a fade for the light average weight
|
||||
static inline const float LightInfluence(const float cfDot)
|
||||
{
|
||||
static const float scfMinInfluence = 0.01f; //influence = 0
|
||||
static const float scfFullInfluence = 0.2f; //influence = 1
|
||||
if(cfDot >= scfFullInfluence)
|
||||
return 1.f;
|
||||
if(cfDot <= scfMinInfluence)
|
||||
return 0.f;
|
||||
return (cfDot - scfMinInfluence) / (scfFullInfluence - scfMinInfluence);
|
||||
}
|
||||
|
||||
#endif // __INDOOR_LIGHT_PATCHES_H__
|
||||
2479
Editor/LightmapCompiler/IndoorPatchLights.cpp
Normal file
2479
Editor/LightmapCompiler/IndoorPatchLights.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1296
Editor/LightmapCompiler/IndoorPatches.cpp
Normal file
1296
Editor/LightmapCompiler/IndoorPatches.cpp
Normal file
File diff suppressed because it is too large
Load Diff
65
Editor/LightmapCompiler/LMCompCommon.h
Normal file
65
Editor/LightmapCompiler/LMCompCommon.h
Normal file
@@ -0,0 +1,65 @@
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// Crytek CryENGINE source code
|
||||
// History:
|
||||
// - Created by Tim Schroeder
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
|
||||
#ifndef __LM_COMP_COMMONH_H__
|
||||
#define __LM_COMP_COMMONH_H__
|
||||
|
||||
#pragma once
|
||||
|
||||
struct IndoorBaseInterface
|
||||
{
|
||||
ILog *m_pLog;
|
||||
IRenderer *m_pRenderer;
|
||||
I3DEngine *m_p3dEngine;
|
||||
IConsole *m_pConsole;
|
||||
ISystem *m_pSystem;
|
||||
};
|
||||
|
||||
#include "LMCompStructures.h"
|
||||
|
||||
extern ICompilerProgress *g_pIProgress;
|
||||
|
||||
_inline void __cdecl _TRACE(std::vector<CString>& rLogInfo, const bool cbDoOutput, const char *sFormat, ... )
|
||||
{
|
||||
va_list vl;
|
||||
static char sTraceString[1024];
|
||||
|
||||
va_start(vl, sFormat);
|
||||
vsprintf(sTraceString, sFormat, vl);
|
||||
va_end(vl);
|
||||
|
||||
rLogInfo.push_back(CString(sTraceString));
|
||||
|
||||
if(cbDoOutput == false)
|
||||
return;
|
||||
|
||||
if (g_pIProgress == NULL)
|
||||
return;
|
||||
g_pIProgress->Output(sTraceString);
|
||||
}
|
||||
|
||||
_inline void __cdecl _TRACE(const char *sFormat, ... )
|
||||
{
|
||||
va_list vl;
|
||||
static char sTraceString[1024];
|
||||
|
||||
va_start(vl, sFormat);
|
||||
vsprintf(sTraceString, sFormat, vl);
|
||||
va_end(vl);
|
||||
|
||||
if (g_pIProgress == NULL)
|
||||
return;
|
||||
g_pIProgress->Output(sTraceString);
|
||||
}
|
||||
|
||||
/*
|
||||
__inline bool IsLeafBufferEmpty(CLeafBuffer *pLB)
|
||||
{
|
||||
return (pLB->m_pSecVertBuffer == NULL && pLB->m_pSecVertBuffer->m_NumVerts == 0 && pLB->m_NumIndices == 0);
|
||||
}
|
||||
*/
|
||||
|
||||
#endif
|
||||
182
Editor/LightmapCompiler/LMLightCollection.h
Normal file
182
Editor/LightmapCompiler/LMLightCollection.h
Normal file
@@ -0,0 +1,182 @@
|
||||
#ifndef __LM_LIGHT_COLLECTION_H__
|
||||
#define __LM_LIGHT_COLLECTION_H__
|
||||
|
||||
#include "LMCompStructures.h"
|
||||
|
||||
#include "RasterCube.h"
|
||||
|
||||
|
||||
//! \sa LMCompLight
|
||||
enum eLightType
|
||||
{
|
||||
eSpotlight,
|
||||
ePoint,
|
||||
eDirectional, //!< Sun
|
||||
};
|
||||
|
||||
//class CRadPoly;
|
||||
|
||||
struct RasterCubeUserT
|
||||
{
|
||||
float fVertices[3][3];
|
||||
Vec3d vNormal; //plane normal of triangle
|
||||
// CRadPoly *pTriangle;
|
||||
bool operator == (const RasterCubeUserT& A) const
|
||||
{ return memcmp(this, &A, sizeof(RasterCubeUserT)) == 0; };
|
||||
bool operator > (const RasterCubeUserT& A) const
|
||||
{ return memcmp(this, &A, sizeof(RasterCubeUserT)) == 1; };
|
||||
};
|
||||
|
||||
typedef CRasterCube<RasterCubeUserT, true, false> CRasterCubeImpl;//fast version using only two raster and break after first valid hit encounter
|
||||
//typedef CRasterCube<RasterCubeUserT> CRasterCubeImpl;//old version with 3 rastertables and no early out
|
||||
|
||||
inline void CalcNCombineHash( const DWORD indwValue, DWORD &inoutHash )
|
||||
{
|
||||
// inoutHash^=inoutHash*0x1c1a8926 + indwValue + inoutHash;
|
||||
// inoutHash^=inoutHash%600011 + indwValue;
|
||||
inoutHash^=(inoutHash%600011) + (inoutHash/600011) + indwValue;
|
||||
}
|
||||
|
||||
inline void CalcNCombineHash( const float infValue, DWORD &inoutHash )
|
||||
{
|
||||
CalcNCombineHash(*((DWORD *)(&infValue)),inoutHash);
|
||||
}
|
||||
|
||||
inline void CalcNCombineHash( const Vec3d &invValue, DWORD &inoutHash )
|
||||
{
|
||||
CalcNCombineHash(invValue.x,inoutHash);
|
||||
CalcNCombineHash(invValue.y,inoutHash);
|
||||
CalcNCombineHash(invValue.z,inoutHash);
|
||||
|
||||
}
|
||||
|
||||
//! \sa eLightType
|
||||
struct LMCompLight
|
||||
{
|
||||
LMCompLight():m_CompLightID(std::pair<EntityId, EntityId>(0,0))
|
||||
{
|
||||
vWorldSpaceLightPos = Vec3d(0.0f, 0.0f, 0.0f);
|
||||
vDirection = Vec3d(1.0f, 0.0f, 0.0f);
|
||||
fRadius = 1.0f;
|
||||
fLightFrustumAngleDegree = 45.0f;
|
||||
eType = ePoint;
|
||||
fColor[0]=0;fColor[1]=0;fColor[2]=0;
|
||||
m_pLastIntersection=0;
|
||||
|
||||
// m_pPointLtRC = NULL;
|
||||
|
||||
m_pLastIntersectionRasterCube = NULL;
|
||||
|
||||
uiFlags = 0;
|
||||
pVisArea = 0;
|
||||
|
||||
m_bFakeRadiosity = false;
|
||||
m_bDot3 = true;
|
||||
m_bOcclType = false;
|
||||
m_bCastShadow = true;
|
||||
};
|
||||
|
||||
~LMCompLight(){}
|
||||
|
||||
Vec3d vWorldSpaceLightPos; //!<
|
||||
Vec3d vDirection; //!< For directional / spotlights (normalized)
|
||||
float fRadius; //!< >=0
|
||||
float fLightFrustumAngleDegree; //!< For spotlights
|
||||
float fColor[3]; //!< [0..,0..,0..]
|
||||
eLightType eType; //!<
|
||||
|
||||
bool m_bDot3; //!< marks the lightsource to be dot3 vector contributing
|
||||
bool m_bFakeRadiosity; //!< applies a different lighting model
|
||||
bool m_bOcclType; //!< indicates a occlusion map light source type
|
||||
bool m_bCastShadow; //!< indicates whether this lights casts shadow into lightmap or not
|
||||
|
||||
CString m_Name; //!< name of lightsource
|
||||
std::pair<EntityId, EntityId> m_CompLightID; //!< id which the light is referred to from GLMIOcclInfo (the serialization index)
|
||||
|
||||
// CRasterCubeImpl *m_pPointLtRC; //!< Raster cube convering all geometry in the point light's radius
|
||||
RasterCubeUserT *m_pLastIntersection; //!< Filled when ReturnElement() has a new intersection - to optimize the shadow rays
|
||||
CRasterCubeImpl *m_pLastIntersectionRasterCube; //!< stores where cached result belongs to
|
||||
|
||||
uint uiFlags;
|
||||
void * pVisArea;
|
||||
|
||||
//! /return hashing value to detect changes in the data
|
||||
DWORD GetLightHashValue( void ) const
|
||||
{
|
||||
DWORD dwRet=0;
|
||||
|
||||
CalcNCombineHash(vWorldSpaceLightPos,dwRet);
|
||||
CalcNCombineHash(vDirection,dwRet);
|
||||
CalcNCombineHash(fRadius,dwRet);
|
||||
CalcNCombineHash(fLightFrustumAngleDegree,dwRet);
|
||||
CalcNCombineHash(fColor[0],dwRet);
|
||||
CalcNCombineHash(fColor[1],dwRet);
|
||||
CalcNCombineHash(fColor[2],dwRet);
|
||||
CalcNCombineHash((DWORD)eType,dwRet);
|
||||
DWORD ciFlagSum = (m_bFakeRadiosity? 0x11111111 : 0) + (m_bDot3? 0x22222222 : 0) + (m_bCastShadow? 0x44444444 : 0) + (m_bOcclType? 0x88888888 : 0);
|
||||
CalcNCombineHash(ciFlagSum, dwRet);
|
||||
return(dwRet);
|
||||
}
|
||||
};
|
||||
|
||||
// \brief Collection class for passing lights to the compiler, converts 3D engine lights
|
||||
// to LM compiler lights
|
||||
// \sa LMCompLight
|
||||
class CLMLightCollection
|
||||
{
|
||||
public:
|
||||
CLMLightCollection():m_uiOcclLightSize(0){};
|
||||
std::vector<LMCompLight>& GetLights() { return m_vLights; }
|
||||
std::vector<CDLight *>& GetSrcLights() { return m_vSrcLights; };
|
||||
const unsigned int OcclLightSize() {return m_uiOcclLightSize;}
|
||||
//!
|
||||
void Release() { delete this; };
|
||||
|
||||
//! /param pLight must not be 0
|
||||
void AddLight(CDLight *pLight, const CString& rName, const EntityId& rID, const bool cbCastShadow = true)
|
||||
{
|
||||
assert(pLight);
|
||||
|
||||
LMCompLight cNewLight;
|
||||
|
||||
cNewLight.fLightFrustumAngleDegree = pLight->m_fLightFrustumAngle;
|
||||
cNewLight.fColor[0] = pLight->m_Color.r;
|
||||
cNewLight.fColor[1] = pLight->m_Color.g;
|
||||
cNewLight.fColor[2] = pLight->m_Color.b;
|
||||
cNewLight.fRadius = pLight->m_fRadius;
|
||||
cNewLight.vDirection = pLight->m_Orientation.m_vForward;
|
||||
cNewLight.vDirection.Normalize();
|
||||
cNewLight.vWorldSpaceLightPos = pLight->m_Origin;
|
||||
// for Visible Area
|
||||
if(pLight->m_pOwner)
|
||||
{
|
||||
cNewLight.uiFlags = pLight->m_Flags;
|
||||
cNewLight.pVisArea = (void *) pLight->m_pOwner->GetEntityVisArea();
|
||||
}
|
||||
if (pLight->m_Flags & DLF_PROJECT)
|
||||
cNewLight.eType = eSpotlight;
|
||||
else
|
||||
cNewLight.eType = ePoint;
|
||||
|
||||
cNewLight.m_bFakeRadiosity = (pLight->m_Flags & DLF_FAKE_RADIOSITY);
|
||||
cNewLight.m_bDot3 = (pLight->m_Flags & DLF_LMDOT3);
|
||||
cNewLight.m_bOcclType = (pLight->m_Flags & DLF_LMOCCL);
|
||||
cNewLight.m_bCastShadow = cbCastShadow;
|
||||
if(cNewLight.m_bOcclType) m_uiOcclLightSize++;
|
||||
|
||||
cNewLight.m_Name = rName;
|
||||
|
||||
cNewLight.m_CompLightID.first = rID;
|
||||
cNewLight.m_CompLightID.second = m_vLights.size();
|
||||
|
||||
m_vLights.push_back(cNewLight);
|
||||
m_vSrcLights.push_back(pLight);
|
||||
};
|
||||
|
||||
protected:
|
||||
std::vector<LMCompLight> m_vLights; //!< lightmap lights
|
||||
std::vector<CDLight *> m_vSrcLights; //!< source entity
|
||||
unsigned int m_uiOcclLightSize; //!< number of occlusion map light source types
|
||||
};
|
||||
|
||||
#endif
|
||||
1005
Editor/LightmapCompiler/RadMesh.cpp
Normal file
1005
Editor/LightmapCompiler/RadMesh.cpp
Normal file
File diff suppressed because it is too large
Load Diff
679
Editor/LightmapCompiler/RasterCube.h
Normal file
679
Editor/LightmapCompiler/RasterCube.h
Normal file
@@ -0,0 +1,679 @@
|
||||
#pragma once
|
||||
|
||||
#include "RasterTable.h" // CRasterTable
|
||||
#include <assert.h> // assert()
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
template <class T, class T2> class _Matrix34C;
|
||||
template <class T> class _Vector2dC;
|
||||
|
||||
template < class T > class _Vector3dC
|
||||
{
|
||||
public:
|
||||
T p[3];
|
||||
|
||||
// default constructor
|
||||
_Vector3dC ();
|
||||
// constructor
|
||||
_Vector3dC ( T x, T y, T z );
|
||||
_Vector3dC ( const _Vector3dC<T> &x );
|
||||
_Vector3dC ( const _Vector2dC<T> &x );
|
||||
_Vector3dC ( const Vec3d &x ) { p[0]=(T)x.x;p[1]=(T)x.y;p[2]=(T)x.z; }
|
||||
_Vector3dC ( const T &x );
|
||||
|
||||
void Set ( T x, T y, T z );
|
||||
|
||||
void Max ( const _Vector3dC<T> &c );
|
||||
void Min ( const _Vector3dC<T> &c );
|
||||
|
||||
const _Vector3dC<T> operator- ( void ) const;
|
||||
|
||||
_Vector3dC<T> operator- ( const _Vector3dC<T> &other ) const;
|
||||
_Vector3dC<T> operator-= ( const _Vector3dC<T> &other );
|
||||
_Vector3dC<T> operator+ ( const _Vector3dC<T> &other ) const;
|
||||
_Vector3dC<T> operator+= ( const _Vector3dC<T> &other );
|
||||
T operator* ( const _Vector3dC<T> &other ) const;
|
||||
_Vector3dC<T> operator* ( const T fak ) const;
|
||||
_Vector3dC<T> operator*= ( const T fak );
|
||||
_Vector3dC<T> operator/= ( const T fak );
|
||||
bool operator== ( const _Vector3dC<T> &outher ) const;
|
||||
|
||||
T Length ( void ) const;
|
||||
double LengthQuad ( void ) const;
|
||||
void Normalize ( void );
|
||||
|
||||
// a=thumb, b=zeigefinger, b=mittelfinger mit rechter Hand
|
||||
friend _Vector3dC<T> CrossProd ( const _Vector3dC<T> &a, const _Vector3dC<T> &b ); // Kreuzprodukt
|
||||
|
||||
friend _Vector3dC<T> operator* ( const T t, const _Vector3dC<T> &a );
|
||||
};
|
||||
|
||||
template <class T>
|
||||
_Vector3dC<T>::_Vector3dC()
|
||||
{}
|
||||
|
||||
template <class T>
|
||||
_Vector3dC<T>::_Vector3dC( T x, T y, T z )
|
||||
{
|
||||
p[0]=x;p[1]=y;p[2]=z;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
_Vector3dC<T>::_Vector3dC( const T &x )
|
||||
{
|
||||
assert(x==0); // sonst macht das glaub ich keinen Sinn
|
||||
p[0]=x;p[1]=x;p[2]=x;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
_Vector3dC<T>::_Vector3dC( const _Vector3dC<T> &x )
|
||||
{
|
||||
p[0]=x.p[0];p[1]=x.p[1];p[2]=x.p[2];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
_Vector3dC<T>::_Vector3dC( const _Vector2dC<T> &x )
|
||||
{
|
||||
p[0]=x.p[0];p[1]=x.p[1];p[2]=0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void _Vector3dC<T>::Set( T x, T y, T z )
|
||||
{
|
||||
p[0]=x;p[1]=y;p[2]=z;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
_Vector3dC<T> _Vector3dC<T>::operator-( const _Vector3dC<T> &b ) const
|
||||
{
|
||||
return _Vector3dC<T>(p[0]-b.p[0],p[1]-b.p[1],p[2]-b.p[2] );
|
||||
};
|
||||
|
||||
template <class T>
|
||||
_Vector3dC<T> _Vector3dC<T>::operator-=( const _Vector3dC<T> &b )
|
||||
{
|
||||
p[0]-=b.p[0];p[1]-=b.p[1];p[2]-=b.p[2];
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
_Vector3dC<T> _Vector3dC<T>::operator+( const _Vector3dC<T> &b ) const
|
||||
{
|
||||
return _Vector3dC<T>(p[0]+b.p[0],p[1]+b.p[1],p[2]+b.p[2] );
|
||||
}
|
||||
|
||||
template <class T>
|
||||
_Vector3dC<T> _Vector3dC<T>::operator+=( const _Vector3dC<T> &b )
|
||||
{
|
||||
p[0]+=b.p[0];p[1]+=b.p[1];p[2]+=b.p[2];
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
_Vector3dC<T> _Vector3dC<T>::operator*( const T f ) const
|
||||
{
|
||||
return _Vector3dC<T>(p[0]*f,p[1]*f,p[2]*f );
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T _Vector3dC<T>::operator*( const _Vector3dC<T> &b ) const
|
||||
{
|
||||
return(p[0]*b.p[0]+p[1]*b.p[1]+p[2]*b.p[2]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool _Vector3dC<T>::operator==( const _Vector3dC<T> &other ) const
|
||||
{
|
||||
if(p[0]!=other.p[0])return(false);
|
||||
if(p[1]!=other.p[1])return(false);
|
||||
if(p[2]!=other.p[2])return(false);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
_Vector3dC<T> _Vector3dC<T>::operator*=( const T f )
|
||||
{
|
||||
p[0]*=f;p[1]*=f;p[2]*=f;
|
||||
|
||||
return(*this);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
_Vector3dC<T> _Vector3dC<T>::operator/=( const T f )
|
||||
{
|
||||
T fInv=1/f;
|
||||
|
||||
p[0]*=fInv;p[1]*=fInv;p[2]*=fInv;
|
||||
|
||||
return(*this);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
_Vector3dC<T> CrossProd( const _Vector3dC<T> &a, const _Vector3dC<T> &b )
|
||||
{
|
||||
_Vector3dC<T> ret;
|
||||
|
||||
ret.p[0]=a.p[1]*b.p[2] - a.p[2]*b.p[1];
|
||||
ret.p[1]=a.p[2]*b.p[0] - a.p[0]*b.p[2];
|
||||
ret.p[2]=a.p[0]*b.p[1] - a.p[1]*b.p[0];
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void _Vector3dC<T>::Normalize( void )
|
||||
{
|
||||
T len=1.0f/Length();
|
||||
|
||||
p[0]*=len;p[1]*=len;p[2]*=len;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T _Vector3dC<T>::Length( void ) const
|
||||
{
|
||||
return( (T)sqrt(p[0]*p[0]+p[1]*p[1]+p[2]*p[2]) );
|
||||
}
|
||||
|
||||
// unary negation
|
||||
template <class T>
|
||||
const _Vector3dC<T> _Vector3dC<T>::operator-( void ) const
|
||||
{
|
||||
return(_Vector3dC<T>(-p[0],-p[1],-p[2]));
|
||||
}
|
||||
|
||||
typedef _Vector3dC<double> CVector3D;
|
||||
|
||||
|
||||
template <class T>
|
||||
class CPossibleIntersectionSink
|
||||
{
|
||||
public:
|
||||
//! return one element from the bucket
|
||||
//! /param inObject
|
||||
//! /param inoutfRayMaxDist in and out value for max. shooting distance or FLT_MAX, if you found a interesection you may update this because further intersections are no longer interesting
|
||||
//! /return true=do further processing, false=stop I found what I need (e.g. any intersection for shadow testing)
|
||||
bool ReturnElement( T &inObject, float &inoutfRayMaxDist );
|
||||
|
||||
//!
|
||||
void EndReturningBucket( void )
|
||||
{}
|
||||
};
|
||||
|
||||
template <class T, bool bBreakAfterFirstHit = false, bool bUseXRaster = true>
|
||||
class CRasterCube
|
||||
{
|
||||
public:
|
||||
//! default constructor
|
||||
CRasterCube( void );
|
||||
|
||||
//! destructor
|
||||
virtual ~CRasterCube( void );
|
||||
|
||||
//! alloc raster, after that Phase 1 has started
|
||||
//! /param invMin minimum values for the bounding box
|
||||
//! /param invMax maximum values for the bounding box
|
||||
//! /param inElementCount element count for the data structure size estimation
|
||||
//! /param infMagnifier scale factor for internal data structures (scales ~ quadratic in memory consumptions)
|
||||
//! /return true=success, false otherwise
|
||||
bool Init( const CVector3D invMin, const CVector3D invMax, DWORD inElementCount, float infMagnifier=1.0f );
|
||||
|
||||
//! free data
|
||||
void DeInit( void );
|
||||
|
||||
//! Has to be called in Phase1, after that Phase 2 has started
|
||||
//! /param inbDebug debug output is generated
|
||||
//! /return true=success, false otherwise
|
||||
bool PreProcess( const bool inbDebug );
|
||||
|
||||
//! Has to be called after Phase2
|
||||
void Compress( void );
|
||||
|
||||
//! call this per triangle after Init and before PreProcess
|
||||
//! after PreProcess call it again for every triangle
|
||||
//! /param invVertex
|
||||
//! /param inpElement
|
||||
void PutInTriangle( const Vec3d invVertex[3], const T &inElement );
|
||||
|
||||
//!
|
||||
//! /param outdwSize
|
||||
//! /return memory consumption in bytes O(1)
|
||||
DWORD CalcMemoryConsumption( DWORD outdwSize[3] );
|
||||
|
||||
// this works because m_pExtraMemoryPool is sorted in ascending order
|
||||
// returns true if inSink.ReturnElement returns false(meaning stop processing), does not bother if bBreakAfterFirstHit = false
|
||||
template <class Sink>
|
||||
const bool GatherElementsAt( int iniPos[3], Sink &inSink, float& rfRet )
|
||||
{
|
||||
rfRet=FLT_MAX;
|
||||
|
||||
DWORD *pElX = 0;
|
||||
if(bUseXRaster)
|
||||
{
|
||||
pElX=m_XRaster.GetElementsAt(iniPos[1],iniPos[2]); // YZ
|
||||
if(!pElX)return(false);
|
||||
}
|
||||
|
||||
DWORD *pElY=m_YRaster.GetElementsAt(iniPos[2],iniPos[0]); // ZX
|
||||
if(!pElY)return(false);
|
||||
DWORD *pElZ=m_ZRaster.GetElementsAt(iniPos[0],iniPos[1]); // XY
|
||||
if(!pElZ)return(false);
|
||||
|
||||
if(bUseXRaster)
|
||||
assert(*pElX);
|
||||
assert(*pElY);
|
||||
assert(*pElZ);
|
||||
|
||||
// get the intersection of all three lists
|
||||
for(;;)
|
||||
{
|
||||
// increase pointer to the biggest values
|
||||
if(bUseXRaster)
|
||||
{
|
||||
if(*pElY>*pElX)
|
||||
{
|
||||
if(*pElZ>*pElY){ pElZ++;if(*pElZ==0)break; }
|
||||
else { pElY++;if(*pElY==0)break; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if(*pElZ>*pElX){ pElZ++;if(*pElZ==0)break; }
|
||||
else
|
||||
{
|
||||
if(*pElX==*pElY && *pElY==*pElZ)
|
||||
{
|
||||
if(bBreakAfterFirstHit)
|
||||
{
|
||||
if(!inSink.ReturnElement(m_vElements[(*pElX++)-1],rfRet))
|
||||
{
|
||||
inSink.EndReturningBucket();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
inSink.ReturnElement(m_vElements[(*pElX++)-1],rfRet); // -1 because 0 is used for termination
|
||||
if(*pElX==0)break;
|
||||
pElY++;if(*pElY==0)break;
|
||||
pElZ++;if(*pElZ==0)break;
|
||||
}
|
||||
else { pElX++;if(*pElX==0)break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
else//bUseXRaster = false
|
||||
{
|
||||
if(*pElZ > *pElY)
|
||||
{
|
||||
pElZ++;
|
||||
if(*pElZ==0)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(*pElZ < *pElY)
|
||||
{
|
||||
pElY++;
|
||||
if(*pElY==0)
|
||||
break;
|
||||
}
|
||||
else //*pElY == *pElZ
|
||||
{
|
||||
if(bBreakAfterFirstHit)
|
||||
{
|
||||
if(!inSink.ReturnElement(m_vElements[(*pElY++)-1],rfRet))
|
||||
{
|
||||
inSink.EndReturningBucket();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
inSink.ReturnElement(m_vElements[(*pElY++)-1],rfRet); // -1 because 0 is used for termination
|
||||
if(*pElY==0)
|
||||
break;
|
||||
pElZ++;
|
||||
if(*pElZ==0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inSink.EndReturningBucket();
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
// raytracing, gather unsorted hits (sorted could give faster access to the first hit)
|
||||
// call ClearListBefore and GetHitList afterwards
|
||||
// if bBreakAfterFirstHit=true it returns immediately if GatherElementsAt returns true (this is when inSink.ReturnElement returns false(meaning stop processing))
|
||||
template <class Sink>
|
||||
void GatherRayHitsDirection( const CVector3D _invStart, const CVector3D _invDir, Sink &inSink, const float infRayMax=FLT_MAX )
|
||||
{
|
||||
CVector3D invStart,vDirRelative; // scaled to the internal representation
|
||||
|
||||
// tranform the ray into the RasterCubeSpace
|
||||
for(int i=0;i<3;i++)
|
||||
{
|
||||
double fScale=(((double)(m_iSize[i]))/((double)m_vMax.p[i]-(double)m_vMin.p[i]));
|
||||
invStart.p[i]=(_invStart.p[i]-m_vMin.p[i])*fScale; vDirRelative.p[i]=_invDir.p[i]*fScale;
|
||||
}
|
||||
|
||||
CVector3D vDir=vDirRelative;
|
||||
|
||||
int iPos[3]={ (int)floor(invStart.p[0]),(int)floor(invStart.p[1]),(int)floor(invStart.p[2]) }; // floor done
|
||||
|
||||
// integer direction
|
||||
int iDir[3]={ -1,-1,-1 };
|
||||
|
||||
CVector3D vPosInCube( fmod(fabs(invStart.p[0]),1),fmod(fabs(invStart.p[1]),1),fmod(fabs(invStart.p[2]),1) );
|
||||
|
||||
if(vDir.p[0]>0){ iDir[0]=1;vDir.p[0]=-vDir.p[0];vPosInCube.p[0]=1.0f-vPosInCube.p[0]; }
|
||||
if(vDir.p[1]>0){ iDir[1]=1;vDir.p[1]=-vDir.p[1];vPosInCube.p[1]=1.0f-vPosInCube.p[1]; }
|
||||
if(vDir.p[2]>0){ iDir[2]=1;vDir.p[2]=-vDir.p[2];vPosInCube.p[2]=1.0f-vPosInCube.p[2]; }
|
||||
|
||||
// make sure it's in the range 0..1
|
||||
if(vPosInCube.p[0]<=0)vPosInCube.p[0]++;
|
||||
if(vPosInCube.p[1]<=0)vPosInCube.p[1]++;
|
||||
if(vPosInCube.p[2]<=0)vPosInCube.p[2]++;
|
||||
|
||||
assert(vPosInCube.p[0]>0);
|
||||
assert(vPosInCube.p[1]>0);
|
||||
assert(vPosInCube.p[2]>0);
|
||||
assert(vPosInCube.p[0]<=1.0f);
|
||||
assert(vPosInCube.p[1]<=1.0f);
|
||||
assert(vPosInCube.p[2]<=1.0f);
|
||||
|
||||
|
||||
// calculate T and StepT
|
||||
double fT[3],fTStep[3];
|
||||
|
||||
if(vDir.p[0]!=0.0)
|
||||
{ fTStep[0]=1.0/vDir.p[0];fT[0]=vPosInCube.p[0]*fTStep[0]; }
|
||||
else
|
||||
{ fTStep[0]=0.0;fT[0]=-FLT_MAX; }
|
||||
|
||||
if(vDir.p[1]!=0.0)
|
||||
{ fTStep[1]=1.0/vDir.p[1];fT[1]=vPosInCube.p[1]*fTStep[1]; }
|
||||
else
|
||||
{ fTStep[1]=0.0;fT[1]=-FLT_MAX; }
|
||||
|
||||
if(vDir.p[2]!=0.0)
|
||||
{ fTStep[2]=1.0/vDir.p[2];fT[2]=vPosInCube.p[2]*fTStep[2]; }
|
||||
else
|
||||
{ fTStep[2]=0.0;fT[2]=-FLT_MAX; }
|
||||
|
||||
float fRayMax=infRayMax;
|
||||
|
||||
int iEndBorder[3];
|
||||
|
||||
CalcNewBorder(invStart,vDirRelative,fRayMax,iDir,iEndBorder);
|
||||
|
||||
float fNewRayMax;
|
||||
for(;;)
|
||||
{
|
||||
// get elements if we are in the block
|
||||
if((DWORD)iPos[0]<(DWORD)m_iSize[0])
|
||||
if((DWORD)iPos[1]<(DWORD)m_iSize[1])
|
||||
if((DWORD)iPos[2]<(DWORD)m_iSize[2])
|
||||
{
|
||||
if(bBreakAfterFirstHit)
|
||||
{
|
||||
if(GatherElementsAt(iPos,inSink, fNewRayMax))
|
||||
return;//one valid hit found, stop here
|
||||
}
|
||||
else
|
||||
GatherElementsAt(iPos,inSink, fNewRayMax); // Baustelle
|
||||
|
||||
// new Border
|
||||
if(fNewRayMax<fRayMax)
|
||||
{
|
||||
fRayMax=fNewRayMax;
|
||||
|
||||
CalcNewBorder(invStart,vDirRelative,fRayMax,iDir,iEndBorder);
|
||||
}
|
||||
}
|
||||
|
||||
// advance position
|
||||
int iAxis=GetBiggestValue(fT);
|
||||
|
||||
fT[iAxis]+=fTStep[iAxis];
|
||||
iPos[iAxis]+=iDir[iAxis];
|
||||
|
||||
// stop on border hit
|
||||
if(iDir[0]>0){ if(iPos[0]>=iEndBorder[0])break; }
|
||||
else { if(iPos[0]<=iEndBorder[0])break; }
|
||||
if(iDir[1]>0){ if(iPos[1]>=iEndBorder[1])break; }
|
||||
else { if(iPos[1]<=iEndBorder[1])break; }
|
||||
if(iDir[2]>0){ if(iPos[2]>=iEndBorder[2])break; }
|
||||
else { if(iPos[2]<=iEndBorder[2])break; }
|
||||
}
|
||||
}
|
||||
|
||||
template <class Sink>
|
||||
void GatherRayHitsTo( const CVector3D _invStart, const CVector3D _invEnd, Sink &inSink )
|
||||
{
|
||||
CVector3D vDir=_invEnd-_invStart; float fRayMax=(float)vDir.Length();
|
||||
|
||||
vDir.Normalize(); // Baustelle
|
||||
|
||||
GatherRayHitsDirection(_invStart,vDir,inSink,fRayMax);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
CVector3D m_vMin; //!< bounding box min from Init() parameters)
|
||||
CVector3D m_vMax; //!< bounding box max from Init() parameters)
|
||||
int m_iSize[3]; //!< integer size of the internal raster images
|
||||
|
||||
std::vector<T> m_vElements; //!< index to the elements that are put in
|
||||
|
||||
|
||||
CRasterTable<DWORD> m_XRaster; //!< YZ internal raster images - index-1 to m_vElements because 0 is used for termination
|
||||
|
||||
CRasterTable<DWORD> m_YRaster; //!< ZX internal raster images - index-1 to m_vElements because 0 is used for termination
|
||||
CRasterTable<DWORD> m_ZRaster; //!< XY internal raster images - index-1 to m_vElements because 0 is used for termination
|
||||
|
||||
void CalcNewBorder( CVector3D &invStart, CVector3D &invDirRelative, float infRayMax, int iniDir[3], int outiNewBorder[3] )
|
||||
{
|
||||
if(infRayMax==FLT_MAX)
|
||||
{
|
||||
if(iniDir[0]>0)outiNewBorder[0]=m_iSize[0]; else outiNewBorder[0]=-1;
|
||||
if(iniDir[1]>0)outiNewBorder[1]=m_iSize[1]; else outiNewBorder[1]=-1;
|
||||
if(iniDir[2]>0)outiNewBorder[2]=m_iSize[2]; else outiNewBorder[2]=-1;
|
||||
return;
|
||||
}
|
||||
|
||||
CVector3D vNewEnd=invStart + invDirRelative*infRayMax;
|
||||
|
||||
for(int i=0;i<3;i++)
|
||||
{
|
||||
outiNewBorder[i]=(int)floor(vNewEnd.p[i])+iniDir[i];
|
||||
|
||||
if(outiNewBorder[i]<-1)outiNewBorder[i]=-1;
|
||||
|
||||
if(outiNewBorder[i]>m_iSize[i])outiNewBorder[i]=m_iSize[i];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// constructor
|
||||
template <class T, bool bBreakAfterFirstHit, bool bUseXRaster>
|
||||
CRasterCube<T, bBreakAfterFirstHit, bUseXRaster>::CRasterCube( void )
|
||||
{
|
||||
DeInit();
|
||||
}
|
||||
|
||||
// destructor
|
||||
template <class T, bool bBreakAfterFirstHit, bool bUseXRaster>
|
||||
CRasterCube<T, bBreakAfterFirstHit, bUseXRaster>::~CRasterCube( void )
|
||||
{
|
||||
DeInit();
|
||||
}
|
||||
|
||||
|
||||
// free data
|
||||
template <class T, bool bBreakAfterFirstHit, bool bUseXRaster>
|
||||
void CRasterCube<T, bBreakAfterFirstHit, bUseXRaster>::DeInit( void )
|
||||
{
|
||||
if(bUseXRaster)
|
||||
m_XRaster.DeInit();
|
||||
m_YRaster.DeInit();
|
||||
m_ZRaster.DeInit();
|
||||
|
||||
m_iSize[0]=m_iSize[1]=m_iSize[2]=0;
|
||||
}
|
||||
|
||||
// alloc raster, after that Phase 1 has started
|
||||
template <class T, bool bBreakAfterFirstHit, bool bUseXRaster>
|
||||
bool CRasterCube<T, bBreakAfterFirstHit, bUseXRaster>::Init( const CVector3D invMin, const CVector3D invMax, DWORD inElementCount, float infMagnifier )
|
||||
{
|
||||
m_vElements.reserve(inElementCount);
|
||||
|
||||
CVector3D vSize;
|
||||
|
||||
m_vMin=invMin;
|
||||
m_vMax=invMax;
|
||||
vSize=m_vMax-m_vMin;
|
||||
|
||||
float fAvgSize=((float)vSize.p[0]+(float)vSize.p[1]+(float)vSize.p[2])/3.0f;
|
||||
|
||||
if(fAvgSize==0.0f)return(false);
|
||||
|
||||
float fMassSideLength=(float)sqrt((double)inElementCount) * infMagnifier;
|
||||
|
||||
m_iSize[0]=(int)(vSize.p[0]/fAvgSize * fMassSideLength)+2;
|
||||
m_iSize[1]=(int)(vSize.p[1]/fAvgSize * fMassSideLength)+2;
|
||||
m_iSize[2]=(int)(vSize.p[2]/fAvgSize * fMassSideLength)+2;
|
||||
|
||||
/*
|
||||
char str[256];
|
||||
|
||||
sprintf(str,"CRasterCube<T>::Init %dx%dx%d\n",m_iSize[0],m_iSize[1],m_iSize[2]);
|
||||
OutputDebugString(str);
|
||||
*/
|
||||
|
||||
CVector3D vBorder=CVector3D((vSize.p[0]+1.0f)/(float)m_iSize[0],(vSize.p[1]+1.0f)/(float)m_iSize[1],(vSize.p[2]+1.0f)/(float)m_iSize[2]);
|
||||
|
||||
m_vMin-=vBorder*2;
|
||||
m_vMax+=vBorder*2;
|
||||
|
||||
const int iMinimumSize=3;
|
||||
|
||||
if(m_iSize[0]<iMinimumSize)m_iSize[0]=iMinimumSize;
|
||||
if(m_iSize[1]<iMinimumSize)m_iSize[1]=iMinimumSize;
|
||||
if(m_iSize[2]<iMinimumSize)m_iSize[2]=iMinimumSize;
|
||||
if(bUseXRaster)
|
||||
if(!m_XRaster.Init(m_iSize[1],m_iSize[2])) // YZ
|
||||
return(false);
|
||||
if(!m_YRaster.Init(m_iSize[2],m_iSize[0])) // ZX
|
||||
return(false);
|
||||
if(!m_ZRaster.Init(m_iSize[0],m_iSize[1])) // XY
|
||||
return(false);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
// call this per triangle after Init and before PreProcess
|
||||
// after PreProcess call it again for every triangle
|
||||
template <class T, bool bBreakAfterFirstHit, bool bUseXRaster>
|
||||
void CRasterCube<T, bBreakAfterFirstHit, bUseXRaster>::PutInTriangle( const Vec3d invVertices[3], const T &inpElement )
|
||||
{
|
||||
float fX[3],fY[3];
|
||||
double fScale[3];
|
||||
DWORD dwElementNo=(DWORD)(m_vElements.size()+1); // +1 because 0 is used for termination
|
||||
|
||||
fScale[0]=(((double)(m_iSize[0]))/(m_vMax.p[0]-m_vMin.p[0]));
|
||||
fScale[1]=(((double)(m_iSize[1]))/(m_vMax.p[1]-m_vMin.p[1]));
|
||||
fScale[2]=(((double)(m_iSize[2]))/(m_vMax.p[2]-m_vMin.p[2]));
|
||||
if(bUseXRaster)
|
||||
{
|
||||
fX[0]=(float)((invVertices[0].y-m_vMin.p[1])*fScale[1]);fY[0]=(float)((invVertices[0].z-m_vMin.p[2])*fScale[2]);
|
||||
fX[1]=(float)((invVertices[1].y-m_vMin.p[1])*fScale[1]);fY[1]=(float)((invVertices[1].z-m_vMin.p[2])*fScale[2]);
|
||||
fX[2]=(float)((invVertices[2].y-m_vMin.p[1])*fScale[1]);fY[2]=(float)((invVertices[2].z-m_vMin.p[2])*fScale[2]);
|
||||
m_XRaster.PutInTriangle(fX,fY,dwElementNo);
|
||||
}
|
||||
fX[0]=(float)((invVertices[0].z-m_vMin.p[2])*fScale[2]);fY[0]=(float)((invVertices[0].x-m_vMin.p[0])*fScale[0]);
|
||||
fX[1]=(float)((invVertices[1].z-m_vMin.p[2])*fScale[2]);fY[1]=(float)((invVertices[1].x-m_vMin.p[0])*fScale[0]);
|
||||
fX[2]=(float)((invVertices[2].z-m_vMin.p[2])*fScale[2]);fY[2]=(float)((invVertices[2].x-m_vMin.p[0])*fScale[0]);
|
||||
m_YRaster.PutInTriangle(fX,fY,dwElementNo);
|
||||
|
||||
fX[0]=(float)((invVertices[0].x-m_vMin.p[0])*fScale[0]);fY[0]=(float)((invVertices[0].y-m_vMin.p[1])*fScale[1]);
|
||||
fX[1]=(float)((invVertices[1].x-m_vMin.p[0])*fScale[0]);fY[1]=(float)((invVertices[1].y-m_vMin.p[1])*fScale[1]);
|
||||
fX[2]=(float)((invVertices[2].x-m_vMin.p[0])*fScale[0]);fY[2]=(float)((invVertices[2].y-m_vMin.p[1])*fScale[1]);
|
||||
m_ZRaster.PutInTriangle(fX,fY,dwElementNo);
|
||||
|
||||
m_vElements.push_back(inpElement);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Has to be called in Phase1, after that Phase 2 has started
|
||||
template <class T, bool bBreakAfterFirstHit, bool bUseXRaster>
|
||||
bool CRasterCube<T, bBreakAfterFirstHit, bUseXRaster>::PreProcess( const bool inbDebug )
|
||||
{
|
||||
if(inbDebug)
|
||||
{
|
||||
if(bUseXRaster)
|
||||
m_XRaster.Debug("CRasterCubeDebugX.tga");
|
||||
m_YRaster.Debug("CRasterCubeDebugY.tga");
|
||||
m_ZRaster.Debug("CRasterCubeDebugZ.tga");
|
||||
}
|
||||
|
||||
if(bUseXRaster)
|
||||
if(!m_XRaster.PreProcess()) return(false);
|
||||
if(!m_YRaster.PreProcess()) return(false);
|
||||
if(!m_ZRaster.PreProcess()) return(false);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
// Has to be called in Phase1, after that Phase 2 has started
|
||||
template <class T, bool bBreakAfterFirstHit, bool bUseXRaster>
|
||||
void CRasterCube<T, bBreakAfterFirstHit, bUseXRaster>::Compress( void )
|
||||
{
|
||||
if(bUseXRaster)
|
||||
m_XRaster.Compress();
|
||||
m_YRaster.Compress();
|
||||
m_ZRaster.Compress();
|
||||
}
|
||||
|
||||
|
||||
//! /param inT
|
||||
//! /return 0/1/2 plane axis that was hit
|
||||
__forceinline int GetBiggestValue( double inT[3] )
|
||||
{
|
||||
// get the biggest value
|
||||
|
||||
if(inT[0]>inT[1])
|
||||
{
|
||||
if(inT[2]>inT[0])
|
||||
return(2);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(inT[2]>inT[1])
|
||||
return(2);
|
||||
else
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
|
||||
// calculates memory consumption in bytes O(1)
|
||||
template <class T, bool bBreakAfterFirstHit, bool bUseXRaster>
|
||||
DWORD CRasterCube<T, bBreakAfterFirstHit, bUseXRaster>::CalcMemoryConsumption( DWORD outdwSize[3] )
|
||||
{
|
||||
outdwSize[0]=m_iSize[0];
|
||||
outdwSize[1]=m_iSize[1];
|
||||
outdwSize[2]=m_iSize[2];
|
||||
if(bUseXRaster)
|
||||
return(m_XRaster.CalcMemoryConsumption()+m_YRaster.CalcMemoryConsumption()+m_ZRaster.CalcMemoryConsumption()+sizeof(*this));
|
||||
else
|
||||
return(m_YRaster.CalcMemoryConsumption()+m_ZRaster.CalcMemoryConsumption()+sizeof(*this));
|
||||
}
|
||||
462
Editor/LightmapCompiler/RasterTable.h
Normal file
462
Editor/LightmapCompiler/RasterTable.h
Normal file
@@ -0,0 +1,462 @@
|
||||
#pragma once
|
||||
|
||||
#include <assert.h> // assert()
|
||||
#include "SimpleTriangleRasterizer.h" // CSimpleTriangleRasterizer
|
||||
|
||||
// This class is to speed up raycasting queries.
|
||||
// each element in a 2D raster has a pointer (or zero) to a few elements in a second memory(elemets: void *) (0 teminated)
|
||||
// The raster can be used to query elements on a 3D line - if you project the 3D World down to that raster from one side.
|
||||
// To get the maximum speedup you shoudl do this from 3 sides.
|
||||
|
||||
template <class T>
|
||||
class CRasterTable
|
||||
{
|
||||
public:
|
||||
//! constructor
|
||||
CRasterTable( void );
|
||||
|
||||
//! destructor
|
||||
virtual ~CRasterTable( void );
|
||||
|
||||
//! alloc raster, after that Phase 1 has started
|
||||
//! /param indwXSize 1..
|
||||
//! /param indwYSize 1..
|
||||
//! /return true=success, false otherwise
|
||||
bool Init( const DWORD indwXSize, const DWORD indwYSize );
|
||||
|
||||
//!
|
||||
//! free data
|
||||
void DeInit( void );
|
||||
|
||||
//! Has to be called in Phase 1, after Phase 2 has started
|
||||
//! /return true=success, false otherwise
|
||||
bool PreProcess( void );
|
||||
|
||||
//! call this per triangle after Init and before PreProcess
|
||||
//! after PreProcess call it again for every triangle
|
||||
//! /param infX[3] x coordiantes of the 3 vertices in raster units
|
||||
//! /param infX[3] y coordiantes of the 3 vertices in raster units
|
||||
//! /param inElement element you want to store
|
||||
void PutInTriangle( float infX[3], float infY[3], T &inElement );
|
||||
|
||||
//! returns pointer to zero terminated array of pointers
|
||||
//! /param iniX 0..m_dwXSize-1
|
||||
//! /param iniY 0..m_dwYSize-1
|
||||
//! /return
|
||||
T *GetElementsAt( int iniX, int iniY );
|
||||
|
||||
//!
|
||||
//! /return memory consumption in bytes O(1)
|
||||
DWORD CalcMemoryConsumption( void );
|
||||
|
||||
//!
|
||||
//! /param inPathFileName filename with path and extension
|
||||
void Debug( const char *inPathFileName ) const;
|
||||
|
||||
//!
|
||||
//! /param outPitchInBytes
|
||||
//! /return
|
||||
DWORD *GetDebugData( DWORD &outPitchInBytes ) const;
|
||||
|
||||
//!
|
||||
//! /return width in raster elements
|
||||
DWORD GetWidth( void );
|
||||
|
||||
//!
|
||||
//! /return height in raster elements
|
||||
DWORD GetHeight( void );
|
||||
|
||||
//! to save memory and make it faster - less cache misses)
|
||||
// IF YOU WANNA USE THIS FUNCTION, CLEAR IT FIRST BECAUSE IT SIMPLY DOES NOT WORK
|
||||
void Compress( void );
|
||||
|
||||
// **************************************************************
|
||||
|
||||
union
|
||||
{
|
||||
DWORD * m_pDataCounter; //!< used in Phase 1 [m_dwXSize*m_dwYSize]
|
||||
T ** m_pDataPtr; //!< used in Phase 2 [m_dwXSize*m_dwYSize]
|
||||
};
|
||||
|
||||
private:
|
||||
T * m_pExtraMemoryPool; //!< for the pointers to store (zero terminated) (sorted in ascending order) [m_ExtraMemorySize]
|
||||
DWORD m_ExtraMemorySize; //!< extra memroy pool size in StoredElementPtr elements
|
||||
|
||||
DWORD m_dwXSize; //!< width of the buffer 1.. if allocated, otherwise 0
|
||||
DWORD m_dwYSize; //!< height of the buffer 1.. if allocated, otherwise 0
|
||||
|
||||
|
||||
|
||||
//! callback function
|
||||
class CPixelIncrement: public CSimpleTriangleRasterizer::IRasterizeSink
|
||||
{
|
||||
public:
|
||||
|
||||
//! constructor
|
||||
CPixelIncrement( DWORD *inpBuffer, DWORD indwWidth, DWORD indwHeight )
|
||||
{
|
||||
m_pBuffer=inpBuffer;
|
||||
m_dwWidth=indwWidth;
|
||||
m_dwHeight=indwHeight;
|
||||
}
|
||||
|
||||
//!
|
||||
virtual void Line( const float infXLeft, const float infXRight,
|
||||
const int iniLeft, const int iniRight, const int iniY )
|
||||
{
|
||||
assert(iniLeft>=0);
|
||||
assert(iniY>=0);
|
||||
assert(iniRight<=(int)m_dwWidth);
|
||||
assert(iniY<(int)m_dwHeight);
|
||||
|
||||
DWORD *pMem=&m_pBuffer[iniLeft+iniY*m_dwWidth];
|
||||
|
||||
for(int x=iniLeft;x<iniRight;x++)
|
||||
{
|
||||
*pMem=*pMem+1;
|
||||
pMem++;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD * m_pBuffer; //!<
|
||||
DWORD m_dwWidth; //!< x= [0,m_dwWidth[
|
||||
DWORD m_dwHeight; //!< y= [0,m_dwHeight[
|
||||
};
|
||||
|
||||
|
||||
//! callback function
|
||||
template <class T>
|
||||
class CPixelAddArrayElement: public CSimpleTriangleRasterizer::IRasterizeSink
|
||||
{
|
||||
public:
|
||||
|
||||
//! constructor
|
||||
CPixelAddArrayElement( T **inpBuffer, DWORD indwWidth, T *inElementPtr )
|
||||
{
|
||||
m_pBuffer=inpBuffer;
|
||||
m_dwWidth=indwWidth;
|
||||
m_ElementPtr=inElementPtr;
|
||||
}
|
||||
|
||||
//!
|
||||
__forceinline void ReturnPixel( T * &rPtr )
|
||||
{
|
||||
--rPtr;
|
||||
*rPtr=*m_ElementPtr;
|
||||
}
|
||||
|
||||
//!
|
||||
virtual void Line( const float infXLeft, const float infXRight,
|
||||
const int iniLeft, const int iniRight, const int iniY )
|
||||
{
|
||||
T **pMem=&m_pBuffer[iniLeft+iniY*m_dwWidth];
|
||||
|
||||
for(int x=iniLeft;x<iniRight;x++)
|
||||
ReturnPixel(*pMem++);
|
||||
}
|
||||
|
||||
T * m_ElementPtr; //!< element to store
|
||||
T ** m_pBuffer; //!< pointer to the array buffer
|
||||
DWORD m_dwWidth; //!< width of the buffer
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
// constructor
|
||||
template <class T>
|
||||
CRasterTable<T>::CRasterTable( void )
|
||||
{
|
||||
assert(sizeof(DWORD)==sizeof(DWORD *)); // only for 32 Bit compiler
|
||||
|
||||
m_pDataPtr=0;
|
||||
m_pExtraMemoryPool=0;
|
||||
m_ExtraMemorySize=0;
|
||||
}
|
||||
|
||||
// destructor
|
||||
template <class T>
|
||||
CRasterTable<T>::~CRasterTable( void )
|
||||
{
|
||||
DeInit();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// free data
|
||||
template <class T>
|
||||
void CRasterTable<T>::DeInit( void )
|
||||
{
|
||||
delete [] m_pDataCounter;m_pDataCounter=0;
|
||||
delete [] m_pExtraMemoryPool;m_pExtraMemoryPool=0;
|
||||
m_ExtraMemorySize=0;
|
||||
m_dwXSize=0;
|
||||
m_dwYSize=0;
|
||||
}
|
||||
|
||||
|
||||
// alloc raster, after that Phase 1 has started
|
||||
template <class T>
|
||||
bool CRasterTable<T>::Init( const DWORD indwXSize, const DWORD indwYSize )
|
||||
{
|
||||
assert(!m_pDataCounter);
|
||||
assert(!m_pExtraMemoryPool); DeInit();
|
||||
assert(indwXSize);
|
||||
assert(indwYSize);
|
||||
|
||||
m_dwXSize=indwXSize;
|
||||
m_dwYSize=indwYSize;
|
||||
|
||||
assert(sizeof(DWORD)==sizeof(T *));
|
||||
m_pDataCounter=new DWORD[m_dwXSize*m_dwYSize];
|
||||
|
||||
if(m_pDataCounter)
|
||||
memset(m_pDataCounter,0,m_dwXSize*m_dwYSize*sizeof(DWORD));
|
||||
|
||||
return(m_pDataPtr!=0);
|
||||
}
|
||||
|
||||
|
||||
// Has to be called in Phase1, after that Phase 2 has started
|
||||
template <class T>
|
||||
bool CRasterTable<T>::PreProcess( void )
|
||||
{
|
||||
assert(m_pDataCounter);
|
||||
assert(!m_pExtraMemoryPool);
|
||||
assert(!m_ExtraMemorySize);
|
||||
|
||||
DWORD dwSum=0; // extra memroy pool size in StoredElementPtr elements
|
||||
|
||||
{
|
||||
DWORD *ptr=m_pDataCounter;
|
||||
|
||||
for(DWORD i=0;i<m_dwXSize*m_dwYSize;i++)
|
||||
{
|
||||
DWORD dwNumEl=*ptr++;
|
||||
|
||||
if(dwNumEl!=0)
|
||||
dwSum+=dwNumEl+1; // Elements + NullTermination
|
||||
}
|
||||
}
|
||||
|
||||
if(dwSum==0)return(true); // no information to store - no problem
|
||||
|
||||
m_pExtraMemoryPool=new T[dwSum];
|
||||
|
||||
m_ExtraMemorySize=dwSum;
|
||||
|
||||
if(!m_pExtraMemoryPool)return(false);
|
||||
|
||||
memset(m_pExtraMemoryPool,0,dwSum*sizeof(T));
|
||||
|
||||
// build the access structure for compressing the elements in a vector (pointer is in the beginning on the last element)
|
||||
// after filing in the triangles once again the pointer is on the first element
|
||||
{
|
||||
DWORD *ptr1=m_pDataCounter;
|
||||
T **ptr2=m_pDataPtr;
|
||||
T *dest=m_pExtraMemoryPool;
|
||||
|
||||
for(DWORD i=0;i<m_dwXSize*m_dwYSize;i++)
|
||||
{
|
||||
DWORD dwNumEl=*ptr1++;
|
||||
|
||||
if(dwNumEl!=0)
|
||||
{
|
||||
dest+=dwNumEl;
|
||||
*ptr2++=dest;
|
||||
dest++; // Elements + NullTermination
|
||||
}
|
||||
else *ptr2++=0;
|
||||
}
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// call this per triangle after Init and before PreProcess
|
||||
// after PreProcess call it again for every triangle
|
||||
template <class T>
|
||||
void CRasterTable<T>::PutInTriangle( float infX[3], float infY[3], T &inElement )
|
||||
{
|
||||
float fU[3],fV[3];
|
||||
|
||||
for(int i=0;i<3;i++)
|
||||
{
|
||||
fU[i]=infX[i];fV[i]=infY[i];
|
||||
}
|
||||
|
||||
CSimpleTriangleRasterizer Rasterizer(m_dwXSize,m_dwYSize);
|
||||
|
||||
if(m_pExtraMemoryPool==0) // Phase 1
|
||||
{
|
||||
CPixelIncrement pix(m_pDataCounter,m_dwXSize,m_dwYSize);
|
||||
|
||||
Rasterizer.CallbackFillConservative(fU,fV,&pix);
|
||||
}
|
||||
else // Phase 2
|
||||
{
|
||||
CPixelAddArrayElement<T> pix(m_pDataPtr,m_dwXSize,&inElement);
|
||||
|
||||
Rasterizer.CallbackFillConservative(fU,fV,&pix);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// returns pointer to zero terminated array of pointers
|
||||
template <class T>
|
||||
T *CRasterTable<T>::GetElementsAt( int iniX, int iniY )
|
||||
{
|
||||
assert(iniX>=0);
|
||||
assert(iniX<(int)m_dwXSize);
|
||||
assert(iniY>=0);
|
||||
assert(iniY<(int)m_dwYSize);
|
||||
|
||||
T *pRet=m_pDataPtr[iniY*m_dwXSize+iniX];
|
||||
|
||||
if(pRet)
|
||||
assert(*pRet); // no pointer in the raster should point to empty list
|
||||
|
||||
return(pRet);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// returns pointer to zero terminated array of pointers
|
||||
// IF YOU WANNA USE THIS FUNCTION, CLEAR IT FIRST BECAUSE IT SIMPLY DOES NOT WORK
|
||||
template <class T>
|
||||
void CRasterTable<T>::Compress( void )
|
||||
{
|
||||
if(!m_pExtraMemoryPool)return;
|
||||
|
||||
T *pDestStart=0;
|
||||
DWORD dwNewMemorySize=0;
|
||||
|
||||
for(DWORD i=0;i<m_dwXSize*m_dwYSize;i++)
|
||||
{
|
||||
T *pSrcStart=m_pDataPtr[i]; // pointer from the raster element
|
||||
|
||||
if(!pSrcStart)continue; // no elements there
|
||||
|
||||
{
|
||||
bool bAddBucket=true;
|
||||
T *pSrc=pSrcStart, *pDest=pDestStart;
|
||||
|
||||
if(pDestStart)
|
||||
while(*pSrc == *pDest)
|
||||
{
|
||||
if(*pSrc==0)
|
||||
{
|
||||
// buckets are fully identical
|
||||
bAddBucket=false;
|
||||
break;
|
||||
}
|
||||
|
||||
pDest++;pSrc++;
|
||||
}
|
||||
|
||||
if(bAddBucket)
|
||||
{
|
||||
if(!pDestStart) pDestStart=m_pExtraMemoryPool;
|
||||
else
|
||||
{
|
||||
while(*pDestStart)pDestStart++; pDestStart++;
|
||||
}
|
||||
|
||||
// copy bucket
|
||||
T *pSrc=pSrcStart, *pDest=pDestStart;
|
||||
|
||||
while(*pSrc)
|
||||
{ *pDest++=*pSrc++;dwNewMemorySize++; }
|
||||
|
||||
*pDest++=0; // 0 terminate
|
||||
assert(*pDestStart); // no pointer in the raster should point to empty list
|
||||
|
||||
m_pDataPtr[i]=pDestStart;
|
||||
}
|
||||
else m_pDataPtr[i]=pDestStart;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
T *newMem=new T[dwNewMemorySize];
|
||||
|
||||
if(!newMem)return; // no memory - no compression
|
||||
|
||||
// copy in new buffer
|
||||
memcpy(newMem,m_pExtraMemoryPool,dwNewMemorySize*sizeof(T));
|
||||
|
||||
// correct the pointers to the new buffer
|
||||
for(i=0;i<m_dwXSize*m_dwYSize;i++)
|
||||
{
|
||||
if(m_pDataPtr[i])
|
||||
{
|
||||
assert(*m_pDataPtr[i]); // no pointer in the raster should point to empty list
|
||||
m_pDataPtr[i]=(T *)( (DWORD)(m_pDataPtr[i]) - (DWORD)m_pExtraMemoryPool + (DWORD)newMem);
|
||||
assert(*m_pDataPtr[i]); // no pointer in the raster should point to empty list
|
||||
}
|
||||
}
|
||||
|
||||
delete [] m_pExtraMemoryPool;
|
||||
|
||||
// set new buffer
|
||||
m_pExtraMemoryPool=newMem;
|
||||
|
||||
float fRatio=(float)dwNewMemorySize/(float)m_ExtraMemorySize;
|
||||
}
|
||||
|
||||
|
||||
// calculates memory consumption in bytes O(1)
|
||||
template <class T>
|
||||
DWORD CRasterTable<T>::CalcMemoryConsumption( void )
|
||||
{
|
||||
return(m_dwXSize*m_dwYSize*sizeof(m_pDataCounter)+m_ExtraMemorySize*sizeof(T));
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
void CRasterTable<T>::Debug( const char *inPathFileName ) const
|
||||
{
|
||||
#ifdef _TGA_LOADER_INCLUDED
|
||||
for(DWORD i=0;i<m_dwXSize*m_dwYSize;i++)
|
||||
m_pDataCounter[i]=m_pDataCounter[i]*10+0x0800;
|
||||
|
||||
PIX_SaveTGA32(inPathFileName,(unsigned char *)m_pDataCounter,m_dwXSize,m_dwYSize,false,false);
|
||||
|
||||
for(DWORD i=0;i<m_dwXSize*m_dwYSize;i++)
|
||||
m_pDataCounter[i]=(m_pDataCounter[i]-0x0800)/10;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class T>
|
||||
DWORD *CRasterTable<T>::GetDebugData( DWORD &outPitchInBytes ) const
|
||||
{
|
||||
outPitchInBytes=m_dwXSize*sizeof(DWORD);
|
||||
return(m_pDataCounter);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class T>
|
||||
DWORD CRasterTable<T>::GetWidth( void )
|
||||
{
|
||||
return(m_dwXSize);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
DWORD CRasterTable<T>::GetHeight( void )
|
||||
{
|
||||
return(m_dwYSize);
|
||||
}
|
||||
|
||||
354
Editor/LightmapCompiler/SimpleTriangleRasterizer.cpp
Normal file
354
Editor/LightmapCompiler/SimpleTriangleRasterizer.cpp
Normal file
@@ -0,0 +1,354 @@
|
||||
#include "stdafx.h" // precompiled headers
|
||||
#include "SimpleTriangleRasterizer.h" // CSimpleTriangleRastizer
|
||||
#include <math.h> // sqrt()
|
||||
|
||||
#define FLT_MAX 3.402823466e+38F
|
||||
|
||||
#ifndef min
|
||||
#define min(a,b) ((a)<(b)?(a):(b))
|
||||
#endif
|
||||
#ifndef max
|
||||
#define max(a,b) ((a)>(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
|
||||
void CSimpleTriangleRasterizer::lambertHorizlineConservative( float fx1, float fx2, int yy, IRasterizeSink *inpSink )
|
||||
{
|
||||
int x1=(int)floorf(fx1),x2=(int)floorf(fx2+1.0f);
|
||||
|
||||
if(x1<m_iMinX)x1=m_iMinX;
|
||||
if(x2>m_iMaxX+1)x2=m_iMaxX+1;
|
||||
if(x1>m_iMaxX+1)x1=m_iMaxX+1;
|
||||
if(x2<m_iMinX)x2=m_iMinX;
|
||||
|
||||
|
||||
inpSink->Line(fx1,fx2,x1,x2,yy);
|
||||
}
|
||||
|
||||
void CSimpleTriangleRasterizer::lambertHorizlineSubpixelCorrect( float fx1, float fx2, int yy, IRasterizeSink *inpSink )
|
||||
{
|
||||
int x1=(int)floorf(fx1+0.5f),x2=(int)floorf(fx2+0.5f);
|
||||
|
||||
if(x1<m_iMinX)x1=m_iMinX;
|
||||
if(x2>m_iMaxX+1)x2=m_iMaxX+1;
|
||||
if(x1>m_iMaxX+1)x1=m_iMaxX+1;
|
||||
if(x2<m_iMinX)x2=m_iMinX;
|
||||
|
||||
inpSink->Line(fx1,fx2,x1,x2,yy);
|
||||
}
|
||||
|
||||
// optimizable
|
||||
void CSimpleTriangleRasterizer::CopyAndSortY( const float infX[3], const float infY[3], float outfX[3], float outfY[3] )
|
||||
{
|
||||
outfX[0]=infX[0];outfY[0]=infY[0];
|
||||
outfX[1]=infX[1];outfY[1]=infY[1];
|
||||
outfX[2]=infX[2];outfY[2]=infY[2];
|
||||
|
||||
// Sort the coordinates, so that (x[1], y[1]) becomes the highest coord
|
||||
float tmp;
|
||||
|
||||
if(outfY[0]>outfY[1])
|
||||
{
|
||||
if(outfY[1]>outfY[2])
|
||||
{
|
||||
tmp=outfY[0];outfY[0]=outfY[1];outfY[1]=tmp;
|
||||
tmp=outfX[0];outfX[0]=outfX[1];outfX[1]=tmp;
|
||||
tmp=outfY[1];outfY[1]=outfY[2];outfY[2]=tmp;
|
||||
tmp=outfX[1];outfX[1]=outfX[2];outfX[2]=tmp;
|
||||
|
||||
if(outfY[0]>outfY[1])
|
||||
{
|
||||
tmp=outfY[0];outfY[0]=outfY[1];outfY[1]=tmp;
|
||||
tmp=outfX[0];outfX[0]=outfX[1];outfX[1]=tmp;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp=outfY[0];outfY[0]=outfY[1];outfY[1]=tmp;
|
||||
tmp=outfX[0];outfX[0]=outfX[1];outfX[1]=tmp;
|
||||
|
||||
if(outfY[1]>outfY[2])
|
||||
{
|
||||
tmp=outfY[1];outfY[1]=outfY[2];outfY[2]=tmp;
|
||||
tmp=outfX[1];outfX[1]=outfX[2];outfX[2]=tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(outfY[1]>outfY[2])
|
||||
{
|
||||
tmp=outfY[1];outfY[1]=outfY[2];outfY[2]=tmp;
|
||||
tmp=outfX[1];outfX[1]=outfX[2];outfX[2]=tmp;
|
||||
|
||||
if(outfY[0]>outfY[1])
|
||||
{
|
||||
tmp=outfY[0];outfY[0]=outfY[1];outfY[1]=tmp;
|
||||
tmp=outfX[0];outfX[0]=outfX[1];outfX[1]=tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSimpleTriangleRasterizer::CallbackFillRectConservative( float _x[3], float _y[3], IRasterizeSink *inpSink )
|
||||
{
|
||||
inpSink->Triangle(m_iMinY);
|
||||
|
||||
float fMinX=min(_x[0],min(_x[1],_x[2]));
|
||||
float fMaxX=max(_x[0],max(_x[1],_x[2]));
|
||||
float fMinY=min(_y[0],min(_y[1],_y[2]));
|
||||
float fMaxY=max(_y[0],max(_y[1],_y[2]));
|
||||
|
||||
int iMinX=max(m_iMinX,(int)floorf(fMinX));
|
||||
int iMaxX=min(m_iMaxX+1,(int)ceilf(fMaxX));
|
||||
int iMinY=max(m_iMinY,(int)floorf(fMinY));
|
||||
int iMaxY=min(m_iMaxY+1,(int)ceilf(fMaxY));
|
||||
|
||||
for(int y=iMinY;y<iMaxY;y++)
|
||||
inpSink->Line(fMinX,fMaxX,iMinX,iMaxX,y);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void CSimpleTriangleRasterizer::CallbackFillConservative( float _x[3], float _y[3], IRasterizeSink *inpSink )
|
||||
{
|
||||
float x[3],y[3];
|
||||
|
||||
CopyAndSortY(_x,_y,x,y);
|
||||
|
||||
// Calculate interpolation steps
|
||||
float fX1toX2step=0.0f; if(y[1]-y[0]!=0.0f)fX1toX2step=(x[1]-x[0])/(float)(y[1]-y[0]);
|
||||
float fX1toX3step=0.0f; if(y[2]-y[0]!=0.0f)fX1toX3step=(x[2]-x[0])/(float)(y[2]-y[0]);
|
||||
float fX2toX3step=0.0f; if(y[2]-y[1]!=0.0f)fX2toX3step=(x[2]-x[1])/(float)(y[2]-y[1]);
|
||||
|
||||
float fX1toX2=x[0], fX1toX3=x[0], fX2toX3=x[1];
|
||||
bool bFirstLine=true;
|
||||
bool bTriangleCallDone=false;
|
||||
|
||||
// Go through the scanlines of the triangle
|
||||
int yy=(int)floorf(y[0]); // was floor
|
||||
|
||||
for(; yy<=(int)floorf(y[2]); yy++)
|
||||
// for(yy=m_iMinY; yy<=m_iMaxY; yy++) // juhu
|
||||
{
|
||||
float fSubPixelYStart=0.0f,fSubPixelYEnd=1.0f;
|
||||
float start,end;
|
||||
|
||||
// first line
|
||||
if(bFirstLine)
|
||||
{
|
||||
fSubPixelYStart=y[0]-floorf(y[0]);
|
||||
start=x[0];end=x[0];bFirstLine=false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// top part without middle corner line
|
||||
if(yy<=(int)floorf(y[1]))
|
||||
{
|
||||
start=min(fX1toX2,fX1toX3);end=max(fX1toX2,fX1toX3);
|
||||
}
|
||||
else
|
||||
{
|
||||
start=min(fX2toX3,fX1toX3);end=max(fX2toX3,fX1toX3);
|
||||
}
|
||||
}
|
||||
|
||||
// middle corner line
|
||||
if(yy==(int)floorf(y[1]))
|
||||
{
|
||||
fSubPixelYEnd=y[1]-floorf(y[1]);
|
||||
|
||||
fX1toX3+=fX1toX3step*(fSubPixelYEnd-fSubPixelYStart);
|
||||
start=min(start,fX1toX3);end=max(end,fX1toX3);
|
||||
start=min(start,x[1]);end=max(end,x[1]);
|
||||
|
||||
fSubPixelYStart=fSubPixelYEnd;fSubPixelYEnd=1.0f;
|
||||
}
|
||||
|
||||
// last line
|
||||
if(yy==(int)floorf(y[2]))
|
||||
{
|
||||
start=min(start,x[2]);end=max(end,x[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// top part without middle corner line
|
||||
if(yy<(int)floorf(y[1]))
|
||||
{
|
||||
fX1toX2+=fX1toX2step*(fSubPixelYEnd-fSubPixelYStart);
|
||||
start=min(start,fX1toX2);end=max(end,fX1toX2);
|
||||
}
|
||||
else
|
||||
{
|
||||
fX2toX3+=fX2toX3step*(fSubPixelYEnd-fSubPixelYStart);
|
||||
start=min(start,fX2toX3);end=max(end,fX2toX3);
|
||||
}
|
||||
|
||||
fX1toX3+=fX1toX3step*(fSubPixelYEnd-fSubPixelYStart);
|
||||
start=min(start,fX1toX3);end=max(end,fX1toX3);
|
||||
}
|
||||
|
||||
if(yy>=m_iMinY && yy<=m_iMaxY)
|
||||
{
|
||||
if(!bTriangleCallDone){ inpSink->Triangle(yy);bTriangleCallDone=true; }
|
||||
|
||||
lambertHorizlineConservative(start,end,yy,inpSink);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CSimpleTriangleRasterizer::CallbackFillSubpixelCorrect( float _x[3], float _y[3], IRasterizeSink *inpSink )
|
||||
{
|
||||
float x[3],y[3];
|
||||
|
||||
CopyAndSortY(_x,_y,x,y);
|
||||
|
||||
if(y[0]-floorf(y[0])==0.0f)y[0]-=0.0001f;
|
||||
|
||||
// Calculate interpolation steps
|
||||
float fX1toX2step=0.0f; if(y[1]-y[0]!=0.0f)fX1toX2step=(x[1]-x[0])/(float)(y[1]-y[0]);
|
||||
float fX1toX3step=0.0f; if(y[2]-y[0]!=0.0f)fX1toX3step=(x[2]-x[0])/(float)(y[2]-y[0]);
|
||||
float fX2toX3step=0.0f; if(y[2]-y[1]!=0.0f)fX2toX3step=(x[2]-x[1])/(float)(y[2]-y[1]);
|
||||
|
||||
float fX1toX2=x[0], fX1toX3=x[0], fX2toX3=x[1];
|
||||
bool bFirstLine=true;
|
||||
bool bTriangleCallDone=false;
|
||||
|
||||
y[0]-=0.5f;y[1]-=0.5f;y[2]-=0.5f;
|
||||
|
||||
int yy=(int)floorf(y[0]);
|
||||
|
||||
for(; yy<=(int)floorf(y[2]); yy++)
|
||||
{
|
||||
float fSubPixelYStart=0.0f,fSubPixelYEnd=1.0f;
|
||||
float start,end;
|
||||
|
||||
// first line
|
||||
if(bFirstLine)
|
||||
{
|
||||
fSubPixelYStart=y[0]-floorf(y[0]);
|
||||
start=x[0];end=x[0];bFirstLine=false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// top part without middle corner line
|
||||
if(yy<=(int)floorf(y[1]))
|
||||
{
|
||||
start=min(fX1toX2,fX1toX3);end=max(fX1toX2,fX1toX3);
|
||||
}
|
||||
else
|
||||
{
|
||||
start=min(fX2toX3,fX1toX3);end=max(fX2toX3,fX1toX3);
|
||||
}
|
||||
}
|
||||
|
||||
// middle corner line
|
||||
if(yy==(int)floorf(y[1]))
|
||||
{
|
||||
fSubPixelYEnd=y[1]-floorf(y[1]);
|
||||
|
||||
fX1toX3+=fX1toX3step*(fSubPixelYEnd-fSubPixelYStart);
|
||||
|
||||
fSubPixelYStart=fSubPixelYEnd;fSubPixelYEnd=1.0f;
|
||||
}
|
||||
|
||||
// last line
|
||||
if(yy!=(int)floorf(y[2]))
|
||||
{
|
||||
// top part without middle corner line
|
||||
if(yy<(int)floorf(y[1]))
|
||||
fX1toX2+=fX1toX2step*(fSubPixelYEnd-fSubPixelYStart);
|
||||
else
|
||||
fX2toX3+=fX2toX3step*(fSubPixelYEnd-fSubPixelYStart);
|
||||
|
||||
fX1toX3+=fX1toX3step*(fSubPixelYEnd-fSubPixelYStart);
|
||||
}
|
||||
|
||||
if(start!=end)
|
||||
if(yy>=m_iMinY && yy<=m_iMaxY)
|
||||
{
|
||||
if(!bTriangleCallDone){ inpSink->Triangle(yy);bTriangleCallDone=true; }
|
||||
|
||||
lambertHorizlineSubpixelCorrect(start,end,yy,inpSink);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// shrink triangle by n pixel, optimizable
|
||||
void CSimpleTriangleRasterizer::ShrinkTriangle( float inoutfX[3], float inoutfY[3], float infAmount )
|
||||
{
|
||||
float fX[3]={ inoutfX[0], inoutfX[1], inoutfX[2] };
|
||||
float fY[3]={ inoutfY[0], inoutfY[1], inoutfY[2] };
|
||||
|
||||
/*
|
||||
// move edge to opposing vertex
|
||||
float dx,dy,fLength;
|
||||
|
||||
for(int a=0;a<3;a++)
|
||||
{
|
||||
int b=a+1;if(b>=3)b=0;
|
||||
int c=b+1;if(c>=3)c=0;
|
||||
|
||||
dx=fX[a]-(fX[b]+fX[c])*0.5f;
|
||||
dy=fY[a]-(fY[b]+fY[c])*0.5f;
|
||||
fLength=(float)sqrt(dx*dx+dy*dy);
|
||||
if(fLength>1.0f)
|
||||
{
|
||||
dx/=fLength;dy/=fLength;
|
||||
inoutfX[b]+=dx;inoutfY[b]+=dy;
|
||||
inoutfX[c]+=dx;inoutfY[c]+=dy;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
// move vertex to opposing edge
|
||||
float dx,dy,fLength;
|
||||
|
||||
for(int a=0;a<3;a++)
|
||||
{
|
||||
int b=a+1;if(b>=3)b=0;
|
||||
int c=b+1;if(c>=3)c=0;
|
||||
|
||||
dx=fX[a]-(fX[b]+fX[c])*0.5f;
|
||||
dy=fY[a]-(fY[b]+fY[c])*0.5f;
|
||||
fLength=(float)sqrt(dx*dx+dy*dy);
|
||||
if(fLength>1.0f)
|
||||
{
|
||||
dx/=fLength;dy/=fLength;
|
||||
inoutfX[a]-=dx;inoutfY[a]-=dy;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// move vertex to get edges shifted perpendicual for 1 unit
|
||||
for(int a=0;a<3;a++)
|
||||
{
|
||||
float dx1,dy1,dx2,dy2,fLength;
|
||||
|
||||
int b=a+1;if(b>=3)b=0;
|
||||
int c=b+1;if(c>=3)c=0;
|
||||
|
||||
dx1=fX[b]-fX[a];
|
||||
dy1=fY[b]-fY[a];
|
||||
fLength=(float)sqrt(dx1*dx1+dy1*dy1);
|
||||
if(infAmount>0)if(fLength<infAmount)continue;
|
||||
if(fLength==0.0f)continue;
|
||||
dx1/=fLength;dy1/=fLength;
|
||||
|
||||
dx2=fX[c]-fX[a];
|
||||
dy2=fY[c]-fY[a];
|
||||
fLength=(float)sqrt(dx2*dx2+dy2*dy2);
|
||||
if(infAmount>0)if(fLength<infAmount)continue;
|
||||
if(fLength==0.0f)continue;
|
||||
dx2/=fLength;dy2/=fLength;
|
||||
|
||||
inoutfX[a]+=(dx1+dx2)*infAmount;inoutfY[a]+=(dy1+dy2)*infAmount;
|
||||
}
|
||||
}
|
||||
166
Editor/LightmapCompiler/SimpleTriangleRasterizer.h
Normal file
166
Editor/LightmapCompiler/SimpleTriangleRasterizer.h
Normal file
@@ -0,0 +1,166 @@
|
||||
#pragma once
|
||||
|
||||
// Helper class
|
||||
//
|
||||
// clipping is done in integer
|
||||
//
|
||||
|
||||
class CSimpleTriangleRasterizer
|
||||
{
|
||||
public:
|
||||
|
||||
class IRasterizeSink
|
||||
{
|
||||
public:
|
||||
|
||||
//! is called once per triangel for the first possible visible line
|
||||
//! /param iniStartY
|
||||
virtual void Triangle( const int iniStartY )
|
||||
{
|
||||
}
|
||||
|
||||
//! callback function
|
||||
//! /param infXLeft included - not clipped against left and reight border
|
||||
//! /param infXRight excluded - not clipped against left and reight border
|
||||
//! /param iniXLeft included
|
||||
//! /param iniXRight excluded
|
||||
//! /param iniY
|
||||
virtual void Line( const float infXLeft, const float infXRight,
|
||||
const int iniXLeft, const int iniXRight, const int iniY )=0;
|
||||
};
|
||||
|
||||
typedef unsigned long DWORD;
|
||||
|
||||
// -----------------------------------------------------
|
||||
|
||||
//! implementation sink sample
|
||||
class CDWORDFlatFill: public IRasterizeSink
|
||||
{
|
||||
public:
|
||||
|
||||
//! constructor
|
||||
CDWORDFlatFill( DWORD *inpBuffer, const DWORD indwPitchInPixels, DWORD indwValue )
|
||||
{
|
||||
m_dwValue=indwValue;
|
||||
m_pBuffer=inpBuffer;
|
||||
m_dwPitchInPixels=indwPitchInPixels;
|
||||
}
|
||||
|
||||
virtual void Triangle( const int iniY )
|
||||
{
|
||||
m_pBufferLine=&m_pBuffer[iniY*m_dwPitchInPixels];
|
||||
}
|
||||
|
||||
virtual void Line( const float infXLeft, const float infXRight,
|
||||
const int iniLeft, const int iniRight, const int iniY )
|
||||
{
|
||||
DWORD *mem=&m_pBufferLine[iniLeft];
|
||||
|
||||
for(int x=iniLeft;x<iniRight;x++)
|
||||
*mem++=m_dwValue;
|
||||
|
||||
m_pBufferLine+=m_dwPitchInPixels;
|
||||
}
|
||||
|
||||
private:
|
||||
DWORD m_dwValue; //!< fill value
|
||||
DWORD *m_pBufferLine; //!< to get rid of the multiplication per line
|
||||
|
||||
DWORD m_dwPitchInPixels; //!< in DWORDS, not in Bytes
|
||||
DWORD *m_pBuffer; //!< pointer to the buffer
|
||||
};
|
||||
|
||||
// -----------------------------------------------------
|
||||
|
||||
//! constructor
|
||||
//! /param iniWidth excluded
|
||||
//! /param iniHeight excluded
|
||||
CSimpleTriangleRasterizer( const int iniWidth, const int iniHeight )
|
||||
{
|
||||
m_iMinX=0;
|
||||
m_iMinY=0;
|
||||
m_iMaxX=iniWidth-1;
|
||||
m_iMaxY=iniHeight-1;
|
||||
}
|
||||
/*
|
||||
//! constructor
|
||||
//! /param iniMinX included
|
||||
//! /param iniMinY included
|
||||
//! /param iniMaxX included
|
||||
//! /param iniMaxY included
|
||||
CSimpleTriangleRasterizer( const int iniMinX, const int iniMinY, const int iniMaxX, const int iniMaxY )
|
||||
{
|
||||
m_iMinX=iniMinX;
|
||||
m_iMinY=iniMinY;
|
||||
m_iMaxX=iniMaxX;
|
||||
m_iMaxY=iniMaxY;
|
||||
}
|
||||
*/
|
||||
//! simple triangle filler with clipping (optimizable), not subpixel correct
|
||||
//! /param pBuffer pointer o the color buffer
|
||||
//! /param indwWidth width of the color buffer
|
||||
//! /param indwHeight height of the color buffer
|
||||
//! /param x array of the x coordiantes of the three vertices
|
||||
//! /param y array of the x coordiantes of the three vertices
|
||||
//! /param indwValue value of the triangle
|
||||
void DWORDFlatFill( DWORD *inpBuffer, const DWORD indwPitchInPixels, float x[3], float y[3], DWORD indwValue, bool inbConservative )
|
||||
{
|
||||
CDWORDFlatFill pix(inpBuffer,indwPitchInPixels,indwValue);
|
||||
|
||||
if(inbConservative)
|
||||
CallbackFillConservative(x,y,&pix);
|
||||
else
|
||||
CallbackFillSubpixelCorrect(x,y,&pix);
|
||||
}
|
||||
|
||||
// Rectangle around triangle - more stable - use for debugging purpose
|
||||
void CallbackFillRectConservative( float x[3], float y[3], IRasterizeSink *inpSink );
|
||||
|
||||
|
||||
//! subpixel correct triangle filler (conservative or not conservative)
|
||||
//! \param pBuffer pointe to the DWORD
|
||||
//! \param indwWidth width of the buffer pBuffer pointes to
|
||||
//! \param indwHeight height of the buffer pBuffer pointes to
|
||||
//! \param x array of the x coordiantes of the three vertices
|
||||
//! \param y array of the x coordiantes of the three vertices
|
||||
//! \param inpSink pointer to the sink interface (is called per triangle and per triangle line)
|
||||
void CallbackFillConservative( float x[3], float y[3], IRasterizeSink *inpSink );
|
||||
|
||||
//! subpixel correct triangle filler (conservative or not conservative)
|
||||
//! \param pBuffer pointe to the DWORD
|
||||
//! \param indwWidth width of the buffer pBuffer pointes to
|
||||
//! \param indwHeight height of the buffer pBuffer pointes to
|
||||
//! \param x array of the x coordiantes of the three vertices
|
||||
//! \param y array of the x coordiantes of the three vertices
|
||||
//! \param inpSink pointer to the sink interface (is called per triangle and per triangle line)
|
||||
void CallbackFillSubpixelCorrect( float x[3], float y[3], IRasterizeSink *inpSink );
|
||||
|
||||
//!
|
||||
//! /param inoutfX
|
||||
//! /param inoutfY
|
||||
//! /param infAmount could be positive or negative
|
||||
static void ShrinkTriangle( float inoutfX[3], float inoutfY[3], float infAmount );
|
||||
|
||||
private:
|
||||
|
||||
// Clipping Rect;
|
||||
|
||||
int m_iMinX; //!< minimum x value included
|
||||
int m_iMinY; //!< minimum y value included
|
||||
int m_iMaxX; //!< maximum x value included
|
||||
int m_iMaxY; //!< maximum x value included
|
||||
|
||||
void lambertHorizlineConservative( float fx1, float fx2, int y, IRasterizeSink *inpSink );
|
||||
void lambertHorizlineSubpixelCorrect( float fx1, float fx2, int y, IRasterizeSink *inpSink );
|
||||
void CopyAndSortY( const float infX[3], const float infY[3], float outfX[3],float outfY[3] );
|
||||
};
|
||||
|
||||
|
||||
// extension ideas:
|
||||
// * callback with coverage mask (possible non ordered sampling)
|
||||
// * z-buffer behaviour
|
||||
// * gouraud shading
|
||||
// * texture mapping with nearest/bicubic/bilinear filter
|
||||
// * further primitives: thick line, ellipse
|
||||
// * build a template version
|
||||
// *
|
||||
78
Editor/LightmapCompiler/TexelSampler.cpp
Normal file
78
Editor/LightmapCompiler/TexelSampler.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// Crytek CryENGINE source code
|
||||
// History:
|
||||
// - Created by Michael Glueck
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
|
||||
#include "stdafx.h" // precompiled headers
|
||||
#include "TexelSampler.h" // CSimpleTriangleRastizer
|
||||
|
||||
|
||||
void CTexelSampler::Init(const EAATYPE ceAAType)
|
||||
{
|
||||
m_vSamples.clear();
|
||||
//process according to desired processing method
|
||||
//pay attention to add them sorted by u and then v
|
||||
switch(ceAAType)
|
||||
{
|
||||
case NONE:
|
||||
m_vSamples.push_back(SSample()); //default constructor did everything
|
||||
break;
|
||||
case MED:
|
||||
{
|
||||
SSample sample;
|
||||
sample.bTexelCenter = false;
|
||||
sample.fX = 0.f - 0.5f;
|
||||
sample.fY = 0.f - 0.5f;
|
||||
sample.fWeight = 0.125f; //1/8 for corner texels
|
||||
m_vSamples.push_back(sample);
|
||||
sample.fX = 1.f - 0.5f;
|
||||
sample.fY = 0.f - 0.5f;
|
||||
m_vSamples.push_back(sample);
|
||||
sample.fX = 0.5f - 0.5f;
|
||||
sample.fY = 0.5f - 0.5f;
|
||||
sample.fWeight = 0.5f; //1/2 weight for center texel
|
||||
sample.bTexelCenter = true;
|
||||
m_vSamples.push_back(sample);
|
||||
sample.fX = 0.f - 0.5f;
|
||||
sample.fY = 1.f - 0.5f;
|
||||
sample.fWeight = 0.125f;
|
||||
sample.bTexelCenter = false;
|
||||
m_vSamples.push_back(sample);
|
||||
sample.fX = 1.f - 0.5f;
|
||||
sample.fY = 1.f - 0.5f;
|
||||
m_vSamples.push_back(sample);
|
||||
}
|
||||
break;
|
||||
case HIGH:
|
||||
{
|
||||
//it is assumed to be equal to n^2
|
||||
SSample sample;
|
||||
//uniform grid sampling
|
||||
sample.fWeight = 1.f/(2.0f*(float)(HIGH-1));
|
||||
static const float scfGrid = sqrtf((float)HIGH);
|
||||
static const unsigned int scuiCount = (unsigned int)scfGrid;
|
||||
sample.bTexelCenter = false;
|
||||
float y = 1.f/(2.f * scfGrid);
|
||||
for(int v=0;v<scuiCount;v++)
|
||||
{
|
||||
float x = 1.f/(2.f * scfGrid);
|
||||
for(int u=0;u<scuiCount;u++)
|
||||
{
|
||||
x += 2.f/(2.f * scfGrid);
|
||||
sample.fX = x - 0.5f;
|
||||
sample.fY = y - 0.5f;
|
||||
m_vSamples.push_back(sample);
|
||||
}
|
||||
y += 2.f/(2.f * scfGrid);
|
||||
}
|
||||
//alter weight of center sample
|
||||
m_vSamples[(HIGH-1)/2].fWeight = 0.5f;
|
||||
m_vSamples[(HIGH-1)/2].bTexelCenter = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//use no AA in this case (shouldn't happen anyway)
|
||||
m_vSamples.push_back(SSample()); //default constructor did everything
|
||||
}
|
||||
}
|
||||
83
Editor/LightmapCompiler/TexelSampler.h
Normal file
83
Editor/LightmapCompiler/TexelSampler.h
Normal file
@@ -0,0 +1,83 @@
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* class contains the functionality for retrieving samples relative to a texel center
|
||||
* uses prepared raster table
|
||||
* texel ranges from -0.5,-0.5 to 0.5,0.5, therefore texel center located at 0.0,0.0
|
||||
* one is guaranteed to be set as texel center
|
||||
*/
|
||||
class CTexelSampler
|
||||
{
|
||||
public:
|
||||
//!< describes one sample
|
||||
typedef struct SSample
|
||||
{
|
||||
float fX; //!< u-position relative to texel center
|
||||
float fY; //!< v-position relative to texel center
|
||||
float fWeight; //!< weight for this sample
|
||||
bool bTexelCenter; //!< true if to use as texel center, default true to guarantee at least one valid sample
|
||||
SSample():fX(0.f),fY(0.f),fWeight(1.0f),bTexelCenter(true){}
|
||||
}SSample;
|
||||
|
||||
//!< enumerates the available antialiasing approaches
|
||||
typedef enum EAATYPE
|
||||
{
|
||||
NONE = 1, //!< only texel center gets processed
|
||||
MED = 5, //!< texel center and all corners gets sampled
|
||||
HIGH = 9 //!< texel center and 8 additional samples get used
|
||||
}EAATYPE;
|
||||
/**
|
||||
* constructor which initializes the sample table
|
||||
* @param ceAAType desired accuracy for antialiasing (determines number of samples to take)
|
||||
*/
|
||||
CTexelSampler(const EAATYPE ceAAType = MED)
|
||||
{
|
||||
Init(ceAAType);
|
||||
}
|
||||
/**
|
||||
* reinitializes the sample table
|
||||
* @param ceAAType desired accuracy for antialiasing (determines number of samples to take)
|
||||
*/
|
||||
void Reinitialize(const EAATYPE ceAAType = MED)
|
||||
{
|
||||
Init(ceAAType);
|
||||
}
|
||||
/**
|
||||
* returns number of sampels per texel, sorted to make reuse possible
|
||||
* @return number of samples
|
||||
*/
|
||||
const unsigned int NumberOfSamples() const
|
||||
{
|
||||
return m_vSamples.size();
|
||||
}
|
||||
/**
|
||||
* retrieves an const iterator to the samples
|
||||
* @param const iterator to the sample vector
|
||||
*/
|
||||
std::vector<SSample>::const_iterator BeginIterator() const
|
||||
{
|
||||
return m_vSamples.begin();
|
||||
}
|
||||
/**
|
||||
* retrieves an const iterator to the samples
|
||||
* @param const iterator to the sample vector
|
||||
*/
|
||||
std::vector<SSample>::const_iterator EndIterator() const
|
||||
{
|
||||
return m_vSamples.end();
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* initializes sampler, called from Reinitialize and contructor
|
||||
* @param ceAAType desired accuracy for antialiasing (determines number of samples to take)
|
||||
*/
|
||||
void Init(const EAATYPE ceAAType);
|
||||
|
||||
std::vector<SSample> m_vSamples; //!< sample offset related to respective texel center, sorted by u and then v
|
||||
};
|
||||
|
||||
typedef std::vector<CTexelSampler::SSample>::const_iterator SampleIter;
|
||||
Reference in New Issue
Block a user