/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plDistributor_inc
#define plDistributor_inc
#include "plMath/plRandom.h"
#include "plDistTree.h"
class INode;
class Mesh;
class TriObject;
class BitmapTex;
class plLayerTex;
class plExportProgressBar;
class plMaxNode;
class plDistTree;
// To Use:
//
// First you must set the interface
// Second, you must set the node(s) to be replicated.
// If multiple replicants, they will be randomly selected at each plant site.
// Set the spacing. Default is 10 or so, but shouldn't be counted on.
// Set the spacing range. Set it to less than half the spacing to prevent
// replicants piling up on each other.
// Rather than increasing the spacing range (which causes pileup), you can increase
// the randomness of placement with the overall probability factor. Reducing it
// means fewer grid points will be used, so placement seems more random
//
// Options:
// PolarRange - defines the cone about the surface normal to randomly fill for up direction
// PolarBunch - defines tendency to bunch around the center of PolarRange cone,
// with zero being uniform distribution, and one being all on cone axis.
// AlignmentVector - defines a world space preferred up orientation.
// AlignmentWeight - blend factor between random normal (from polar stuff) and
// above AlignmentVector.
// ScaleRange - defines range of non-uniform scale to apply to each replicant.
// ProbabilityTexmap - A BitmapTex which maps the probability of an instance
// taking root at any point on the surface. Various interpretations of the
// map available (see ProbabilityChan). If the surface mesh doesn't have
// the appropriate uvw mapping for the map, the map will be ignored.
// ProbabilityChan - defines interpretation of texel value from ProbTexmap
// into a probability. ColorChan enum types are pretty self-explanatory.
// In all cases, a higher texel channel value means more likely of a
// replicant taking root there.
//
// Finally, call Distrubute() with a node containing a surface to be populated.
//
// Modifying. Were actually creating the new node instances, but then we just
// want to re-pack them into clusters anyway. So all we really need is to
// know which template (fRepNodes) and what transform to use for it. We can
// use that to make our clusters, without bogging Max down with adding and
// deleting a gazillion INodes.
class plDistribInstance
{
public:
INode* fNode;
Matrix3 fNodeTM;
Matrix3 fObjectTM;
INode* fBone;
BOOL fRigid;
Box3 fFade;
Point3 fFlex;
Mesh* fMesh;
};
class plDistribInstTab : public Tab
{
};
class plMeshCache
{
public:
Mesh* fMesh;
Point3 fFlex;
plMeshCache() {}
};
class plMeshCacheTab : public Tab
{
};
class plDistributor
{
public:
enum ColorChan
{
kRed = 0x1,
kGreen = 0x2,
kBlue = 0x4,
kAlpha = 0x8,
kAverageRedGreen = kRed | kGreen,
kAverageRedGreenTimesAlpha = kRed | kGreen | kAlpha,
kAverage = kRed | kGreen | kBlue,
kAverageTimesAlpha = kAverage | kAlpha,
kMax = 0x100,
kMaxColor = kMax | kRed | kGreen | kBlue,
kMaxColorTimesAlpha = kMaxColor | kAlpha,
kMaxRedGreen = kMax | kRed | kGreen,
kMaxRedGreenTimesAlpha = kMaxRedGreen | kAlpha
};
enum
{
kLockNone = 0x0,
kLockX = 0x1,
kLockY = 0x2,
kLockZ = 0x4
};
enum
{
kWgtMapChan = 66,
kNormMapChan = 67
};
enum IsoType
{
kIsoNone,
kIsoLow,
kIsoMedium,
kIsoHigh,
kIsoMax = kIsoHigh
};
enum ConformType
{
kConformNone,
kConformAll,
kConformHeight,
kConformCheck,
kConformBase
};
protected:
mutable INode* fSurfNode;
mutable Mesh* fSurfMesh;
mutable TriObject* fSurfObjToDelete;
mutable INodeTab fRepNodes;
mutable plDistTree* fDistTree;
mutable plDistTree fMeshTree;
Interface* fInterface;
IsoType fIsolation;
ConformType fConformity;
BOOL fFaceNormals;
float fSpacing;
float fRndPosRadius;
Point3 fAlignVec;
float fAlignWgt;
float fOffsetMin;
float fOffsetMax;
Point3 fAngProbVec;
float fAngProbLo;
float fAngProbHi;
float fAngProbTrans;
float fAltProbLo;
float fAltProbHi;
float fAltProbTrans;
float fPolarRange;
float fTanPolarRange;
float fAzimuthRange;
float fOverallProb;
float fPolarBunch;
ULONG fScaleLock;
Point3 fScaleLo;
Point3 fScaleHi;
BitmapTex* fProbBitmapTex;
plLayerTex* fProbLayerTex;
ColorChan fProbColorChan;
float fProbRemapFromLo;
float fProbRemapFromHi;
float fProbRemapToLo;
float fProbRemapToHi;
float fMaxConform; // in feet
Box3 fFade;
INode* fBone;
BOOL fRigid;
// Temps used during processing.
mutable Matrix3 fSurfToWorld;
mutable Matrix3 fWorldToSurf;
mutable Matrix3 fSurfToWorldVec;
mutable Matrix3 fWorldToSurfVec;
mutable Point3 fSurfAlignVec;
mutable Point3 fSurfAngProbVec;
mutable plRandom fRand;
mutable float fCosAngProbHi;
mutable float fCosAngProbHiTrans;
mutable float fCosAngProbLo;
mutable float fCosAngProbLoTrans;
void ISetAngProbCosines() const;
BOOL ISetSurfaceNode(INode* node) const;
BOOL IGetMesh(INode* node, TriObject*& objToDelete, Mesh*& retMesh) const;
BOOL INeedMeshTree() const;
void IMakeMeshTree() const;
void IFindFaceSet(const Box3& box, Tab& faces) const;
BOOL IProjectVertex(const Point3& pt, const Point3& dir, float maxDist, Tab&faces, Point3& projPt) const;
BOOL IConform(Matrix3& l2w, int iRepNode, plMeshCacheTab& cache, int& iCache) const;
BOOL IConformHeight(Matrix3& l2w, int iRepNode, plMeshCacheTab& cache, int& iCache) const;
BOOL IConformAll(Matrix3& l2w, int iRepNode, plMeshCacheTab& cache, int& iCache) const;
BOOL IConformCheck(Matrix3& l2w, int iRepNode, plMeshCacheTab& cache, int& iCache) const;
BOOL IConformBase(Matrix3& l2w, int iRepNode, plMeshCacheTab& cache, int& iCache) const;
Matrix3 IOTM(int iRepNode) const;
Matrix3 IInvOTM(int iRepNode) const;
Matrix3 IGenerateTransform(int iRepNode, int iFace, const Point3& pt, const Point3& bary) const;
hsBool IProbablyDoIt(int iFace, Point3& del, const Point3& bary) const;
hsBool IFailsAltProb(int iFace, const Point3& bary) const;
hsBool IFailsAngProb(int iFace, const Point3& bary) const;
hsBool IFailsProbBitmap(int iFace, const Point3& bary) const;
Box3 ISetupGrid(const Point3& p0, const Point3& p1, const Point3& p2) const;
Point3& IPerturbPoint(Point3& pt) const;
int ISelectRepNode() const;
Point3 IPerpAxis(const Point3& p) const;
Point3 IGetSurfaceNormal(int iFace, const Point3& bary) const;
BOOL ISpaceClear(int iRepNode, const Matrix3& l2w, Box3& clearBox, plMeshCacheTab& cache) const;
void IReserveSpace(const Box3& clearBox) const;
void IReplicate(Matrix3& l2w, int iRep, plDistribInstTab& reps, plMeshCache& mCache) const;
void IDistributeOverFace(int iFace, plDistribInstTab& reps, plMeshCacheTab& cache) const;
BOOL IDistributeOverMesh(plDistribInstTab& reps, plMeshCacheTab& cache, plExportProgressBar& bar) const;
void IClear();
BOOL IValidateSettings(INode* surfNode, plMeshCacheTab& cache) const;
BOOL ISetupNormals(plMaxNode* node, Mesh* mesh, BOOL radiateNorm) const;
BOOL IDuplicate2Sided(plMaxNode* node, Mesh* mesh) const;
BOOL ISetupSkinWeights(plMaxNode* node, Mesh* mesh, const Point3& flex) const;
BOOL IReadyRepNodes(plMeshCacheTab& cache) const;
public:
plDistributor();
virtual ~plDistributor();
void SetTheInterface(Interface* i) { fInterface = i; }
Interface* GetTheInterface() const { return fInterface; }
BOOL Distribute(INode* surfNode, plDistribInstTab& replicants, plMeshCacheTab& cache, plExportProgressBar& bar) const;
void Reset();
UInt32 GetRandSeed() const;
void SetRandSeed(int seed);
void ClearReplicateNodes();
void AddReplicateNode(INode* node);
int GetNumReplicateNodes() const { return fRepNodes.Count(); }
INode* GetReplicateNode(int i) const { return fRepNodes[i]; }
INode* GetSurfaceNode() const { return fSurfNode; }
void SetSpacing(float f) { fSpacing = f; }
float GetSpacing() const { return fSpacing; }
void SetSpacingRange(float f) { fRndPosRadius = f; }
float GetSpacingRange() const { return fRndPosRadius; }
void SetAlignmentVec(const Point3& v) { fAlignVec = v; }
Point3 GetAlignmentVec() const { return fAlignVec; }
void SetAlignmentWeight(float w) { fAlignWgt = w / 100.f; }
float GetAlignmentWeight() const { return fAlignWgt * 100.f; }
void SetPolarRange(float deg);
float GetPolarRange() const { return hsScalarRadToDeg(fPolarRange); }
void SetAzimuthRange(float deg) { fAzimuthRange = hsScalarDegToRad(deg); }
float GetAzimuthRange() const { return hsScalarRadToDeg(fAzimuthRange); }
void SetOverallProb(float percent) { fOverallProb = percent/100.f; }
float GetOverallProb() const { return fOverallProb * 100.f; }
void SetAngleProbVec(const Point3& v) { fAngProbVec = v; }
Point3 GetAngleProbVec() const { return fAngProbVec; }
void SetAngleProbHi(float deg) { fAngProbHi = deg; }
float GetAngleProbHi() const { return fAngProbHi; }
void SetAngleProbLo(float deg) { fAngProbLo = deg; }
float GetAngleProbLo() const { return fAngProbLo; }
void SetAngleProbTransition(float deg) { fAngProbTrans = deg; }
float GetAngleProbTransition() const { return fAngProbTrans; }
void SetMinAltitude(float feet) { fAltProbLo = feet; }
float GetMinAltitude() const { return fAltProbLo; }
void SetMaxAltitude(float feet) { fAltProbHi = feet; }
float GetMaxAltitude() const { return fAltProbHi; }
void SetAltitudeTransition(float feet) { fAltProbTrans = feet; }
float GetAltitudeTransition() const { return fAltProbTrans; }
void SetPolarBunch(float b) { fPolarBunch = b/100.f; }
float GetPolarBunch() const { return fPolarBunch * 100.f; }
void SetScaleRange(const Point3& lo, const Point3& hi) { fScaleLo = lo; fScaleHi = hi; }
Point3 GetScaleRangeMin() const { return fScaleLo; }
Point3 GetScaleRangeMax() const { return fScaleHi; }
void SetProbabilityBitmapTex(BitmapTex* t);
BitmapTex* GetProbabilityBitmapTex() const { return fProbBitmapTex; }
void SetProbabilityLayerTex(plLayerTex* t);
plLayerTex* GetProbabilityLayerTex() const { return fProbLayerTex; }
void SetProbabilityChan(ColorChan c) { fProbColorChan = c; }
ColorChan GetProbabilityChan() const { return fProbColorChan; }
void SetProbabilityRemapFromLo(float f) { fProbRemapFromLo = f / 255.f; }
float GetProbabilityRemapFromLo() const { return fProbRemapFromLo * 255.f; }
void SetProbabilityRemapFromHi(float f) { fProbRemapFromHi = f / 255.f; }
float GetProbabilityRemapFromHi() const { return fProbRemapFromHi * 255.f; }
void SetProbabilityRemapToLo(float f) { fProbRemapToLo = f / 255.f; }
float GetProbabilityRemapToLo() const { return fProbRemapToLo * 255.f; }
void SetProbabilityRemapToHi(float f) { fProbRemapToHi = f / 255.f; }
float GetProbabilityRemapToHi() const { return fProbRemapToHi * 255.f; }
// We don't really know what fades are, they're just something we're handed that
// we stamp on every distribInstance we generate. See plDistribComponent.h.
void SetFade(const Box3& fade) { fFade = fade; }
Box3 GetFade() const { return fFade; }
void SetBone(INode* b) { fBone = b; }
INode* GetBone() const { return fBone; }
void SetRigid(BOOL b) { fRigid = b; }
BOOL GetRigid() const { return fRigid; }
void SetScaleLock(ULONG f) { fScaleLock = f; }
ULONG GetScaleLock() const { return fScaleLock; }
void SetDistTree(plDistTree* dt) { fDistTree = dt; }
plDistTree* GetDistTree() const { return fDistTree; }
void SetIsolation(IsoType t) { fIsolation = t; }
IsoType GetIsolation() const { return fIsolation; }
void SetConformity(ConformType t) { fConformity = t; }
ConformType GetConformity() const { return fConformity; }
void SetMaxConform(float feet) { fMaxConform = feet; }
float GetMaxConform() const { return fMaxConform; }
void SetMinOffset(float feet) { fOffsetMin = feet; }
float GetMinOffset() const { return fOffsetMin; }
void SetMaxOffset(float feet) { fOffsetMax = feet; }
float GetMaxOffset() const { return fOffsetMax; }
void SetFaceNormals(BOOL on=true) { fFaceNormals = on; }
BOOL GetFaceNormals() const { return fFaceNormals; }
};
#endif // plDistributor_inc