You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
405 lines
16 KiB
405 lines
16 KiB
/*==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 <http://www.gnu.org/licenses/>. |
|
|
|
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<plDistribInstance> |
|
{ |
|
}; |
|
|
|
class plMeshCache |
|
{ |
|
public: |
|
Mesh* fMesh; |
|
Point3 fFlex; |
|
|
|
plMeshCache() {} |
|
}; |
|
|
|
class plMeshCacheTab : public Tab<plMeshCache> |
|
{ |
|
}; |
|
|
|
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<Int32>& faces) const; |
|
BOOL IProjectVertex(const Point3& pt, const Point3& dir, float maxDist, Tab<Int32>&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
|
|
|