/*==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