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.
 
 
 
 
 

421 lines
14 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/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
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