// NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero 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 Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_EXPORT_NEL_H #define NL_EXPORT_NEL_H #include "nel/misc/types_nl.h" #include "nel/3d/mesh.h" #include "nel/3d/material.h" #include "nel/3d/mesh_vertex_program.h" #include "nel/3d/camera.h" #include "nel/3d/key.h" #include "nel/3d/track_keyframer.h" #include "nel/3d/bone.h" #include "nel/3d/animation_time.h" #include "nel/3d/animation_time.h" #include "nel/../../src/pacs/collision_mesh_build.h" #define UVGEN_MISSING (-1) #define UVGEN_REFLEXION (-2) #define FLOAT_EPSILON 0.001 #define NEL_MTL_A 0x64c75fec #define NEL_MTL_B 0x222b9eb9 #define NEL_LIGHT_CLASS_ID_A 0x36e3181f #define NEL_LIGHT_CLASS_ID_B 0x3ac24049 #define NEL_PACS_BOX_CLASS_ID_A 0x7f374277 #define NEL_PACS_BOX_CLASS_ID_B 0x5d3971df #define NEL_PACS_CYL_CLASS_ID_A 0x62a56810 #define NEL_PACS_CYL_CLASS_ID_B 0x4b3d601c #define NEL_PARTICLE_SYSTEM_CLASS_ID 0x58ce2893 #define NEL_FLARE_CLASS_ID_A 0x4e913532 #define NEL_FLARE_CLASS_ID_B 0x3c2f2307 #define NEL_WAVE_MAKER_CLASS_ID_A 0x77e24828 #define NEL_WAVE_MAKER_CLASS_ID_B 0x329a1de5 #define NEL_REMANENT_SEGMENT_CLASS_ID_A 0x72f3588b #define NEL_REMANENT_SEGMENT_CLASS_ID_B 0x6eda0a52 #define MAX_MAX_TEXTURE 8 #define MAX_MORPHER_CLASS_ID Class_ID(0x17bb6854, 0xa5cba2a3) // *************************************************************************** enum TNelValueType { typeFloat, typePos, typeScale, typeRotation, typeColor, typeInt, typeBoolean, typeString, typeMatrix, }; // *************************************************************************** enum TNelScriptValueType { scriptNothing, scriptFloat, scriptBool, scriptNode, }; // *************************************************************************** namespace NL3D { class CAnimation; class ITrack; class CTrackKeyFramerConstBool; class CSkeletonShape; class CMRMParameters; class IMeshGeom; class CInstanceGroup; class CVegetableShape; class CLodCharacterShapeBuild; class CShapeBank; class IDriver; class CLandscape; class CTextureCube; }; namespace NLPACS { class CRetrieverBank; class CGlobalRetriever; class CPrimitiveBlock; }; namespace NLMISC { class CAABBox; } // *************************************************************************** // Interface for feed back during calculation class IProgress { public: virtual void setLine (uint32 LineNumber, std::string &LineText)=0; virtual void update()=0; }; // *************************************************************************** struct CExportNelOptions { bool bShadow; bool bExportLighting; bool bExportBgColor; bool OutputLightmapLog; std::string sExportLighting; sint32 nExportLighting; float rLumelSize; sint32 nOverSampling; bool bExcludeNonSelected; IProgress *FeedBack; bool bShowLumel; bool bTestSurfaceLighting; float SurfaceLightingCellSize; float SurfaceLightingDeltaZ; CExportNelOptions::CExportNelOptions() { // If no configuration file bShadow = false; bExportLighting = false; bExportBgColor = true; OutputLightmapLog = false; sExportLighting = "c:\\temp"; nExportLighting = 0; // Normal lighting rLumelSize = 0.25f; nOverSampling = 1; bExcludeNonSelected = false; FeedBack = NULL; bShowLumel = false; bTestSurfaceLighting= true; SurfaceLightingCellSize= 1.5f; SurfaceLightingDeltaZ= 0.8f; } void serial(NLMISC::IStream& stream) { sint version = stream.serialVersion (6); // Check version switch (version) { case 6: stream.serial (OutputLightmapLog); case 5: { bool fake= false; stream.serial (fake); } case 4: stream.serial (SurfaceLightingDeltaZ); case 3: stream.serial (bTestSurfaceLighting); stream.serial (SurfaceLightingCellSize); case 2: stream.serial (bExportBgColor); case 1: stream.serial (bShowLumel); stream.serial (bShadow); stream.serial (bExportLighting); stream.serial (sExportLighting); stream.serial (nExportLighting); stream.serial (rLumelSize); stream.serial (nOverSampling); stream.serial (bExcludeNonSelected); } } }; // *************************************************************************** class CExportDesc; // *************************************************************************** typedef std::map TInodePtrInt; // *************************************************************************** /** Descriptor of a WindTree VertexProgram AppData */ class CVPWindTreeAppData { public: enum {HrcDepth= 3, NumTicks=100}; /// Scale value for sliders float FreqScale; float DistScale; /// Frequency of the wind for 3 Hierachy levels. Slider Value int Frequency[HrcDepth]; /// Additional frequency, multiplied by the globalWindPower. Slider Value int FrequencyWindFactor[HrcDepth]; /// Power of the wind on XY. Mul by globalWindPower. Slider Value int DistXY[HrcDepth]; /// Power of the wind on Z. Mul by globalWindPower. Slider Value int DistZ[HrcDepth]; /// Bias result of the cosinus: f= cos(time)+bias. Slider Value int Bias[HrcDepth]; /// BST_CHECKED if want Specular Lighting. int SpecularLighting; }; // *************************************************************************** /// Skeleton Spawn Script build, used at addAnimation() class CSSSBuild { public: struct CKey { std::string Value; NL3D::TAnimationTime Time; }; struct CBoneScript { // The name of the bone on which the track is bound std::string BoneName; // The Temp Track definition std::vector Track; }; std::vector Bones; // if not empty, compile all bone scripts, and add to the animation of the skeleton void compile(NL3D::CAnimation &dest, const char* sBaseName); }; // *************************************************************************** /** * 3dsmax to NeL export interface for other things that landscape. * \author Cyril Corvazier * \author Nevrax France * \date 2000 */ class CExportNel { private: class CAnimationBuildCtx; public: enum { NoError=0, VertexWithoutWeight, InvalidSkeleton, CodeCount }; static const char* ErrorMessage[CodeCount]; typedef std::map mapBoneBindPos; /// Constructor CExportNel (bool errorInDialog, bool view, bool absolutePath, Interface *ip, std::string errorTitle, CExportNelOptions *opt); // ********************* // *** Export mesh // ********************* /** * Build a NeL mesh * * skeletonShape must be NULL if no bones. */ NL3D::IShape* buildShape (INode& node, TimeValue time, const TInodePtrInt *nodeMap, bool buildLods); /** * Build a NeL meshBuild * * This method does not care of the skeletonShape * if isMorphTarget is true, no "mrm/normal mesh interface" is built */ NL3D::CMesh::CMeshBuild* createMeshBuild(INode& node, TimeValue tvTime, NL3D::CMesh::CMeshBaseBuild*& baseBuild, const NLMISC::CMatrix &finalSpace = NLMISC::CMatrix::Identity, bool isMorphTarget= false); /** Test wether the node has app datas specifying interface meshs. * \see applyInterfaceToMeshBuild */ static bool useInterfaceMesh(INode &node); /** Use interface mesh from a max file to unify normal at extremities of a mesh * Example : a character is sliced in slots, each parts being stored in a file. * The normals at the junction part are incorrect. * An "interface" is a polygon that is used to unify normal between various meshs * IMPORTANT : the meshbuild should have been exported in WORLD SPACE * Note : the name of the max file that contains the name of the interface is stored in an app data attached to this node * \param node the node from which datas must be retrieved (name of the .max file containing the interfaces) * \param meshBuildToModify The mesh build whose normal will be modified * \param toWorldMat a matrix to put the meshbuild vertices into worldspace * \param tvTime time aty which evaluate the mesh */ void applyInterfaceToMeshBuild(INode &node, NL3D::CMesh::CMeshBuild &meshBuildToModify, const NLMISC::CMatrix &toWorldMat, TimeValue tvTime); /** This takes a max mesh, and select the vertices that match vertices of a mesh interface * This has no effect if the mesh has no app datas specifying a mesh interface * \see applyInterfaceToMeshBuild * \return true if the operation succeed */ bool selectInterfaceVertices(INode &node, TimeValue time); /** * Build a NeL instance group */ NL3D::CInstanceGroup* buildInstanceGroup(const std::vector& vectNode, std::vector& resultInstanceNode, TimeValue tvTime); /** * Build a complete NeL scene with objects attached to the scene root node * * \param scene is the scene to build * \param shapeBank is the shape bank to use with the scene * \param tvTime if the time to use to build the scene * \param options is the options structure to use to build the scene * \param landscape is a pointer ona landscape created with the scene. Can be NULL if you dan't want to build landscape zones. * \param progress is the progress bar to use to display build progression. Can be NULL if no prgoress bar is needed * \param buildHidden If it is true, build hidden nodes * \param onlySelected If it is true, build only selected nodes * \param buildLods If it is true, build lod of objects */ void buildScene (NL3D::CScene &scene, NL3D::CShapeBank &shapeBank, NL3D::IDriver &driver, TimeValue tvTime, NL3D::CLandscape *landscape, IProgress *progress, bool buildHidden, bool onlySelected, bool buildLods); /** * Build a NeL camera */ void buildCamera(NL3D::CCameraInfo &cameraInfo, INode& node, TimeValue time); /** * Return true if it is a mesh. * * skeletonShape must be NULL if no bones. * * if excludeCollision then return false if the mesh is a collision (NL3D_APPDATA_COLLISION) * else don't test NL3D_APPDATA_COLLISION. */ static bool isMesh (INode& node, TimeValue time, bool excludeCollision= true); static bool isCamera (INode& node, TimeValue time); static bool isDummy (INode& node, TimeValue time); static bool isVegetable (INode& node, TimeValue time); /** Compute an aabbox of a mesh, in world. * \return true if the conversion succeed. */ static bool buildMeshAABBox(INode &node, NLMISC::CAABBox &dest, TimeValue time); /** * Return true if the node is a mesh and has a Nel_Material attached to it */ static bool hasLightMap (INode& node, TimeValue time); void deleteLM (INode& node); bool calculateLM (NL3D::CMesh::CMeshBuild *pZeMeshBuild, NL3D::CMeshBase::CMeshBaseBuild *pZeMeshBaseBuild, INode& ZeNode, TimeValue tvTime, uint firstMaterial, bool outputLightmapLog); bool calculateLMRad(NL3D::CMesh::CMeshBuild *pZeMeshBuild, NL3D::CMeshBase::CMeshBaseBuild *pZeMeshBaseBuild, INode& ZeNode, TimeValue tvTime); // ********************* // *** Export animation // ********************* // Add animation track of this node into the animation object pass in parameter. void addAnimation (NL3D::CAnimation& animation, INode& node, const char* sBaseName, bool root); // Build a NeL track with a 3dsmax node and a controller. NL3D::ITrack* buildATrack (NL3D::CAnimation& animation, Control& c, TNelValueType type, Animatable& node, const CExportDesc& desc, CAnimationBuildCtx *animBuildCtx, bool bodyBiped=false); // Build a Nel bool track from a On/Off max Controller (doesn't work with buildATRack, which require a keyframer interface // , which isn't provided by an on / off controller) static NL3D::CTrackKeyFramerConstBool* buildOnOffTrack(Control& c); // Add tracks for particle systems void addParticleSystemTracks(NL3D::CAnimation& animation, INode& node, const char* parentName) ; // Add tracks for the bone and its children (recursive) void addBoneTracks (NL3D::CAnimation& animation, INode& node, const char* parentName, CAnimationBuildCtx *animBuildCtx, bool root, CSSSBuild &ssBuilder); // Add biped tracks void addBipedNodeTracks (NL3D::CAnimation& animation, INode& node, const char* parentName, CAnimationBuildCtx *animBuildCtx, bool root, CSSSBuild &ssBuilder); // Add a note track. It tackes the first note track of the object static void addNoteTrack(NL3D::CAnimation& animation, INode& node); // Add a SkeletonSpawnScript track. It takes the first note track of the object static void addSSSTrack(CSSSBuild &ssBuilder, INode& node); // Build a Nel String track from the first NoteTrack static NL3D::CTrackKeyFramerConstString* buildFromNoteTrack(INode& node); // Convert keyframe methods static void buildNelKey (NL3D::CKeyFloat& nelKey, ILinFloatKey& maxKey, float ticksPerSecond, const CExportDesc& desc, Control& c); static void buildNelKey (NL3D::CKeyInt& nelKey, ILinFloatKey& maxKey, float ticksPerSecond, const CExportDesc& desc, Control& c); static void buildNelKey (NL3D::CKeyBool& nelKey, ILinFloatKey& maxKey, float ticksPerSecond, const CExportDesc& desc, Control& c); static void buildNelKey (NL3D::CKeyVector& nelKey, ILinPoint3Key& maxKey, float ticksPerSecond, const CExportDesc& desc, Control& c); static void buildNelKey (NL3D::CKeyRGBA& nelKey, ILinPoint3Key& maxKey, float ticksPerSecond, const CExportDesc& desc, Control& c); static void buildNelKey (NL3D::CKeyQuat& nelKey, ILinRotKey& maxKey, float ticksPerSecond, const CExportDesc& desc, Control& c); static void buildNelKey (NL3D::CKeyVector& nelKey, ILinScaleKey& maxKey, float ticksPerSecond, const CExportDesc& desc, Control& c); static void buildNelKey (NL3D::CKeyBezierFloat& nelKey, IBezFloatKey& maxKey, float ticksPerSecond, const CExportDesc& desc, Control& c); static void buildNelKey (NL3D::CKeyBool& nelKey, IBezFloatKey& maxKey, float ticksPerSecond, const CExportDesc& desc, Control& c); static void buildNelKey (NL3D::CKeyBezierVector& nelKey, IBezPoint3Key& maxKey, float ticksPerSecond, const CExportDesc& desc, Control& c); static void buildNelKey (NL3D::CKeyBezierQuat& nelKey, IBezQuatKey& maxKey, float ticksPerSecond, const CExportDesc& desc, Control& c); static void buildNelKey (NL3D::CKeyBezierVector& nelKey, IBezScaleKey& maxKey, float ticksPerSecond, const CExportDesc& desc, Control& c); static void buildNelKey (NL3D::CKeyTCBFloat& nelKey, ITCBFloatKey& maxKey, float ticksPerSecond, const CExportDesc& desc, Control& c); static void buildNelKey (NL3D::CKeyBool& nelKey, ITCBFloatKey& maxKey, float ticksPerSecond, const CExportDesc& desc, Control& c); static void buildNelKey (NL3D::CKeyTCBVector& nelKey, ITCBPoint3Key& maxKey, float ticksPerSecond, const CExportDesc& desc, Control& c); static void buildNelKey (NL3D::CKeyTCBQuat& nelKey, ITCBRotKey& maxKey, float ticksPerSecond, const CExportDesc& desc, Control& c); static void buildNelKey (NL3D::CKeyTCBVector& nelKey, ITCBScaleKey& maxKey, float ticksPerSecond, const CExportDesc& desc, Control& c); // Create the transform matrix tracks void createBipedKeyFramer (NL3D::ITrack *&nelRot, NL3D::ITrack *&nelPos, bool isRot, bool isPos, float ticksPerSecond, const Interval& range, int oRT, const CExportDesc& desc, INode& node, CAnimationBuildCtx *animBuildCtx); // convert to nel time value static NL3D::TAnimationTime convertTime (TimeValue time); // ************************************ // *** Export skeleton and skinning // ************************************ /* * Build a skeleton shape * * mapBindPos is the pointer of the map of bind pos by bone. Can be NULL if the skeleton is already in the bind pos. */ void buildSkeletonShape (NL3D::CSkeletonShape& skeletonShape, INode& node, mapBoneBindPos* mapBindPos, TInodePtrInt& mapId, TimeValue time); // Build an array of CBoneBase void buildSkeleton (std::vector& bonesArray, INode& node, mapBoneBindPos* mapBindPos, TInodePtrInt& mapId, std::set &nameSet, TimeValue time, sint32& idCount, sint32 father=-1); /* * Add Skinning data into the build structure. * You must call first isSkin. If isSkin return true, then you can call this method. * Can return the following errors: * * skeletonShape must be NULL if no bones. * * NoError * VertexWithoutWeight * InvalidSkeleton */ static uint buildSkinning (NL3D::CMesh::CMeshBuild& buildMesh, const TInodePtrInt& skeletonShape, INode& node); // Return true if the mesh is a skin, else return false. static bool isSkin (INode& node); // Return the root node of the skeleton attached to the node. Return NULL if no skeleton. static INode* getSkeletonRootBone (INode& node); // Add bind pose matrix of the bone used by the model in the map. static void addSkeletonBindPos (INode& node, mapBoneBindPos& boneBindPos); // Enable / disable the skin modifier static void enableSkinModifier (INode& node, bool enable); /// return true if the bone must unherit his father scale. Special cases for biped, biped father etc... bool getNELUnHeritFatherScale(INode &node); /** This method do the same thing as getLocalMatrix() mut manages complexs cases of Scale unheritance, strange Biped node Scale stuff, etc.... */ void getNELBoneLocalTM(INode &node, TimeValue time, NLMISC::CVector &nelScale, NLMISC::CQuat &nelQuat, NLMISC::CVector &nelPos); /// Physique Mirroring bool mirrorPhysiqueSelection(INode &node, TimeValue time, const std::vector &vertIn, float threshold); // ************** // *** Export Lod // ************** void addChildLodNode (std::set &lodListToExclude, INode *current = NULL); void addParentLodNode (INode &node, std::set &lodListToExclude, INode *current = NULL); // ********************* // *** Export collision // ********************* /** Export a CCollisionMeshBuild from a list of node. * NB: do not check NEL3D_APPDATA_COLLISION. */ NLPACS::CCollisionMeshBuild* createCollisionMeshBuild(std::vector &nodes, TimeValue tvTime); /** Export a list of CCollisionMeshBuild from a list of node, grouped by igName. User must delete the meshBuilds. * meshBuildList is a vector of tuple igName-Cmb * NB: check NEL3D_APPDATA_COLLISION. if not set, the node is not exported */ bool createCollisionMeshBuildList(std::vector &nodes, TimeValue time, std::vector > &meshBuildList); /** * Parse all the scene and build retrieverBank and globalRetriever. NULL if no collisions mesh found. * \param retIgName eg: if IgName of a collisionMesh "col_pipo_1" is found in the scene, and if * igNamePrefix=="col_" and igNameSuffix=="_", then retIgName returned is "pipo". * If different igName may match, result is undefined (random). */ void computeCollisionRetrieverFromScene(TimeValue time, NLPACS::CRetrieverBank *&retrieverBank, NLPACS::CGlobalRetriever *&globalRetriever, const char *igNamePrefix, const char *igNameSuffix, std::string &retIgName); /** * Retrieve the Z rotation in radian of an object with its I matrix vector, assuming that the K matrix vector is near CVector::K */ static float getZRot (const NLMISC::CVector &i); /** * Build a primtive block with an array of inode. Return false if one of the object is not a PACS primitive object. */ bool buildPrimitiveBlock (TimeValue time, std::vector objects, NLPACS::CPrimitiveBlock &primitiveBlock); // ********************* // *** Export misc // ********************* // Transforme a 3dsmax view matrix to camera matrix. static Matrix3 viewMatrix2CameraMatrix (const Matrix3& viewMatrix); // Convert a 3dsmax matrix in NeL matrix static void convertMatrix (NLMISC::CMatrix& nelMatrix, const Matrix3& maxMatrix); // Convert a NeL matrix in 3dsmax matrix static void convertMatrix (Matrix3& maxMatrix, const NLMISC::CMatrix& nelMatrix); /// Convert a 3dsmax uv matrix to a nel uv matrix static void uvMatrix2NelUVMatrix (const Matrix3& uvMatrix, NLMISC::CMatrix &dest); // Convert a 3dsmax vector in NeL vector static void convertVector (NLMISC::CVector& nelVector, const Point3& maxVector); // Get local node matrix static void getLocalMatrix (Matrix3& localMatrix, INode& node, TimeValue time); // Decompose a 3dsmax matrix in NeL translation, scale, quat. static void decompMatrix (NLMISC::CVector& nelScale, NLMISC::CQuat& nelRot, NLMISC::CVector& nelPos, const Matrix3& maxMatrix); // Convert a 3dsmax color in NeL color static void convertColor (NLMISC::CRGBA& nelColor, const Color& maxColor); // Return true if the node as the classId classid or is derived from a class with classId class id static bool isClassIdCompatible (Animatable& node, Class_ID& classId); // Return the pointer on ther subanim with the name sName of the node. If it doesn't exist, return NULL. static Animatable* getSubAnimByName (Animatable& node, const char* sName); // Get the node name static std::string getName (MtlBase& mtl); // Get the node name static std::string getName (INode& node); // Get the NEL node name. ie either NEL3D_APPDATA_INSTANCE_SHAPE appData or just GetName(). static std::string getNelObjectName (INode& node); // Get lights void getLights (std::vector& vectLight, TimeValue time, INode* node=NULL); // Get the root node of the scene INode *getRootNode() const; // Get All node (objects only) of a hierarchy. NULL => all the scene void getObjectNodes (std::vector& vectNode, TimeValue time, INode* node=NULL); // *** Paramblock2 access // Return the pointer on the subanim with the name sName of the node. If it doesn't exist, return NULL. static Control* getControlerByName (Animatable& node, const char* sName); // Return the pointer on the subanim with the name sName of the node. If it doesn't exist, return NULL. // Support only those type: // TYPE_FLOAT // TYPE_INT // TYPE_POINT3 // TYPE_BOOL static bool getValueByNameUsingParamBlock2 (Animatable& node, const char* sName, ParamType2 type, void *pValue, TimeValue time, bool verbose = true); // Get the first modifier in the pipeline of a node by its class identifier static Modifier* getModifier (INode* pNode, Class_ID modCID); // Get the ambient value NLMISC::CRGBA getAmbientColor (TimeValue time); // Get the backgorund value NLMISC::CRGBA getBackGroundColor (TimeValue time); // Get the light group static uint getLightGroup (INode *node); // Get the light animation name static std::string getAnimatedLight (INode *node); // *** Script access // Eval a scripted function static bool scriptEvaluate (const char *script, void *out, TNelScriptValueType type); // *** Appdata access // Get an appData float static float getScriptAppData (Animatable *node, uint32 id, float def); // Set an appData float static void setScriptAppData (Animatable *node, uint32 id, float value); // Get an appData integer static int getScriptAppData (Animatable *node, uint32 id, int def); // Set an appData integer static void setScriptAppData (Animatable *node, uint32 id, int value); // Get an appData integer static std::string getScriptAppData (Animatable *node, uint32 id, const std::string& def); // Set an appData integer static void setScriptAppData (Animatable *node, uint32 id, const std::string& value); // Get an appData RGBA static NLMISC::CRGBA getScriptAppData (Animatable *node, uint32 id, NLMISC::CRGBA def); // Set an appData RGBA static void setScriptAppData (Animatable *node, uint32 id, NLMISC::CRGBA val); // Output error message void outputErrorMessage (const char *message); void outputWarningMessage (const char *message); // Get an appData VertexProgram WindTree (ensure same default values for all retrieve). static void getScriptAppDataVPWT (Animatable *node, CVPWindTreeAppData &apd); // Set an appData VertexProgram WindTree. static void setScriptAppDataVPWT (Animatable *node, const CVPWindTreeAppData &apd); /** private func : this convert a polygon expressed as a max mesh into a list of ordered vectors. * This also gives an average normal by averaging faces normals. */ static void maxPolygonMeshToOrderedPoly(Mesh &mesh, std::vector &dest, const NLMISC::CMatrix &basis, NLMISC::CVector &avgNormal); // ******************** // *** Export Vegetable // ******************** /* * Build a skeleton shape * * mapBindPos is the pointer of the map of bind pos by bone. Can be NULL if the skeleton is already in the bind pos. */ bool buildVegetableShape (NL3D::CVegetableShape& skeletonShape, INode& node, TimeValue time); // ******************** // *** Export Lod Character // ******************** /* is this node a lod character ??? */ static bool isLodCharacter (INode& node, TimeValue time); /* * Build a lod character from a node */ bool buildLodCharacter (NL3D::CLodCharacterShapeBuild& lodBuild, INode& node, TimeValue time, const TInodePtrInt *nodeMap); // ************* // *** Misc *** // ************* // get a ptr to max interface Interface *getInterface() const { return _Ip; } /// Return true if error must be in dialog, false if error must not stop the process. bool isErrorInDialog () const; private: // A class that describe how build a NeL material with a max one class CMaterialDesc { public: friend class CExportNel; // Default constructor init _IndexInMaxMaterial to MISSING_VALUE, _UVMatrix to indentity and clamp to 0, 0, 1, 1 CMaterialDesc () { _IndexInMaxMaterial=UVGEN_MISSING; _IndexInMaxMaterialAlternative=UVGEN_MISSING; _UVMatrix.IdentityMatrix(); _CropU=0.f; _CropV=0.f; _CropW=1.f; _CropH=1.f; } const Matrix3 &getUVMatrix() const { return _UVMatrix; } private: // *** Data // Index in material sint _IndexInMaxMaterial; sint _IndexInMaxMaterialAlternative; // Matrix for UVs Matrix3 _UVMatrix; // Crop region float _CropU; float _CropV; float _CropW; float _CropH; }; // Max material info class CMaxMaterialInfo { public: // Default constructor CMaxMaterialInfo () { AlphaVertex = false; ColorVertex = false; AlphaVertexChannel = 0; TextureMatrixEnabled = false; uint i; for (i=0; i RemapChannel; // Material names std::string MaterialName; // Alpha vertex in this material bool AlphaVertex; /* UV channel routing : * (UVRouting[i] == 0xff) UV channel i is not needed * (UVRouting[i] != 0xff) UV channel i is needed for the material * (UVRouting[i] == i) UV channel i is present in the vertex buffer * (UVRouting[i] != i) UV channel i is not present in the vertex buffer. It is routed to another UV channel.*/ uint8 UVRouting[MAX_MAX_TEXTURE]; // Color vertex in this material bool ColorVertex; // Alpha vertex channel for this material uint AlphaVertexChannel; // allow to export a user texture matrix bool TextureMatrixEnabled; }; // Max base build structure class CMaxMeshBaseBuild { public: CMaxMeshBaseBuild () { NeedVertexColor = false; uint i; for (i=0; i MaterialInfo; }; // ********************* // *** Export mesh // ********************* // Get 3ds UVs channel used by a texmap and make a good index channel // Can return an interger in [0; MAX_MESHMAPS-1] or on of the following value: UVGEN_REFLEXION, UVGEN_MISSING static int getVertMapChannel (Texmap& texmap, Matrix3& channelMatrix, TimeValue time); // Build a CLight static bool buildLight (GenLight &maxLight, NL3D::CLight& nelLight, INode& node, TimeValue time); /** * Build a NeL base mesh interface * * if skeletonShape is NULL, no skinning is exported. */ void buildBaseMeshInterface (NL3D::CMeshBase::CMeshBaseBuild& buildMesh, CMaxMeshBaseBuild& maxBaseBuild, INode& node, TimeValue time, const NLMISC::CMatrix& basis); /** * Build a NeL mesh interface * * if skeletonShape is NULL, no skinning is exported. * if isMorphTarget is true, no "mrm/normal mesh interface" is built */ void buildMeshInterface (TriObject &tri, NL3D::CMesh::CMeshBuild& buildMesh, const NL3D::CMeshBase::CMeshBaseBuild& buildBaseMesh, const CMaxMeshBaseBuild& maxBaseBuild, INode& node, TimeValue time, const TInodePtrInt* nodeMap, const NLMISC::CMatrix& newBasis=NLMISC::CMatrix::Identity, const NLMISC::CMatrix& finalSpace=NLMISC::CMatrix::Identity, bool isMorphTarget= false); /** * Get all the blend shapes from a node in the meshbuild form */ void getBSMeshBuild (std::vector &bsList, INode &node, TimeValue time, bool skined); /** * Build a NeL mrm parameters block */ static void buildMRMParameters (Animatable& node, NL3D::CMRMParameters& params); /** * Build a mesh geom with a node */ NL3D::IMeshGeom *buildMeshGeom (INode& node, TimeValue time, const TInodePtrInt *nodeMap, NL3D::CMeshBase::CMeshBaseBuild &buildBaseMesh, std::vector& listMaterialName, bool& isTransparent, bool& isOpaque, const NLMISC::CMatrix& parentMatrix); /** * Build the mesh morpher info in the mesh geom */ void buildMeshMorph (NL3D::CMesh::CMeshBuild& buildMesh, INode &node, TimeValue time, bool skined); // Get the normal of a face for a given corner in localSpace static Point3 getLocalNormal (int face, int corner, Mesh& mesh); // Build a water shape. The given node must have a water materiel, an assertion is raised otherwise NL3D::IShape *buildWaterShape(INode& node, TimeValue time); // build a wave maker shape NL3D::IShape *buildWaveMakerShape(INode& node, TimeValue time); // ********************* // *** Export FXs *** // ********************* // Build shape from a particle system node NL3D::IShape *buildParticleSystem(INode& node, TimeValue time); // Build shape from a remanence node NL3D::IShape *buildRemanence(INode& node, TimeValue time); // Build shape from a flare node NL3D::IShape *buildFlare(INode& node, TimeValue time); // ********************* // *** Export material // ********************* /** Test wether the given max node has a water material. A water object should only have one material, and must have planar, convex geometry. * Morevover, the mapping should only have scale and offsets, no rotation */ static bool hasWaterMaterial(INode& node, TimeValue time); // Build an array of NeL material corresponding with max material at this node. void buildMaterials (std::vector& Materials, CMaxMeshBaseBuild& maxBaseBuild, INode& node, TimeValue time); // Build a NeL material corresponding with a max material. void buildAMaterial (NL3D::CMaterial& material, CMaxMaterialInfo& materialInfo, Mtl& mtl, TimeValue time); // Build a NeL texture corresponding with a max Texmap. NL3D::ITexture* buildATexture (Texmap& texmap, CMaterialDesc& remap3dsTexChannel, TimeValue time, bool forceCubic=false); /// Build a NeL texture cube from a Reflect/refract map containing 6 textures. NL3D::CTextureCube *buildTextureCubeFromReflectRefract(Texmap &texmap, TimeValue time); /// Build a NeL texture cube from a Composite map containing 6 textures. (note: no re-ordering is done, because it didn't reorder composite cube in previous version either). NL3D::CTextureCube *buildTextureCubeFromComposite(Texmap &texmap, TimeValue time); /// Build a NeL texture cube from a single texture. NL3D::CTextureCube *buildTextureCubeFromTexture(Texmap &texmap, TimeValue time); public: /** Return true if a mesh has a material whose shader requires a specific vertex shader to work (for example, per-pixel lighting). * This also stores the result in shader */ static bool hasMaterialWithShaderForVP(INode &node, TimeValue time, NL3D::CMaterial::TShader &shader); /// Test wether the given material need a specific vertex program to work correctly static bool needVP(Mtl &mat, TimeValue time, NL3D::CMaterial::TShader &shader); private: /** Build a mesh vertex program associated with the given shader * For now there can be only one vertex program per mesh, so you must specify the shader this v.p must be built for. * The meshBuild may be modfied by this operation (to add tangent space infos for example) * \return The vertex program or NULL if the op failed, or if there's no need for a v.p. */ static NL3D::IMeshVertexProgram *buildMeshMaterialShaderVP(NL3D::CMaterial::TShader shader, NL3D::CMesh::CMeshBuild *mb); /// Test wether a material need a vertex program // ********************* // *** Export Animation // ********************* // Add tracks for the node void addNodeTracks (NL3D::CAnimation& animation, INode& node, const char* parentName, CAnimationBuildCtx *animBuildCtx, bool root, CSSSBuild &ssBuilder, bool bodyBiped=false); // Add tracks for the light void addLightTracks (NL3D::CAnimation& animation, INode& node, const char* parentName); // Add tracks for the morphing void addMorphTracks (NL3D::CAnimation& animation, INode& node, const char* parentName); // Add tracks for the object void addObjTracks (NL3D::CAnimation& animation, Object& obj, const char* parentName); // Add tracks for the material void addMtlTracks (NL3D::CAnimation& animation, Mtl& mtl, const char* parentName); // Add tracks for the texture void addTexTracks (NL3D::CAnimation& animation, Texmap& tex, uint stage, const char* parentName); // Get a biped key parameter using script bool getBipedKeyInfo (const char* nodeName, const char* paramName, uint key, float& res); // Get inplace biped mode bool getBipedInplaceMode (const char* nodeName, const char* inplaceFunction, bool &res); // Change inplace biped mode bool setBipedInplaceMode (const char* nodeName, const char* inplaceFunction, bool onOff); // Current context for addAnimation() class CAnimationBuildCtx { public: struct CBipedKey { TimeValue Time; // The correct Nel Local TM NLMISC::CVector Pos; NLMISC::CQuat Quat; NLMISC::CVector Scale; }; struct CBipedNode { INode *Node; // Oversampled position std::vector Keys; }; // The animation range for Biped Nodes. BipedRangeMin and BipedRangeMax are inclusive TimeValue BipedRangeMin; TimeValue BipedRangeMax; // All biped nodes we must export. std::vector BipedNodes; public: CAnimationBuildCtx(); bool hasBipedNodes() const {return BipedNodes.size()>0;} // compile the bipedMap from BipedNodes, and other infos void compileBiped(); // From a node, get its associated CBipedNode in the BipedNodes array. CBipedNode *getBipedNodeInfo(INode *node); /* return true if this node must export Track Position. It returns true for bodyBiped and LClavicle and RClavicle limb for now. NB: We use script to now if the node is a clavicle (ie not hack-tested by node name) But this slow test is done in compileBiped(). */ bool mustExportBipedBonePos(INode *node); private: // Map from INode * to CBiped Id in BipedNodes typedef std::map TBipedMap; TBipedMap _BipedMap; // List of node which must export their position. typedef std::set TBipedSet; TBipedSet _ExportBipedBonePosSet; // Add a limb node to the _ExportBipedBonePosSet. eg: #larm. void addLimbNodeToExportPos(INode *rootNode, const char *limbId); }; // Bkup ctx of a biped bone. struct CBipedNodePlaceMode { INode *Node; bool InPlaceMode; bool InPlaceYMode; bool InPlaceXMode; }; // void buildBipedInformation(CAnimationBuildCtx &animBuildCtx, INode &node); // void overSampleBipedAnimation(CAnimationBuildCtx &animBuildCtx, uint overSampleValue); /// return the Nel Scale Reference node if any. INode *getNELScaleReferenceNode(INode &node); /// return true if the node has a biped controller (either body or slave). bool isBipedNode(INode &node); /// As part of getNELBoneLocalTM. void getNELBoneLocalScale(INode &node, TimeValue time, NLMISC::CVector &nelScale); private: // Pointer on the interface Interface *_Ip; // Texture are built path absolute bool _AbsolutePath; // Build to view the scene bool _View; // Errors goes in dialog bool _ErrorInDialog; // Error title std::string _ErrorTitle; // Build options CExportNelOptions _Options; }; /** replacment for sprintf scanf (because of localisation in max) */ float toFloatMax(const char *src); // Same as to float max, but returns true if succeed bool toFloatMax(const char *src, float &dest); std::string toStringMax(float value); std::string toStringMax(int value); #endif // NL_EXPORT_NEL_H /* End of export_nel.h */