diff --git a/pandatool/src/eggbase/eggReader.cxx b/pandatool/src/eggbase/eggReader.cxx index 6de0425968..8a5ace4b1e 100644 --- a/pandatool/src/eggbase/eggReader.cxx +++ b/pandatool/src/eggbase/eggReader.cxx @@ -155,6 +155,19 @@ as_reader() { return this; } +//////////////////////////////////////////////////////////////////// +// Function: EggReader::pre_process_egg_file +// Access: Public, Virtual +// Description: Performs any processing of the egg file that is +// appropriate after reading it in. +// +// Normally, you should not need to call this function +// directly; it is called automatically at startup. +//////////////////////////////////////////////////////////////////// +void EggReader:: +pre_process_egg_file() { +} + //////////////////////////////////////////////////////////////////// // Function: EggReader::handle_args // Access: Protected, Virtual @@ -215,6 +228,8 @@ handle_args(ProgramBase::Args &args) { _data->merge(file_data); } + pre_process_egg_file(); + return true; } diff --git a/pandatool/src/eggbase/eggReader.h b/pandatool/src/eggbase/eggReader.h index 588b5c3cd4..36a46bca2f 100644 --- a/pandatool/src/eggbase/eggReader.h +++ b/pandatool/src/eggbase/eggReader.h @@ -39,6 +39,7 @@ public: void add_delod_options(double default_delod = -1.0); virtual EggReader *as_reader(); + virtual void pre_process_egg_file(); protected: virtual bool handle_args(Args &args); diff --git a/pandatool/src/eggbase/eggToSomething.cxx b/pandatool/src/eggbase/eggToSomething.cxx index 3256190caf..fbfa585fd8 100644 --- a/pandatool/src/eggbase/eggToSomething.cxx +++ b/pandatool/src/eggbase/eggToSomething.cxx @@ -82,6 +82,68 @@ EggToSomething(const string &format_name, "one of 'y-up', 'z-up', 'y-up-left', or 'z-up-left'. The default " "is the same coordinate system as the input egg file. If this is " "different from the input egg file, a conversion will be performed."); + + _input_units = DU_invalid; + _output_units = DU_invalid; +} + +//////////////////////////////////////////////////////////////////// +// Function: EggToSomething::add_units_options +// Access: Public +// Description: Adds -ui and -uo as valid options for this program. +// If the user specifies -uo and -ui, or just -uo and +// the program specifies -ui by setting _input_units, +// the indicated units conversion will be automatically +// applied before writing out the egg file. +//////////////////////////////////////////////////////////////////// +void EggToSomething:: +add_units_options() { + add_option + ("ui", "units", 40, + "Specify the units of the input egg file. If this is " + "specified, the vertices in the egg file will be scaled as " + "necessary to make the appropriate units conversion; otherwise, " + "the vertices will be left as they are.", + &EggToSomething::dispatch_units, NULL, &_input_units); + + add_option + ("uo", "units", 40, + "Specify the units of the resulting " + _format_name + + " file. Normally, the default units for the format are used.", + &EggToSomething::dispatch_units, NULL, &_output_units); +} + +//////////////////////////////////////////////////////////////////// +// Function: EggToSomething::apply_units_scale +// Access: Protected +// Description: Applies the scale indicated by the input and output +// units to the indicated egg file. This is normally +// done automatically when the file is read in. +//////////////////////////////////////////////////////////////////// +void EggToSomething:: +apply_units_scale(EggData *data) { + if (_output_units != DU_invalid && _input_units != DU_invalid && + _input_units != _output_units) { + nout << "Converting from " << format_long_unit(_input_units) + << " to " << format_long_unit(_output_units) << "\n"; + double scale = convert_units(_input_units, _output_units); + data->transform(LMatrix4d::scale_mat(scale)); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: EggToSomething::pre_process_egg_file +// Access: Protected, Virtual +// Description: Performs any processing of the egg file that is +// appropriate after reading it in. +// +// Normally, you should not need to call this function +// directly; it is called automatically at startup. +//////////////////////////////////////////////////////////////////// +void EggToSomething:: +pre_process_egg_file() { + apply_units_scale(_data); + EggConverter::pre_process_egg_file(); } //////////////////////////////////////////////////////////////////// diff --git a/pandatool/src/eggbase/eggToSomething.h b/pandatool/src/eggbase/eggToSomething.h index ef3cf4fa84..4da4a88124 100644 --- a/pandatool/src/eggbase/eggToSomething.h +++ b/pandatool/src/eggbase/eggToSomething.h @@ -22,6 +22,7 @@ #include "pandatoolbase.h" #include "eggConverter.h" +#include "distanceUnit.h" //////////////////////////////////////////////////////////////////// // Class : EggToSomething @@ -36,8 +37,15 @@ public: bool allow_last_param = true, bool allow_stdout = true); + void add_units_options(); + protected: + void apply_units_scale(EggData *data); + virtual void pre_process_egg_file(); virtual bool handle_args(Args &args); + + DistanceUnit _input_units; + DistanceUnit _output_units; }; #endif diff --git a/pandatool/src/mayaegg/Sources.pp b/pandatool/src/mayaegg/Sources.pp index 948beebe10..e16615fcef 100644 --- a/pandatool/src/mayaegg/Sources.pp +++ b/pandatool/src/mayaegg/Sources.pp @@ -17,6 +17,7 @@ #define SOURCES \ config_mayaegg.cxx config_mayaegg.h \ mayaEggGroupUserData.cxx mayaEggGroupUserData.I mayaEggGroupUserData.h \ + mayaEggLoader.cxx mayaEggLoader.h \ mayaBlendDesc.cxx mayaBlendDesc.h \ mayaNodeDesc.cxx mayaNodeDesc.h \ mayaNodeTree.cxx mayaNodeTree.h \ diff --git a/pandatool/src/mayaeggimport/mayaEggLoader.cxx b/pandatool/src/mayaegg/mayaEggLoader.cxx similarity index 93% rename from pandatool/src/mayaeggimport/mayaEggLoader.cxx rename to pandatool/src/mayaegg/mayaEggLoader.cxx index 55f58df45e..b9f059022e 100755 --- a/pandatool/src/mayaeggimport/mayaEggLoader.cxx +++ b/pandatool/src/mayaegg/mayaEggLoader.cxx @@ -1,840 +1,839 @@ -// Filename: mayaEggImport.cxx -// Created by: jyelon (20Jul05) -// -//////////////////////////////////////////////////////////////////// -// -// PANDA 3D SOFTWARE -// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved -// -// All use of this software is subject to the terms of the Panda 3d -// Software license. You should have received a copy of this license -// along with this source code; you will also find a current copy of -// the license at http://etc.cmu.edu/panda3d/docs/license/ . -// -// To contact the maintainers of this program write to -// panda3d-general@lists.sourceforge.net . -// -//////////////////////////////////////////////////////////////////// -// -// This file contains the code for class MayaEggLoader. This class -// does the actual work of copying an EggData tree into the maya scene. -// -//////////////////////////////////////////////////////////////////// - - -#include "pandatoolbase.h" -#include "notifyCategoryProxy.h" - -#include "eggData.h" -#include "eggVertexPool.h" -#include "eggVertex.h" -#include "eggPolygon.h" -#include "eggPrimitive.h" -#include "eggGroupNode.h" -#include "eggPolysetMaker.h" -#include "eggBin.h" - -#include "pre_maya_include.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "post_maya_include.h" - -#include "mayaEggLoader.h" - -class MayaEggMesh; -class MayaEggJoint; -class MayaEggTex; - -NotifyCategoryDeclNoExport(mayaloader); -NotifyCategoryDef(mayaloader, ""); - -class MayaEggLoader -{ -public: - bool ConvertEggData(EggData *data, bool merge, bool model, bool anim); - bool ConvertEggFile(const char *name, bool merge, bool model, bool anim); - -public: - void TraverseEggNode(EggNode *node, EggGroup *context); - MayaEggMesh *GetMesh(EggVertexPool *pool); - MayaEggJoint *FindJoint(EggGroup *joint); - MayaEggJoint *MakeJoint(EggGroup *joint, EggGroup *context); - MayaEggTex *GetTex(const string &name, const string &fn); - void CreateSkinCluster(MayaEggMesh *M); - - typedef phash_map MeshTable; - typedef second_of_pair_iterator MeshIterator; - typedef phash_map JointTable; - typedef second_of_pair_iterator JointIterator; - typedef phash_map TexTable; - typedef second_of_pair_iterator TexIterator; - - MeshTable _mesh_tab; - JointTable _joint_tab; - TexTable _tex_tab; - CoordinateSystem _coord_sys; -}; - -MFloatPoint ConvertCoordSys(CoordinateSystem sys, LVector3d vec) -{ - if (sys == CS_zup_right) { - return MFloatPoint(vec[0], vec[2], -vec[1]); - } else { - return MFloatPoint(vec[0], vec[1], vec[2]); - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// -// MayaEggTex -// -//////////////////////////////////////////////////////////////////////////////////////////////////// - -class MayaEggTex -{ -public: - string _name; - string _path; - MObject _file_texture; - MObject _shader; - MObject _shading_group; - - MFnSingleIndexedComponent _component; - void AssignNames(void); -}; - -void MayaEggTex::AssignNames(void) -{ - if (_name == "") return; - MFnDependencyNode shader(_shader); - MFnDependencyNode sgroup(_shading_group); - MFnDependencyNode filetex(_file_texture); - shader.setName(MString(_name.c_str())+"Shader"); - sgroup.setName(MString(_name.c_str())); - if (_file_texture != MObject::kNullObj) - filetex.setName(MString(_name.c_str())+"File"); -} - -MayaEggTex *MayaEggLoader::GetTex(const string &name, const string &fn) -{ - if (_tex_tab.count(fn)) - return _tex_tab[fn]; - - MStatus status; - MFnLambertShader shader; - MFnDependencyNode filetex; - MFnSet sgroup; - - if (fn=="") { - MSelectionList selection; - MObject initGroup; - selection.clear(); - MGlobal::getSelectionListByName("initialShadingGroup",selection); - selection.getDependNode(0, initGroup); - sgroup.setObject(initGroup); - } else { - MPlugArray oldplugs; - MDGModifier dgmod; - - shader.create(true,&status); - sgroup.create(MSelectionList(), MFnSet::kRenderableOnly, &status); - MPlug surfplug = sgroup.findPlug("surfaceShader"); - if (surfplug.connectedTo(oldplugs,true,false)) { - for (unsigned int i=0; i_name = name; - res->_path = fn; - res->_file_texture = filetex.object(); - res->_shader = shader.object(); - res->_shading_group = sgroup.object(); - - _tex_tab[fn] = res; - return res; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// -// MayaEggJoint -// -//////////////////////////////////////////////////////////////////////////////////////////////////// - -class MayaEggJoint -{ -public: - LMatrix4d _trans; - LVector3d _endpos; - LVector3d _perp; - double _thickness; - MObject _joint; - MMatrix _joint_abs; - MDagPath _joint_dag_path; - bool _inskin; - int _index; - EggGroup *_egg_joint; - MayaEggJoint *_parent; - vector _children; - -public: - void GetRotation(LVector3d &xv, LVector3d &yv, LVector3d &zv); - LVector3d GetPos(void) { return _trans.get_row3(3); } - MayaEggJoint *ChooseBestChild(LVector3d dir); - void ChooseEndPos(double thickness); - void CreateMayaBone(CoordinateSystem sys); - void AssignNames(void); -}; - -void MayaEggJoint::GetRotation(LVector3d &xv, LVector3d &yv, LVector3d &zv) -{ - xv = _trans.get_row3(0); - yv = _trans.get_row3(1); - zv = _trans.get_row3(2); - xv.normalize(); - yv.normalize(); - zv = xv.cross(yv); - zv.normalize(); - yv = zv.cross(xv); -} - -void MayaEggJoint::AssignNames(void) -{ - string name = _egg_joint->get_name(); - MFnDependencyNode joint(_joint); - joint.setName(name.c_str()); -} - -MayaEggJoint *MayaEggLoader::FindJoint(EggGroup *joint) -{ - if (joint==0) return 0; - return _joint_tab[joint]; -} - -MayaEggJoint *MayaEggLoader::MakeJoint(EggGroup *joint, EggGroup *context) -{ - MayaEggJoint *parent = FindJoint(context); - MayaEggJoint *result = new MayaEggJoint; - LMatrix4d t = joint->get_transform3d(); - if (parent) { - result->_trans = t * parent->_trans; - } else { - result->_trans = t; - } - result->_endpos = LVector3d(0,0,0); - result->_perp = LVector3d(0,0,0); - result->_thickness = 0.0; - result->_egg_joint = joint; - result->_parent = parent; - result->_joint = MObject::kNullObj; - result->_inskin = false; - result->_index = -1; - if (parent) parent->_children.push_back(result); - _joint_tab[joint] = result; - return result; -} - -MayaEggJoint *MayaEggJoint::ChooseBestChild(LVector3d dir) -{ - if (dir.length() < 0.001) return 0; - dir.normalize(); - double firstbest = -1000; - MayaEggJoint *firstchild = 0; - LVector3d firstpos = GetPos(); - double secondbest = 0; - for (unsigned int i=0; i<_children.size(); i++) { - MayaEggJoint *child = _children[i]; - LVector3d tryfwd = child->GetPos() - GetPos(); - if ((child->GetPos() != firstpos) && (tryfwd.length() > 0.001)) { - LVector3d trydir = tryfwd; - trydir.normalize(); - double quality = trydir.dot(dir); - if (quality > firstbest) { - secondbest = firstbest; - firstbest = quality; - firstpos = child->GetPos(); - firstchild = child; - } else if (quality > secondbest) { - secondbest = quality; - } - } - } - if (firstbest > secondbest + 0.1) - return firstchild; - return 0; -} - -void MayaEggJoint::ChooseEndPos(double thickness) -{ - LVector3d parentpos(0,0,0); - LVector3d parentendpos(0,0,1); - if (_parent) { - parentpos = _parent->GetPos(); - parentendpos = _parent->_endpos; - } - LVector3d fwd = GetPos() - parentpos; - if (fwd.length() < 0.001) { - fwd = parentendpos - parentpos; - } - fwd.normalize(); - MayaEggJoint *child = ChooseBestChild(fwd); - if (child == 0) { - _endpos = fwd * thickness * 0.8 + GetPos(); - _thickness = thickness * 0.8; - } else { - _endpos = child->GetPos(); - _thickness = (_endpos - GetPos()).length(); - if (_thickness > thickness) _thickness = thickness; - } - LVector3d orient = _endpos - GetPos(); - orient.normalize(); - LVector3d altaxis = orient.cross(LVector3d(0,-1,0)); - if (altaxis.length() < 0.001) altaxis = orient.cross(LVector3d(0,0,1)); - _perp = altaxis.cross(orient); - _perp.normalize(); -} - -void MayaEggJoint::CreateMayaBone(CoordinateSystem sys) -{ - LVector3d rxv, ryv, rzv; - GetRotation(rxv, ryv, rzv); - MFloatPoint xv(ConvertCoordSys(sys, rxv)); - MFloatPoint yv(ConvertCoordSys(sys, ryv)); - MFloatPoint zv(ConvertCoordSys(sys, rzv)); - MFloatPoint pos(ConvertCoordSys(sys, GetPos())); - MFloatPoint endpos(ConvertCoordSys(sys, _endpos)); - MFloatPoint tzv(ConvertCoordSys(sys, _perp)); - - double m[4][4]; - m[0][0]=xv.x; m[0][1]=xv.y; m[0][2]=xv.z; m[0][3]=0; - m[1][0]=yv.x; m[1][1]=yv.y; m[1][2]=yv.z; m[1][3]=0; - m[2][0]=zv.x; m[2][1]=zv.y; m[2][2]=zv.z; m[2][3]=0; - m[3][0]=pos.x; m[3][1]=pos.y; m[3][2]=pos.z; m[3][3]=1; - MMatrix trans(m); - _joint_abs = trans; - if (_parent) trans = trans * _parent->_joint_abs.inverse(); - MTransformationMatrix mtm(trans); - MFnIkJoint ikj; - if (_parent) ikj.create(_parent->_joint); - else ikj.create(); - ikj.set(mtm); - _joint = ikj.object(); - ikj.getPath(_joint_dag_path); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// -// MayaEggMesh -// -//////////////////////////////////////////////////////////////////////////////////////////////////// - -typedef pair MayaEggWeight; - -struct MayaEggVertex -{ - Vertexd _pos; - Normald _normal; - vector _weights; - int _index; -}; - -struct MEV_Compare: public stl_hash_compare -{ - size_t operator()(const MayaEggVertex &key) const - { - return key._pos.add_hash(key._normal.get_hash()); - } - bool operator()(const MayaEggVertex &k1, const MayaEggVertex &k2) const - { - int n = k1._pos.compare_to(k2._pos); - if (n < 0) return true; - if (n > 0) return false; - n = k1._normal.compare_to(k2._normal); - if (n < 0) return true; - if (n > 0) return false; - n = k1._weights.size() - k2._weights.size(); - if (n < 0) return true; - if (n > 0) return false; - for (unsigned int i=0; i 0) return false; - EggGroup *g1 = k1._weights[i].second; - EggGroup *g2 = k2._weights[i].second; - if (g1 < g2) return true; - if (g1 > g2) return false; - } - return false; - } -}; - -typedef phash_set VertTable; -typedef phash_map TVertTable; -typedef phash_map CVertTable; - -class MayaEggMesh -{ -public: - - EggVertexPool *_pool; - MFloatPointArray _vertexArray; - MIntArray _polygonCounts; - MIntArray _polygonConnects; - MFloatArray _uarray; - MFloatArray _varray; - MIntArray _uvIds; - MObject _transNode; - MObject _shapeNode; - MDagPath _shape_dag_path; - int _vert_count; - int _tvert_count; - int _cvert_count; - int _face_count; - vector _face_tex; - - VertTable _vert_tab; - TVertTable _tvert_tab; - CVertTable _cvert_tab; - - int GetVert(EggVertex *vert, EggGroup *context, CoordinateSystem sys); - int GetTVert(TexCoordd uv); - int GetCVert(Colorf col); - int AddFace(int v0, int v1, int v2, int tv0, int tv1, int tv2, int cv0, int cv1, int cv2, MayaEggTex *tex); - EggGroup *GetControlJoint(void); - void ConnectTextures(void); - void AssignNames(void); -}; - -#define CTRLJOINT_DEFORM ((EggGroup*)((char*)(-1))) - -int MayaEggMesh::GetVert(EggVertex *vert, EggGroup *context, CoordinateSystem sys) -{ - MayaEggVertex vtx; - vtx._pos = vert->get_pos3(); - vtx._normal = vert->get_normal(); - vtx._index = 0; - - EggVertex::GroupRef::const_iterator gri; - for (gri = vert->gref_begin(); gri != vert->gref_end(); ++gri) { - EggGroup *egg_joint = (*gri); - double membership = egg_joint->get_vertex_membership(vert); - vtx._weights.push_back(MayaEggWeight(membership, egg_joint)); - } - if (vtx._weights.size()==0) { - if (context != 0) - vtx._weights.push_back(MayaEggWeight(1.0, context)); - } - - VertTable::const_iterator vti = _vert_tab.find(vtx); - if (vti != _vert_tab.end()) - return vti->_index; - - vtx._index = _vert_count++; - _vertexArray.append(ConvertCoordSys(sys, vtx._pos)); - _vert_tab.insert(vtx); - return vtx._index; -} - -int MayaEggMesh::GetTVert(TexCoordd uv) -{ - if (_tvert_tab.count(uv)) - return _tvert_tab[uv]; - int idx = _tvert_count++; - _uarray.append(uv.get_x()); - _varray.append(uv.get_y()); - _tvert_tab[uv] = idx; - return idx; -} - -int MayaEggMesh::GetCVert(Colorf col) -{ - // if (_cvert_tab.count(col)) - // return _cvert_tab[col]; - // if (_cvert_count == _mesh->numCVerts) { - // int nsize = _cvert_count*2 + 100; - // _mesh->setNumVertCol(nsize, _cvert_count?TRUE:FALSE); - // } - // int idx = _cvert_count++; - // _mesh->vertCol[idx] = Point3(col.get_x(), col.get_y(), col.get_z()); - // _cvert_tab[col] = idx; - // return idx; - return 0; -} - -void MayaEggMesh::AssignNames(void) -{ - string name = _pool->get_name(); - int nsize = name.size(); - if ((nsize > 6) && (name.rfind(".verts")==(nsize-6))) - name.resize(nsize-6); - MFnDependencyNode dnshape(_shapeNode); - MFnDependencyNode dntrans(_transNode); - dnshape.setName(MString(name.c_str())+"Shape"); - dntrans.setName(MString(name.c_str())); -} - -MayaEggMesh *MayaEggLoader::GetMesh(EggVertexPool *pool) -{ - MayaEggMesh *result = _mesh_tab[pool]; - if (result == 0) { - result = new MayaEggMesh; - result->_pool = pool; - result->_vert_count = 0; - result->_tvert_count = 0; - result->_cvert_count = 0; - result->_face_count = 0; - _mesh_tab[pool] = result; - } - return result; -} - -int MayaEggMesh::AddFace(int v0, int v1, int v2, int tv0, int tv1, int tv2, int cv0, int cv1, int cv2, MayaEggTex *tex) -{ - int idx = _face_count++; - _polygonCounts.append(3); - _polygonConnects.append(v0); - _polygonConnects.append(v1); - _polygonConnects.append(v2); - _uvIds.append(tv0); - _uvIds.append(tv1); - _uvIds.append(tv2); - _face_tex.push_back(tex); - return idx; -} - -void MayaEggMesh::ConnectTextures(void) -{ - bool subtex = false; - for (int i=1; i<_face_count; i++) - if (_face_tex[i] != _face_tex[0]) - subtex = true; - if (!subtex) { - MFnSet sg(_face_tex[0]->_shading_group); - sg.addMember(_shapeNode); - return; - } - for (int i=0; i<_face_count; i++) { - MayaEggTex *tex = _face_tex[i]; - if (tex->_component.object()==MObject::kNullObj) - tex->_component.create(MFn::kMeshPolygonComponent); - tex->_component.addElement(i); - } - for (int i=0; i<_face_count; i++) { - MayaEggTex *tex = _face_tex[i]; - if (tex->_component.object()!=MObject::kNullObj) { - MFnSet sg(tex->_shading_group); - sg.addMember(_shape_dag_path, tex->_component.object()); - tex->_component.setObject(MObject::kNullObj); - } - } -} - -EggGroup *MayaEggMesh::GetControlJoint(void) -{ - EggGroup *result; - VertTable::const_iterator vert = _vert_tab.begin(); - if (vert == _vert_tab.end()) return 0; - switch (vert->_weights.size()) { - case 0: - for (++vert; vert != _vert_tab.end(); ++vert) - if (vert->_weights.size() != 0) - return CTRLJOINT_DEFORM; - return 0; - case 1: - result = vert->_weights[0].second; - for (++vert; vert != _vert_tab.end(); ++vert) - if ((vert->_weights.size() != 1) || (vert->_weights[0].second != result)) - return CTRLJOINT_DEFORM; - return result; - default: - return CTRLJOINT_DEFORM; - } -} - -void MayaEggLoader::CreateSkinCluster(MayaEggMesh *M) -{ - MString cmd("skinCluster -mi "); - vector joints; - - VertTable::const_iterator vert; - int maxInfluences = 0; - for (vert=M->_vert_tab.begin(); vert != M->_vert_tab.end(); ++vert) { - if ((int)(vert->_weights.size()) > maxInfluences) - maxInfluences = vert->_weights.size(); - for (unsigned int i=0; i_weights.size(); i++) { - double strength = vert->_weights[i].first; - MayaEggJoint *joint = FindJoint(vert->_weights[i].second); - if (!joint->_inskin) { - joint->_inskin = true; - joint->_index = joints.size(); - joints.push_back(joint); - } - } - } - cmd += maxInfluences; - - for (unsigned int i=0; i_joint); - cmd = cmd + " "; - cmd = cmd + joint.name(); - } - - MFnDependencyNode shape(M->_shapeNode); - cmd = cmd + " "; - cmd = cmd + shape.name(); - - MStatus status; - MDGModifier dgmod; - status = dgmod.commandToExecute(cmd); - if (status != MStatus::kSuccess) { perror("skinCluster commandToExecute"); return; } - status = dgmod.doIt(); - if (status != MStatus::kSuccess) { perror("skinCluster doIt"); return; } - - MPlugArray oldplugs; - MPlug inPlug = shape.findPlug("inMesh"); - if ((!inPlug.connectedTo(oldplugs,true,false))||(oldplugs.length() != 1)) { - cerr << "skinCluster command failed"; - return; - } - MFnSkinCluster skinCluster(oldplugs[0].node()); - MIntArray influenceIndices; - MFnSingleIndexedComponent component; - component.create(MFn::kMeshVertComponent); - component.setCompleteData(M->_vert_count); - - for (unsigned int i=0; i_joint_dag_path, &status); - if (status != MStatus::kSuccess) { perror("skinCluster index"); return; } - influenceIndices.append((int)index); - } - - MDagPathArray paths; - unsigned infcount = skinCluster.influenceObjects(paths, &status); - if (status != MStatus::kSuccess) { perror("influenceObjects"); return; } - for (unsigned int i=0; i_shape_dag_path, component.object(), index, 0.0, false, NULL); - } - - MFloatArray values; - int tot = M->_vert_count * joints.size(); - values.setLength(tot); - for (int i=0; i_vert_tab.begin(); vert != M->_vert_tab.end(); ++vert) { - for (unsigned int i=0; i_weights.size(); i++) { - double strength = vert->_weights[i].first; - MayaEggJoint *joint = FindJoint(vert->_weights[i].second); - values[vert->_index * joints.size() + joint->_index] = (float)strength; - } - } - skinCluster.setWeights(M->_shape_dag_path, component.object(), influenceIndices, values, false, NULL); - - for (unsigned int i=0; i_inskin = false; - joints[i]->_index = -1; - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// -// TraverseEggData -// -// We have an EggData in memory, and now we're going to copy that -// over into the maya scene graph. -// -//////////////////////////////////////////////////////////////////////////////////////////////////// - -void MayaEggLoader::TraverseEggNode(EggNode *node, EggGroup *context) -{ - vector vertIndices; - vector tvertIndices; - vector cvertIndices; - - if (node->is_of_type(EggPolygon::get_class_type())) { - EggPolygon *poly = DCAST(EggPolygon, node); - - MayaEggTex *tex = 0; - LMatrix3d uvtrans = LMatrix3d::ident_mat(); - - if (poly->has_texture()) { - EggTexture *etex = poly->get_texture(0); - tex = GetTex(etex->get_name(), etex->get_fullpath().to_os_specific()); - if (etex->has_transform()) - uvtrans = etex->get_transform2d(); - } else { - tex = GetTex("",""); - } - - EggPolygon::const_iterator ci; - MayaEggMesh *mesh = GetMesh(poly->get_pool()); - vertIndices.clear(); - tvertIndices.clear(); - cvertIndices.clear(); - for (ci = poly->begin(); ci != poly->end(); ++ci) { - EggVertex *vtx = (*ci); - EggVertexPool *pool = poly->get_pool(); - TexCoordd uv = vtx->get_uv(); - vertIndices.push_back(mesh->GetVert(vtx, context, _coord_sys)); - tvertIndices.push_back(mesh->GetTVert(uv * uvtrans)); - cvertIndices.push_back(mesh->GetCVert(vtx->get_color())); - } - for (unsigned int i=1; iAddFace(vertIndices[0], vertIndices[i], vertIndices[i+1], - tvertIndices[0], tvertIndices[i], tvertIndices[i+1], - cvertIndices[0], cvertIndices[i], cvertIndices[i+1], - tex); - } else if (node->is_of_type(EggGroupNode::get_class_type())) { - EggGroupNode *group = DCAST(EggGroupNode, node); - if (node->is_of_type(EggGroup::get_class_type())) { - EggGroup *group = DCAST(EggGroup, node); - if (group->is_joint()) { - MakeJoint(group, context); - context = group; - } - } - EggGroupNode::const_iterator ci; - for (ci = group->begin(); ci != group->end(); ++ci) { - TraverseEggNode(*ci, context); - } - } -} - -bool MayaEggLoader::ConvertEggData(EggData *data, bool merge, bool model, bool anim) -{ - if (!merge) { - mayaloader_cat.error() << "Currently, only 'merge' mode is implemented.\n"; - return false; - } - - if ((anim) || (!model)) { - mayaloader_cat.error() << "Currently, only model-loading is implemented.\n"; - return false; - } - - MeshIterator ci; - JointIterator ji; - TexIterator ti; - - _coord_sys = data->get_coordinate_system(); - - TraverseEggNode(data, NULL); - - for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) { - MayaEggMesh *mesh = (*ci); - if (mesh->_face_count==0) continue; - - MStatus status; - MFnMesh mfn; - MString cset; - - mesh->_transNode = mfn.create(mesh->_vert_count, mesh->_face_count, - mesh->_vertexArray, mesh->_polygonCounts, mesh->_polygonConnects, - mesh->_uarray, mesh->_varray, - MObject::kNullObj, &status); - mesh->_shapeNode = mfn.object(); - mfn.getPath(mesh->_shape_dag_path); - mesh->ConnectTextures(); - mfn.getCurrentUVSetName(cset); - mfn.assignUVs(mesh->_polygonCounts, mesh->_uvIds, &cset); - } - - double thickness = 0.0; - for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) { - double dfo = ((*ji)->GetPos()).length(); - if (dfo > thickness) thickness = dfo; - } - thickness = thickness * 0.025; - for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) { - MayaEggJoint *joint = *ji; - joint->ChooseEndPos(thickness); - joint->CreateMayaBone(_coord_sys); - } - - for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) { - MayaEggMesh *mesh = (*ci); - EggGroup *joint = mesh->GetControlJoint(); - if (joint) CreateSkinCluster(mesh); - } - - for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) (*ci)->AssignNames(); - for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) (*ji)->AssignNames(); - for (ti = _tex_tab.begin(); ti != _tex_tab.end(); ++ti) (*ti)->AssignNames(); - - for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) delete *ci; - for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) delete *ji; - for (ti = _tex_tab.begin(); ti != _tex_tab.end(); ++ti) delete *ti; - - // ResumeSetKeyMode(); - // ResumeAnimate(); - - mayaloader_cat.info() << "Egg import successful\n"; - return true; -} - -bool MayaEggLoader::ConvertEggFile(const char *name, bool merge, bool model, bool anim) -{ - EggData data; - Filename datafn = Filename::from_os_specific(name); - if (!data.read(datafn)) { - mayaloader_cat.error() << "Cannot read Egg file for import\n"; - return false; - } - return ConvertEggData(&data, merge, model, anim); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// -// The two global functions that form the API of this module. -// -//////////////////////////////////////////////////////////////////////////////////////////////////// - -bool MayaLoadEggData(EggData *data, bool merge, bool model, bool anim) -{ - MayaEggLoader loader; - return loader.ConvertEggData(data, merge, model, anim); -} - -bool MayaLoadEggFile(const char *name, bool merge, bool model, bool anim) -{ - MayaEggLoader loader; - return loader.ConvertEggFile(name, merge, model, anim); -} - +// Filename: mayaEggImport.cxx +// Created by: jyelon (20Jul05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// +// +// This file contains the code for class MayaEggLoader. This class +// does the actual work of copying an EggData tree into the maya scene. +// +//////////////////////////////////////////////////////////////////// + + +#include "pandatoolbase.h" +#include "notifyCategoryProxy.h" + +#include "eggData.h" +#include "eggVertexPool.h" +#include "eggVertex.h" +#include "eggPolygon.h" +#include "eggPrimitive.h" +#include "eggGroupNode.h" +#include "eggPolysetMaker.h" +#include "eggBin.h" + +#include "pre_maya_include.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "post_maya_include.h" + +#include "mayaEggLoader.h" + +class MayaEggMesh; +class MayaEggJoint; +class MayaEggTex; + +NotifyCategoryDeclNoExport(mayaloader); +NotifyCategoryDef(mayaloader, ""); + +class MayaEggLoader +{ +public: + bool ConvertEggData(EggData *data, bool merge, bool model, bool anim); + bool ConvertEggFile(const char *name, bool merge, bool model, bool anim); + +public: + void TraverseEggNode(EggNode *node, EggGroup *context); + MayaEggMesh *GetMesh(EggVertexPool *pool); + MayaEggJoint *FindJoint(EggGroup *joint); + MayaEggJoint *MakeJoint(EggGroup *joint, EggGroup *context); + MayaEggTex *GetTex(const string &name, const string &fn); + void CreateSkinCluster(MayaEggMesh *M); + + typedef phash_map MeshTable; + typedef second_of_pair_iterator MeshIterator; + typedef phash_map JointTable; + typedef second_of_pair_iterator JointIterator; + typedef phash_map TexTable; + typedef second_of_pair_iterator TexIterator; + + MeshTable _mesh_tab; + JointTable _joint_tab; + TexTable _tex_tab; +}; + +MFloatPoint MakeMayaPoint(const LVector3d &vec) +{ + return MFloatPoint(vec[0], vec[1], vec[2]); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// MayaEggTex +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +class MayaEggTex +{ +public: + string _name; + string _path; + MObject _file_texture; + MObject _shader; + MObject _shading_group; + + MFnSingleIndexedComponent _component; + void AssignNames(void); +}; + +void MayaEggTex::AssignNames(void) +{ + if (_name == "") return; + MFnDependencyNode shader(_shader); + MFnDependencyNode sgroup(_shading_group); + MFnDependencyNode filetex(_file_texture); + shader.setName(MString(_name.c_str())+"Shader"); + sgroup.setName(MString(_name.c_str())); + if (_file_texture != MObject::kNullObj) + filetex.setName(MString(_name.c_str())+"File"); +} + +MayaEggTex *MayaEggLoader::GetTex(const string &name, const string &fn) +{ + if (_tex_tab.count(fn)) + return _tex_tab[fn]; + + MStatus status; + MFnLambertShader shader; + MFnDependencyNode filetex; + MFnSet sgroup; + + if (fn=="") { + MSelectionList selection; + MObject initGroup; + selection.clear(); + MGlobal::getSelectionListByName("initialShadingGroup",selection); + selection.getDependNode(0, initGroup); + sgroup.setObject(initGroup); + } else { + MPlugArray oldplugs; + MDGModifier dgmod; + + shader.create(true,&status); + sgroup.create(MSelectionList(), MFnSet::kRenderableOnly, &status); + MPlug surfplug = sgroup.findPlug("surfaceShader"); + if (surfplug.connectedTo(oldplugs,true,false)) { + for (unsigned int i=0; i_name = name; + res->_path = fn; + res->_file_texture = filetex.object(); + res->_shader = shader.object(); + res->_shading_group = sgroup.object(); + + _tex_tab[fn] = res; + return res; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// MayaEggJoint +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +class MayaEggJoint +{ +public: + LMatrix4d _trans; + LVector3d _endpos; + LVector3d _perp; + double _thickness; + MObject _joint; + MMatrix _joint_abs; + MDagPath _joint_dag_path; + bool _inskin; + int _index; + EggGroup *_egg_joint; + MayaEggJoint *_parent; + vector _children; + +public: + void GetRotation(LVector3d &xv, LVector3d &yv, LVector3d &zv); + LVector3d GetPos(void) { return _trans.get_row3(3); } + MayaEggJoint *ChooseBestChild(LVector3d dir); + void ChooseEndPos(double thickness); + void CreateMayaBone(); + void AssignNames(void); +}; + +void MayaEggJoint::GetRotation(LVector3d &xv, LVector3d &yv, LVector3d &zv) +{ + xv = _trans.get_row3(0); + yv = _trans.get_row3(1); + zv = _trans.get_row3(2); + xv.normalize(); + yv.normalize(); + zv = xv.cross(yv); + zv.normalize(); + yv = zv.cross(xv); +} + +void MayaEggJoint::AssignNames(void) +{ + string name = _egg_joint->get_name(); + MFnDependencyNode joint(_joint); + joint.setName(name.c_str()); +} + +MayaEggJoint *MayaEggLoader::FindJoint(EggGroup *joint) +{ + if (joint==0) return 0; + return _joint_tab[joint]; +} + +MayaEggJoint *MayaEggLoader::MakeJoint(EggGroup *joint, EggGroup *context) +{ + MayaEggJoint *parent = FindJoint(context); + MayaEggJoint *result = new MayaEggJoint; + LMatrix4d t = joint->get_transform3d(); + if (parent) { + result->_trans = t * parent->_trans; + } else { + result->_trans = t; + } + result->_endpos = LVector3d(0,0,0); + result->_perp = LVector3d(0,0,0); + result->_thickness = 0.0; + result->_egg_joint = joint; + result->_parent = parent; + result->_joint = MObject::kNullObj; + result->_inskin = false; + result->_index = -1; + if (parent) parent->_children.push_back(result); + _joint_tab[joint] = result; + return result; +} + +MayaEggJoint *MayaEggJoint::ChooseBestChild(LVector3d dir) +{ + if (dir.length() < 0.001) return 0; + dir.normalize(); + double firstbest = -1000; + MayaEggJoint *firstchild = 0; + LVector3d firstpos = GetPos(); + double secondbest = 0; + for (unsigned int i=0; i<_children.size(); i++) { + MayaEggJoint *child = _children[i]; + LVector3d tryfwd = child->GetPos() - GetPos(); + if ((child->GetPos() != firstpos) && (tryfwd.length() > 0.001)) { + LVector3d trydir = tryfwd; + trydir.normalize(); + double quality = trydir.dot(dir); + if (quality > firstbest) { + secondbest = firstbest; + firstbest = quality; + firstpos = child->GetPos(); + firstchild = child; + } else if (quality > secondbest) { + secondbest = quality; + } + } + } + if (firstbest > secondbest + 0.1) + return firstchild; + return 0; +} + +void MayaEggJoint::ChooseEndPos(double thickness) +{ + LVector3d parentpos(0,0,0); + LVector3d parentendpos(0,0,1); + if (_parent) { + parentpos = _parent->GetPos(); + parentendpos = _parent->_endpos; + } + LVector3d fwd = GetPos() - parentpos; + if (fwd.length() < 0.001) { + fwd = parentendpos - parentpos; + } + fwd.normalize(); + MayaEggJoint *child = ChooseBestChild(fwd); + if (child == 0) { + _endpos = fwd * thickness * 0.8 + GetPos(); + _thickness = thickness * 0.8; + } else { + _endpos = child->GetPos(); + _thickness = (_endpos - GetPos()).length(); + if (_thickness > thickness) _thickness = thickness; + } + LVector3d orient = _endpos - GetPos(); + orient.normalize(); + LVector3d altaxis = orient.cross(LVector3d(0,-1,0)); + if (altaxis.length() < 0.001) altaxis = orient.cross(LVector3d(0,0,1)); + _perp = altaxis.cross(orient); + _perp.normalize(); +} + +void MayaEggJoint::CreateMayaBone() +{ + LVector3d rxv, ryv, rzv; + GetRotation(rxv, ryv, rzv); + MFloatPoint xv(MakeMayaPoint(rxv)); + MFloatPoint yv(MakeMayaPoint(ryv)); + MFloatPoint zv(MakeMayaPoint(rzv)); + MFloatPoint pos(MakeMayaPoint(GetPos())); + MFloatPoint endpos(MakeMayaPoint(_endpos)); + MFloatPoint tzv(MakeMayaPoint(_perp)); + + double m[4][4]; + m[0][0]=xv.x; m[0][1]=xv.y; m[0][2]=xv.z; m[0][3]=0; + m[1][0]=yv.x; m[1][1]=yv.y; m[1][2]=yv.z; m[1][3]=0; + m[2][0]=zv.x; m[2][1]=zv.y; m[2][2]=zv.z; m[2][3]=0; + m[3][0]=pos.x; m[3][1]=pos.y; m[3][2]=pos.z; m[3][3]=1; + MMatrix trans(m); + _joint_abs = trans; + if (_parent) trans = trans * _parent->_joint_abs.inverse(); + MTransformationMatrix mtm(trans); + MFnIkJoint ikj; + if (_parent) ikj.create(_parent->_joint); + else ikj.create(); + ikj.set(mtm); + _joint = ikj.object(); + ikj.getPath(_joint_dag_path); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// MayaEggMesh +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef pair MayaEggWeight; + +struct MayaEggVertex +{ + Vertexd _pos; + Normald _normal; + vector _weights; + int _index; +}; + +struct MEV_Compare: public stl_hash_compare +{ + size_t operator()(const MayaEggVertex &key) const + { + return key._pos.add_hash(key._normal.get_hash()); + } + bool operator()(const MayaEggVertex &k1, const MayaEggVertex &k2) const + { + int n = k1._pos.compare_to(k2._pos); + if (n < 0) return true; + if (n > 0) return false; + n = k1._normal.compare_to(k2._normal); + if (n < 0) return true; + if (n > 0) return false; + n = k1._weights.size() - k2._weights.size(); + if (n < 0) return true; + if (n > 0) return false; + for (unsigned int i=0; i 0) return false; + EggGroup *g1 = k1._weights[i].second; + EggGroup *g2 = k2._weights[i].second; + if (g1 < g2) return true; + if (g1 > g2) return false; + } + return false; + } +}; + +typedef phash_set VertTable; +typedef phash_map TVertTable; +typedef phash_map CVertTable; + +class MayaEggMesh +{ +public: + + EggVertexPool *_pool; + MFloatPointArray _vertexArray; + MIntArray _polygonCounts; + MIntArray _polygonConnects; + MFloatArray _uarray; + MFloatArray _varray; + MIntArray _uvIds; + MObject _transNode; + MObject _shapeNode; + MDagPath _shape_dag_path; + int _vert_count; + int _tvert_count; + int _cvert_count; + int _face_count; + vector _face_tex; + + VertTable _vert_tab; + TVertTable _tvert_tab; + CVertTable _cvert_tab; + + int GetVert(EggVertex *vert, EggGroup *context); + int GetTVert(TexCoordd uv); + int GetCVert(Colorf col); + int AddFace(int v0, int v1, int v2, int tv0, int tv1, int tv2, int cv0, int cv1, int cv2, MayaEggTex *tex); + EggGroup *GetControlJoint(void); + void ConnectTextures(void); + void AssignNames(void); +}; + +#define CTRLJOINT_DEFORM ((EggGroup*)((char*)(-1))) + +int MayaEggMesh::GetVert(EggVertex *vert, EggGroup *context) +{ + MayaEggVertex vtx; + vtx._pos = vert->get_pos3(); + vtx._normal = vert->get_normal(); + vtx._index = 0; + + EggVertex::GroupRef::const_iterator gri; + for (gri = vert->gref_begin(); gri != vert->gref_end(); ++gri) { + EggGroup *egg_joint = (*gri); + double membership = egg_joint->get_vertex_membership(vert); + vtx._weights.push_back(MayaEggWeight(membership, egg_joint)); + } + if (vtx._weights.size()==0) { + if (context != 0) + vtx._weights.push_back(MayaEggWeight(1.0, context)); + } + + VertTable::const_iterator vti = _vert_tab.find(vtx); + if (vti != _vert_tab.end()) + return vti->_index; + + vtx._index = _vert_count++; + _vertexArray.append(MakeMayaPoint(vtx._pos)); + _vert_tab.insert(vtx); + return vtx._index; +} + +int MayaEggMesh::GetTVert(TexCoordd uv) +{ + if (_tvert_tab.count(uv)) + return _tvert_tab[uv]; + int idx = _tvert_count++; + _uarray.append(uv.get_x()); + _varray.append(uv.get_y()); + _tvert_tab[uv] = idx; + return idx; +} + +int MayaEggMesh::GetCVert(Colorf col) +{ + // if (_cvert_tab.count(col)) + // return _cvert_tab[col]; + // if (_cvert_count == _mesh->numCVerts) { + // int nsize = _cvert_count*2 + 100; + // _mesh->setNumVertCol(nsize, _cvert_count?TRUE:FALSE); + // } + // int idx = _cvert_count++; + // _mesh->vertCol[idx] = Point3(col.get_x(), col.get_y(), col.get_z()); + // _cvert_tab[col] = idx; + // return idx; + return 0; +} + +void MayaEggMesh::AssignNames(void) +{ + string name = _pool->get_name(); + int nsize = name.size(); + if ((nsize > 6) && (name.rfind(".verts")==(nsize-6))) + name.resize(nsize-6); + MFnDependencyNode dnshape(_shapeNode); + MFnDependencyNode dntrans(_transNode); + dnshape.setName(MString(name.c_str())+"Shape"); + dntrans.setName(MString(name.c_str())); +} + +MayaEggMesh *MayaEggLoader::GetMesh(EggVertexPool *pool) +{ + MayaEggMesh *result = _mesh_tab[pool]; + if (result == 0) { + result = new MayaEggMesh; + result->_pool = pool; + result->_vert_count = 0; + result->_tvert_count = 0; + result->_cvert_count = 0; + result->_face_count = 0; + _mesh_tab[pool] = result; + } + return result; +} + +int MayaEggMesh::AddFace(int v0, int v1, int v2, int tv0, int tv1, int tv2, int cv0, int cv1, int cv2, MayaEggTex *tex) +{ + int idx = _face_count++; + _polygonCounts.append(3); + _polygonConnects.append(v0); + _polygonConnects.append(v1); + _polygonConnects.append(v2); + _uvIds.append(tv0); + _uvIds.append(tv1); + _uvIds.append(tv2); + _face_tex.push_back(tex); + return idx; +} + +void MayaEggMesh::ConnectTextures(void) +{ + bool subtex = false; + for (int i=1; i<_face_count; i++) + if (_face_tex[i] != _face_tex[0]) + subtex = true; + if (!subtex) { + MFnSet sg(_face_tex[0]->_shading_group); + sg.addMember(_shapeNode); + return; + } + for (int i=0; i<_face_count; i++) { + MayaEggTex *tex = _face_tex[i]; + if (tex->_component.object()==MObject::kNullObj) + tex->_component.create(MFn::kMeshPolygonComponent); + tex->_component.addElement(i); + } + for (int i=0; i<_face_count; i++) { + MayaEggTex *tex = _face_tex[i]; + if (tex->_component.object()!=MObject::kNullObj) { + MFnSet sg(tex->_shading_group); + sg.addMember(_shape_dag_path, tex->_component.object()); + tex->_component.setObject(MObject::kNullObj); + } + } +} + +EggGroup *MayaEggMesh::GetControlJoint(void) +{ + EggGroup *result; + VertTable::const_iterator vert = _vert_tab.begin(); + if (vert == _vert_tab.end()) return 0; + switch (vert->_weights.size()) { + case 0: + for (++vert; vert != _vert_tab.end(); ++vert) + if (vert->_weights.size() != 0) + return CTRLJOINT_DEFORM; + return 0; + case 1: + result = vert->_weights[0].second; + for (++vert; vert != _vert_tab.end(); ++vert) + if ((vert->_weights.size() != 1) || (vert->_weights[0].second != result)) + return CTRLJOINT_DEFORM; + return result; + default: + return CTRLJOINT_DEFORM; + } +} + +void MayaEggLoader::CreateSkinCluster(MayaEggMesh *M) +{ + MString cmd("skinCluster -mi "); + vector joints; + + VertTable::const_iterator vert; + int maxInfluences = 0; + for (vert=M->_vert_tab.begin(); vert != M->_vert_tab.end(); ++vert) { + if ((int)(vert->_weights.size()) > maxInfluences) + maxInfluences = vert->_weights.size(); + for (unsigned int i=0; i_weights.size(); i++) { + double strength = vert->_weights[i].first; + MayaEggJoint *joint = FindJoint(vert->_weights[i].second); + if (!joint->_inskin) { + joint->_inskin = true; + joint->_index = joints.size(); + joints.push_back(joint); + } + } + } + cmd += maxInfluences; + + for (unsigned int i=0; i_joint); + cmd = cmd + " "; + cmd = cmd + joint.name(); + } + + MFnDependencyNode shape(M->_shapeNode); + cmd = cmd + " "; + cmd = cmd + shape.name(); + + MStatus status; + MDGModifier dgmod; + status = dgmod.commandToExecute(cmd); + if (status != MStatus::kSuccess) { perror("skinCluster commandToExecute"); return; } + status = dgmod.doIt(); + if (status != MStatus::kSuccess) { perror("skinCluster doIt"); return; } + + MPlugArray oldplugs; + MPlug inPlug = shape.findPlug("inMesh"); + if ((!inPlug.connectedTo(oldplugs,true,false))||(oldplugs.length() != 1)) { + cerr << "skinCluster command failed"; + return; + } + MFnSkinCluster skinCluster(oldplugs[0].node()); + MIntArray influenceIndices; + MFnSingleIndexedComponent component; + component.create(MFn::kMeshVertComponent); + component.setCompleteData(M->_vert_count); + + for (unsigned int i=0; i_joint_dag_path, &status); + if (status != MStatus::kSuccess) { perror("skinCluster index"); return; } + influenceIndices.append((int)index); + } + + MDagPathArray paths; + unsigned infcount = skinCluster.influenceObjects(paths, &status); + if (status != MStatus::kSuccess) { perror("influenceObjects"); return; } + for (unsigned int i=0; i_shape_dag_path, component.object(), index, 0.0, false, NULL); + } + + MFloatArray values; + int tot = M->_vert_count * joints.size(); + values.setLength(tot); + for (int i=0; i_vert_tab.begin(); vert != M->_vert_tab.end(); ++vert) { + for (unsigned int i=0; i_weights.size(); i++) { + double strength = vert->_weights[i].first; + MayaEggJoint *joint = FindJoint(vert->_weights[i].second); + values[vert->_index * joints.size() + joint->_index] = (float)strength; + } + } + skinCluster.setWeights(M->_shape_dag_path, component.object(), influenceIndices, values, false, NULL); + + for (unsigned int i=0; i_inskin = false; + joints[i]->_index = -1; + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// TraverseEggData +// +// We have an EggData in memory, and now we're going to copy that +// over into the maya scene graph. +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void MayaEggLoader::TraverseEggNode(EggNode *node, EggGroup *context) +{ + vector vertIndices; + vector tvertIndices; + vector cvertIndices; + + if (node->is_of_type(EggPolygon::get_class_type())) { + EggPolygon *poly = DCAST(EggPolygon, node); + + MayaEggTex *tex = 0; + LMatrix3d uvtrans = LMatrix3d::ident_mat(); + + if (poly->has_texture()) { + EggTexture *etex = poly->get_texture(0); + tex = GetTex(etex->get_name(), etex->get_fullpath().to_os_specific()); + if (etex->has_transform()) + uvtrans = etex->get_transform2d(); + } else { + tex = GetTex("",""); + } + + EggPolygon::const_iterator ci; + MayaEggMesh *mesh = GetMesh(poly->get_pool()); + vertIndices.clear(); + tvertIndices.clear(); + cvertIndices.clear(); + for (ci = poly->begin(); ci != poly->end(); ++ci) { + EggVertex *vtx = (*ci); + EggVertexPool *pool = poly->get_pool(); + TexCoordd uv = vtx->get_uv(); + vertIndices.push_back(mesh->GetVert(vtx, context)); + tvertIndices.push_back(mesh->GetTVert(uv * uvtrans)); + cvertIndices.push_back(mesh->GetCVert(vtx->get_color())); + } + for (unsigned int i=1; iAddFace(vertIndices[0], vertIndices[i], vertIndices[i+1], + tvertIndices[0], tvertIndices[i], tvertIndices[i+1], + cvertIndices[0], cvertIndices[i], cvertIndices[i+1], + tex); + } else if (node->is_of_type(EggGroupNode::get_class_type())) { + EggGroupNode *group = DCAST(EggGroupNode, node); + if (node->is_of_type(EggGroup::get_class_type())) { + EggGroup *group = DCAST(EggGroup, node); + if (group->is_joint()) { + MakeJoint(group, context); + context = group; + } + } + EggGroupNode::const_iterator ci; + for (ci = group->begin(); ci != group->end(); ++ci) { + TraverseEggNode(*ci, context); + } + } +} + +bool MayaEggLoader::ConvertEggData(EggData *data, bool merge, bool model, bool anim) +{ + if (!merge) { + mayaloader_cat.error() << "Currently, only 'merge' mode is implemented.\n"; + return false; + } + + if ((anim) || (!model)) { + mayaloader_cat.error() << "Currently, only model-loading is implemented.\n"; + return false; + } + + MeshIterator ci; + JointIterator ji; + TexIterator ti; + + if (MGlobal::isYAxisUp()) { + data->set_coordinate_system(CS_yup_right); + } else { + data->set_coordinate_system(CS_zup_right); + } + + TraverseEggNode(data, NULL); + + for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) { + MayaEggMesh *mesh = (*ci); + if (mesh->_face_count==0) continue; + + MStatus status; + MFnMesh mfn; + MString cset; + + mesh->_transNode = mfn.create(mesh->_vert_count, mesh->_face_count, + mesh->_vertexArray, mesh->_polygonCounts, mesh->_polygonConnects, + mesh->_uarray, mesh->_varray, + MObject::kNullObj, &status); + mesh->_shapeNode = mfn.object(); + mfn.getPath(mesh->_shape_dag_path); + mesh->ConnectTextures(); + mfn.getCurrentUVSetName(cset); + mfn.assignUVs(mesh->_polygonCounts, mesh->_uvIds, &cset); + } + + double thickness = 0.0; + for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) { + double dfo = ((*ji)->GetPos()).length(); + if (dfo > thickness) thickness = dfo; + } + thickness = thickness * 0.025; + for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) { + MayaEggJoint *joint = *ji; + joint->ChooseEndPos(thickness); + joint->CreateMayaBone(); + } + + for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) { + MayaEggMesh *mesh = (*ci); + EggGroup *joint = mesh->GetControlJoint(); + if (joint) CreateSkinCluster(mesh); + } + + for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) (*ci)->AssignNames(); + for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) (*ji)->AssignNames(); + for (ti = _tex_tab.begin(); ti != _tex_tab.end(); ++ti) (*ti)->AssignNames(); + + for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) delete *ci; + for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) delete *ji; + for (ti = _tex_tab.begin(); ti != _tex_tab.end(); ++ti) delete *ti; + + // ResumeSetKeyMode(); + // ResumeAnimate(); + + mayaloader_cat.info() << "Egg import successful\n"; + return true; +} + +bool MayaEggLoader::ConvertEggFile(const char *name, bool merge, bool model, bool anim) +{ + EggData data; + Filename datafn = Filename::from_os_specific(name); + if (!data.read(datafn)) { + mayaloader_cat.error() << "Cannot read Egg file for import\n"; + return false; + } + return ConvertEggData(&data, merge, model, anim); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// The two global functions that form the API of this module. +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +bool MayaLoadEggData(EggData *data, bool merge, bool model, bool anim) +{ + MayaEggLoader loader; + return loader.ConvertEggData(data, merge, model, anim); +} + +bool MayaLoadEggFile(const char *name, bool merge, bool model, bool anim) +{ + MayaEggLoader loader; + return loader.ConvertEggFile(name, merge, model, anim); +} + diff --git a/pandatool/src/mayaeggimport/mayaEggLoader.h b/pandatool/src/mayaegg/mayaEggLoader.h similarity index 100% rename from pandatool/src/mayaeggimport/mayaEggLoader.h rename to pandatool/src/mayaegg/mayaEggLoader.h diff --git a/pandatool/src/mayaprogs/Sources.pp b/pandatool/src/mayaprogs/Sources.pp index fe7737a4be..ef488a2265 100644 --- a/pandatool/src/mayaprogs/Sources.pp +++ b/pandatool/src/mayaprogs/Sources.pp @@ -1,6 +1,7 @@ #define BUILD_DIRECTORY $[HAVE_MAYA] #define maya2egg maya2egg +#define egg2maya egg2maya #define mayacopy mayacopy #if $[UNIX_PLATFORM] @@ -11,6 +12,7 @@ // it in also on Unix.) #set maya2egg maya2egg_bin +#set egg2maya egg2maya_bin #set mayacopy mayacopy_bin #begin sed_bin_target @@ -21,6 +23,14 @@ #end sed_bin_target +#begin sed_bin_target + #define TARGET egg2maya + + #define SOURCE mayapath_script + #define COMMAND s:xxx:$[MAYA_LOCATION]:g;s:yyy:$[TARGET]:g;s+zzz+$[MAYA_LICENSE_FILE]+g; + +#end sed_bin_target + #begin sed_bin_target #define TARGET mayacopy @@ -51,6 +61,26 @@ #end bin_target +#begin bin_target + #define USE_PACKAGES maya + #define TARGET $[egg2maya] + #define LOCAL_LIBS \ + mayaegg maya eggbase progbase + #define OTHER_LIBS \ + egg:c pandaegg:m \ + linmath:c putil:c panda:m \ + express:c pandaexpress:m \ + interrogatedb:c dtoolutil:c dtoolbase:c prc:c dconfig:c dtoolconfig:m dtool:m pystub + + // Irix requires this to be named explicitly. + #define UNIX_SYS_LIBS \ + ExtensionLayer + + #define SOURCES \ + eggToMaya.cxx eggToMaya.h + +#end bin_target + #begin bin_target #define USE_PACKAGES maya @@ -112,6 +142,29 @@ mayaSavePview.cxx mayaSavePview.h #end lib_target +#begin lib_target + #define BUILD_TARGET $[not $[LINK_ALL_STATIC]] + #define USE_PACKAGES maya + #define TARGET mayaEggImport + #define LOCAL_LIBS mayaegg maya + #define OTHER_LIBS \ + egg:c pandaegg:m \ + framework:m \ + linmath:c putil:c panda:m \ + express:c pandaexpress:m \ + interrogatedb:c dtoolutil:c dtoolbase:c prc:c dconfig:c dtoolconfig:m dtool:m pystub + + #define BUILDING_DLL BUILDING_MISC + + #if $[WINDOWS_PLATFORM] + #define dlllib mll + #endif + + #define SOURCES \ + mayaEggImport.cxx + +#end lib_target + #begin lib_target #define USE_PACKAGES maya #define TARGET mayaloader diff --git a/pandatool/src/mayaeggimport/eggImportOptions.mel b/pandatool/src/mayaprogs/eggImportOptions.mel similarity index 100% rename from pandatool/src/mayaeggimport/eggImportOptions.mel rename to pandatool/src/mayaprogs/eggImportOptions.mel diff --git a/pandatool/src/mayaprogs/eggToMaya.cxx b/pandatool/src/mayaprogs/eggToMaya.cxx new file mode 100755 index 0000000000..1c709fa919 --- /dev/null +++ b/pandatool/src/mayaprogs/eggToMaya.cxx @@ -0,0 +1,118 @@ +// Filename: eggToMaya.cxx +// Created by: drose (11Aug05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "eggToMaya.h" +#include "mayaEggLoader.h" +#include "mayaApi.h" + +// We must define this to prevent Maya from doubly-declaring its +// MApiVersion string in this file as well as in libmayaegg. +#define _MApiVersion + +#include "pre_maya_include.h" +#include +#include +#include "post_maya_include.h" + +//////////////////////////////////////////////////////////////////// +// Function: EggToMaya::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +EggToMaya:: +EggToMaya() : + EggToSomething("Maya", ".mb", true, false) +{ + add_units_options(); + + set_binary_output(true); + set_program_description + ("egg2maya converts files from egg format to Maya .mb or .ma " + "format. At the moment, it contains support for basic geometry " + "(polygons with textures)."); + + add_option + ("a", "", 0, + "Convert animation tables.", + &EggToMaya::dispatch_none, &_convert_anim); + + add_option + ("m", "", 0, + "Convert polygon models. You may specify both -a and -m at the same " + "time. If you specify neither, the default is -m.", + &EggToMaya::dispatch_none, &_convert_model); + + // Maya files always store centimeters. + _output_units = DU_centimeters; +} + +//////////////////////////////////////////////////////////////////// +// Function: EggToMaya::run +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void EggToMaya:: +run() { + if (!_convert_anim && !_convert_model) { + _convert_model = true; + } + + // Let's convert the output file to a full path before we initialize + // Maya, since Maya now has a nasty habit of changing the current + // directory. + _output_filename.make_absolute(); + + nout << "Initializing Maya.\n"; + PT(MayaApi) maya = MayaApi::open_api(_program_name); + if (!maya->is_valid()) { + nout << "Unable to initialize Maya.\n"; + exit(1); + } + + MStatus status; + status = MFileIO::newFile(true); + if (!status) { + status.perror("Could not initialize file"); + exit(1); + } + + // Now convert the data. + if (!MayaLoadEggData(_data, true, _convert_model, _convert_anim)) { + nout << "Unable to convert egg file.\n"; + exit(1); + } + + // And write out the resulting Maya file. + string os_specific = _output_filename.to_os_generic(); + const char *file_type = NULL; + if (_output_filename.get_extension() == "mb") { + file_type = "mayaBinary"; + } + status = MFileIO::saveAs(os_specific.c_str(), file_type); + if (!status) { + status.perror("Could not save file"); + exit(1); + } +} + +int main(int argc, char *argv[]) { + EggToMaya prog; + prog.parse_command_line(argc, argv); + prog.run(); + return 0; +} diff --git a/pandatool/src/mayaprogs/eggToMaya.h b/pandatool/src/mayaprogs/eggToMaya.h new file mode 100755 index 0000000000..9542710384 --- /dev/null +++ b/pandatool/src/mayaprogs/eggToMaya.h @@ -0,0 +1,42 @@ +// Filename: eggToMaya.h +// Created by: drose (11Aug05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef EGGTOMAYA_H +#define EGGTOMAYA_H + +#include "pandatoolbase.h" + +#include "eggToSomething.h" + +//////////////////////////////////////////////////////////////////// +// Class : EggToMaya +// Description : A program to read an egg file and write a maya file. +//////////////////////////////////////////////////////////////////// +class EggToMaya : public EggToSomething { +public: + EggToMaya(); + + void run(); + +private: + bool _convert_anim; + bool _convert_model; +}; + +#endif + diff --git a/pandatool/src/mayaeggimport/mayaEggImport.cxx b/pandatool/src/mayaprogs/mayaEggImport.cxx similarity index 94% rename from pandatool/src/mayaeggimport/mayaEggImport.cxx rename to pandatool/src/mayaprogs/mayaEggImport.cxx index 8867806990..f7f25bad7d 100755 --- a/pandatool/src/mayaeggimport/mayaEggImport.cxx +++ b/pandatool/src/mayaprogs/mayaEggImport.cxx @@ -31,6 +31,10 @@ #include "dtoolbase.h" +// We must define this to prevent Maya from doubly-declaring its +// MApiVersion string in this file as well as in libmayaegg. +#define _MApiVersion + #include "pre_maya_include.h" #include #include