Adding notifier support (not quite working yet)
This commit is contained in:
parent
be15ba4750
commit
aa83a7b3a0
|
|
@ -1,43 +1,42 @@
|
|||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Filename: maxEggImport.cxx
|
||||
// Created by: jyelon (15Jul05)
|
||||
//
|
||||
// maxEggImport.cxx - Egg Importer for 3D Studio Max.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 is the wrapper code for the max importer plugin.
|
||||
// It includes:
|
||||
//
|
||||
// - user interface dialogs and popups
|
||||
// - plugin initialization/registration
|
||||
//
|
||||
// It does not include the actual code to traverse the EggData.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
// MAX includes
|
||||
#include "maxEggLoader.h"
|
||||
#include "Max.h"
|
||||
#include "maxImportRes.h"
|
||||
#include "istdplug.h"
|
||||
#include "stdmat.h"
|
||||
#include "decomp.h"
|
||||
#include "shape.h"
|
||||
#include "simpobj.h"
|
||||
#include "iparamb2.h"
|
||||
#include "iskin.h"
|
||||
#include "modstack.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"
|
||||
// panda includes.
|
||||
#include "notifyCategoryProxy.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static FILE *lgfile;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The MaxEggImporter class
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class MaxEggMesh;
|
||||
class MaxEggJoint;
|
||||
class MaxEggTex;
|
||||
class BoneFunctions;
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
class MaxEggImporter : public SceneImport
|
||||
{
|
||||
|
|
@ -59,37 +58,11 @@ public:
|
|||
|
||||
public:
|
||||
// GUI-related fields
|
||||
static Interface *_ip;
|
||||
static ImpInterface *_impip;
|
||||
static BOOL _merge;
|
||||
static BOOL _importmodel;
|
||||
static BOOL _importanim;
|
||||
|
||||
public:
|
||||
// Import-related methods:
|
||||
void TraverseEggData(EggData *data);
|
||||
void TraverseEggNode(EggNode *node, EggGroup *context);
|
||||
MaxEggMesh *GetMesh(EggVertexPool *pool);
|
||||
MaxEggJoint *FindJoint(EggGroup *joint);
|
||||
MaxEggJoint *MakeJoint(EggGroup *joint, EggGroup *context);
|
||||
MaxEggTex *GetTex(const string &fn);
|
||||
|
||||
public:
|
||||
// Import-related fields:
|
||||
typedef phash_map<EggVertexPool *, MaxEggMesh *> MeshTable;
|
||||
typedef second_of_pair_iterator<MeshTable::const_iterator> MeshIterator;
|
||||
typedef phash_map<EggGroup *, MaxEggJoint *> JointTable;
|
||||
typedef second_of_pair_iterator<JointTable::const_iterator> JointIterator;
|
||||
typedef phash_map<string, MaxEggTex *> TexTable;
|
||||
typedef second_of_pair_iterator<TexTable::const_iterator> TexIterator;
|
||||
MeshTable _mesh_tab;
|
||||
JointTable _joint_tab;
|
||||
TexTable _tex_tab;
|
||||
int _next_tex;
|
||||
};
|
||||
|
||||
Interface *MaxEggImporter::_ip;
|
||||
ImpInterface *MaxEggImporter::_impip;
|
||||
BOOL MaxEggImporter::_merge = TRUE;
|
||||
BOOL MaxEggImporter::_importmodel = TRUE;
|
||||
BOOL MaxEggImporter::_importanim = FALSE;
|
||||
|
|
@ -211,615 +184,24 @@ static BOOL CALLBACK ImportDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
|
|||
|
||||
int MaxEggImporter::DoImport(const TCHAR *name,ImpInterface *ii,Interface *i, BOOL suppressPrompts)
|
||||
{
|
||||
// Grab the interface pointer.
|
||||
_ip = i;
|
||||
_impip = ii;
|
||||
|
||||
// Prompt the user with our dialogbox.
|
||||
if (!DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_IMPORT_DLG),
|
||||
_ip->GetMAXHWnd(), ImportDlgProc, (LPARAM)this)) {
|
||||
i->GetMAXHWnd(), ImportDlgProc, (LPARAM)this)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Read in the egg file.
|
||||
EggData data;
|
||||
Filename datafn = Filename::from_os_specific(name);
|
||||
if (!data.read(datafn)) {
|
||||
MessageBox(NULL, "Cannot read Egg file", "Panda3D Egg Importer", MB_OK);
|
||||
return 1;
|
||||
std::ostringstream log;
|
||||
Notify::ptr()->set_ostream_ptr(&log, false);
|
||||
bool ok = MaxLoadEggFile(name, _merge ? true:false, _importmodel ? true:false, _importanim ? true:false);
|
||||
const char *txt = log.str().c_str();
|
||||
if (txt[0]) MessageBox(NULL, txt, "Panda3D Importer", MB_OK);
|
||||
else {
|
||||
if (!ok) MessageBox(NULL, "Import Failed, unknown reason\n", "Panda3D Importer", MB_OK);
|
||||
}
|
||||
|
||||
// Do all the good stuff.
|
||||
TraverseEggData(&data);
|
||||
Notify::ptr()->set_ostream_ptr(NULL, false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// MaxEggTex
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class MaxEggTex
|
||||
{
|
||||
public:
|
||||
string _path;
|
||||
int _id;
|
||||
StdMat *_mat;
|
||||
BitmapTex *_bmt;
|
||||
};
|
||||
|
||||
MaxEggTex *MaxEggImporter::GetTex(const string &fn)
|
||||
{
|
||||
if (_tex_tab.count(fn))
|
||||
return _tex_tab[fn];
|
||||
|
||||
BitmapTex *bmt = NewDefaultBitmapTex();
|
||||
bmt->SetMapName((TCHAR*)(fn.c_str()));
|
||||
StdMat *mat = NewDefaultStdMat();
|
||||
mat->SetSubTexmap(ID_DI, bmt);
|
||||
mat->SetTexmapAmt(ID_DI, 1.0, 0);
|
||||
mat->EnableMap(ID_DI, TRUE);
|
||||
mat->SetActiveTexmap(bmt);
|
||||
MaxEggImporter::_ip->ActivateTexture(bmt, mat);
|
||||
|
||||
MaxEggTex *res = new MaxEggTex;
|
||||
res->_path = fn;
|
||||
res->_id = _next_tex ++;
|
||||
res->_bmt = bmt;
|
||||
res->_mat = mat;
|
||||
|
||||
_tex_tab[fn] = res;
|
||||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// MaxEggJoint
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class MaxEggJoint
|
||||
{
|
||||
public:
|
||||
Point3 _xv,_yv,_zv;
|
||||
Point3 _pos;
|
||||
Point3 _endpos;
|
||||
Point3 _zaxis;
|
||||
double _thickness;
|
||||
bool _inskin;
|
||||
SimpleObject2 *_bone;
|
||||
INode *_node;
|
||||
EggGroup *_egg_joint;
|
||||
MaxEggJoint *_parent;
|
||||
vector <MaxEggJoint *> _children;
|
||||
|
||||
public:
|
||||
MaxEggJoint *ChooseBestChild(Point3 dir);
|
||||
void ChooseEndPos(double thickness);
|
||||
void CreateMaxBone(void);
|
||||
};
|
||||
|
||||
MaxEggJoint *MaxEggImporter::FindJoint(EggGroup *joint)
|
||||
{
|
||||
if (joint==0) return 0;
|
||||
return _joint_tab[joint];
|
||||
}
|
||||
|
||||
MaxEggJoint *MaxEggImporter::MakeJoint(EggGroup *joint, EggGroup *context)
|
||||
{
|
||||
MaxEggJoint *parent = FindJoint(context);
|
||||
MaxEggJoint *result = new MaxEggJoint;
|
||||
LMatrix4d t = joint->get_transform();
|
||||
if (parent) {
|
||||
result->_xv = parent->_xv*((float)t(0,0)) + parent->_yv*((float)t(0,1)) + parent->_zv*((float)t(0,2));
|
||||
result->_yv = parent->_xv*((float)t(1,0)) + parent->_yv*((float)t(1,1)) + parent->_zv*((float)t(1,2));
|
||||
result->_zv = parent->_xv*((float)t(2,0)) + parent->_yv*((float)t(2,1)) + parent->_zv*((float)t(2,2));
|
||||
result->_pos = parent->_xv*((float)t(3,0)) + parent->_yv*((float)t(3,1)) + parent->_zv*((float)t(3,2)) + parent->_pos;
|
||||
} else {
|
||||
result->_xv = Point3(((float)t(0,0)), ((float)t(0,1)), ((float)t(0,2)));
|
||||
result->_yv = Point3(((float)t(1,0)), ((float)t(1,1)), ((float)t(1,2)));
|
||||
result->_zv = Point3(((float)t(2,0)), ((float)t(2,1)), ((float)t(2,2)));
|
||||
result->_pos = Point3(((float)t(3,0)), ((float)t(3,1)), ((float)t(3,2)));
|
||||
}
|
||||
result->_endpos = Point3(0,0,0);
|
||||
result->_zaxis = Point3(0,0,0);
|
||||
result->_thickness = 0.0;
|
||||
result->_inskin = false;
|
||||
result->_bone = 0;
|
||||
result->_node = 0;
|
||||
result->_egg_joint = joint;
|
||||
result->_parent = parent;
|
||||
if (parent) parent->_children.push_back(result);
|
||||
_joint_tab[joint] = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
MaxEggJoint *MaxEggJoint::ChooseBestChild(Point3 dir)
|
||||
{
|
||||
if (dir.Length() < 0.001) return 0;
|
||||
dir = dir.Normalize();
|
||||
double firstbest = -1000;
|
||||
MaxEggJoint *firstchild = 0;
|
||||
Point3 firstpos = _pos;
|
||||
double secondbest = 0;
|
||||
for (int i=0; i<_children.size(); i++) {
|
||||
MaxEggJoint *child = _children[i];
|
||||
Point3 tryfwd = child->_pos - _pos;
|
||||
if ((child->_pos != firstpos) && (tryfwd.Length() > 0.001)) {
|
||||
Point3 trydir = tryfwd.Normalize();
|
||||
double quality = trydir % dir;
|
||||
if (quality > firstbest) {
|
||||
secondbest = firstbest;
|
||||
firstbest = quality;
|
||||
firstpos = child->_pos;
|
||||
firstchild = child;
|
||||
} else if (quality > secondbest) {
|
||||
secondbest = quality;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (firstbest > secondbest + 0.1)
|
||||
return firstchild;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MaxEggJoint::ChooseEndPos(double thickness)
|
||||
{
|
||||
Point3 parentpos(0,0,0);
|
||||
Point3 parentendpos(0,0,1);
|
||||
if (_parent) {
|
||||
parentpos = _parent->_pos;
|
||||
parentendpos = _parent->_endpos;
|
||||
}
|
||||
Point3 fwd = _pos - parentpos;
|
||||
if (fwd.Length() < 0.001) {
|
||||
fwd = parentendpos - parentpos;
|
||||
}
|
||||
fwd = fwd.Normalize();
|
||||
MaxEggJoint *child = ChooseBestChild(fwd);
|
||||
if (child == 0) {
|
||||
_endpos = fwd * ((float)(thickness * 0.8)) + _pos;
|
||||
_thickness = thickness * 0.8;
|
||||
} else {
|
||||
_endpos = child->_pos;
|
||||
_thickness = (_endpos - _pos).Length();
|
||||
if (_thickness > thickness) _thickness = thickness;
|
||||
}
|
||||
Point3 orient = (_endpos - _pos).Normalize();
|
||||
Point3 altaxis = orient ^ Point3(0,-1,0);
|
||||
if (altaxis.Length() < 0.001) altaxis = orient ^ Point3(0,0,1);
|
||||
_zaxis = (altaxis ^ orient).Normalize();
|
||||
}
|
||||
|
||||
void MaxEggJoint::CreateMaxBone(void)
|
||||
{
|
||||
Point3 fwd = _endpos - _pos;
|
||||
double len = fwd.Length();
|
||||
Point3 txv = fwd * ((float)(1.0/len));
|
||||
Point3 tzv = _zaxis;
|
||||
Point3 tyv = tzv ^ txv;
|
||||
Point3 row1 = Point3(txv % _xv, txv % _yv, txv % _zv);
|
||||
Point3 row2 = Point3(tyv % _xv, tyv % _yv, tyv % _zv);
|
||||
Point3 row3 = Point3(tzv % _xv, tzv % _yv, tzv % _zv);
|
||||
Matrix3 oomat(row1,row2,row3,Point3(0,0,0));
|
||||
Quat ooquat(oomat);
|
||||
_bone = (SimpleObject2*)CreateInstance(GEOMOBJECT_CLASS_ID, BONE_OBJ_CLASSID);
|
||||
_node = (MaxEggImporter::_ip)->CreateObjectNode(_bone);
|
||||
_node->SetNodeTM(0, Matrix3(_xv, _yv, _zv, _pos));
|
||||
IParamBlock2 *blk = _bone->pblock2;
|
||||
for (int i=0; i<blk->NumParams(); i++) {
|
||||
TSTR n = blk->GetLocalName(i);
|
||||
if (strcmp(n, "Length")==0) blk->SetValue(i,0,(float)len);
|
||||
else if (strcmp(n, "Width")==0) blk->SetValue(i,0,(float)_thickness);
|
||||
else if (strcmp(n, "Height")==0) blk->SetValue(i,0,(float)_thickness);
|
||||
}
|
||||
Point3 boneColor = GetUIColor(COLOR_BONES);
|
||||
_node->SetWireColor(RGB(int(boneColor.x*255.0f), int(boneColor.y*255.0f), int(boneColor.z*255.0f) ));
|
||||
_node->SetBoneNodeOnOff(TRUE, 0);
|
||||
_node->SetRenderable(FALSE);
|
||||
_node->SetName((TCHAR*)(_egg_joint->get_name().c_str()));
|
||||
_node->SetObjOffsetRot(ooquat);
|
||||
if (_parent) {
|
||||
_node->Detach(0, 1);
|
||||
_parent->_node->AttachChild(_node, 1);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// MaxEggMesh
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef pair<double, EggGroup *> MaxEggWeight;
|
||||
|
||||
struct MaxEggVertex
|
||||
{
|
||||
Vertexd _pos;
|
||||
Normald _normal;
|
||||
vector<MaxEggWeight> _weights;
|
||||
int _index;
|
||||
};
|
||||
|
||||
struct MEV_Compare: public stl_hash_compare<MaxEggVertex>
|
||||
{
|
||||
size_t operator()(const MaxEggVertex &key) const
|
||||
{
|
||||
return key._pos.add_hash(key._normal.get_hash());
|
||||
}
|
||||
bool operator()(const MaxEggVertex &k1, const MaxEggVertex &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 (int i=0; i<k1._weights.size(); i++) {
|
||||
double d = k1._weights[i].first - k2._weights[i].first;
|
||||
if (d < 0) return true;
|
||||
if (d > 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;
|
||||
}
|
||||
};
|
||||
|
||||
class MaxEggMesh
|
||||
{
|
||||
public:
|
||||
|
||||
MaxEggImporter *_importer;
|
||||
string _name;
|
||||
TriObject *_obj;
|
||||
Mesh *_mesh;
|
||||
INode *_node;
|
||||
IDerivedObject *_dobj;
|
||||
Modifier *_skin_mod;
|
||||
ISkin *_iskin;
|
||||
ISkinImportData *_iskin_import;
|
||||
int _vert_count;
|
||||
int _tvert_count;
|
||||
int _cvert_count;
|
||||
int _face_count;
|
||||
|
||||
typedef phash_set<MaxEggVertex, MEV_Compare> VertTable;
|
||||
typedef phash_map<TexCoordd, int> TVertTable;
|
||||
typedef phash_map<Colorf, int> CVertTable;
|
||||
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, int tex);
|
||||
EggGroup *GetControlJoint(void);
|
||||
void CreateSkinModifier(void);
|
||||
};
|
||||
|
||||
#define CTRLJOINT_DEFORM ((EggGroup*)((char*)(-1)))
|
||||
|
||||
int MaxEggMesh::GetVert(EggVertex *vert, EggGroup *context)
|
||||
{
|
||||
MaxEggVertex 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(MaxEggWeight(membership, egg_joint));
|
||||
}
|
||||
if (vtx._weights.size()==0) {
|
||||
if (context != 0)
|
||||
vtx._weights.push_back(MaxEggWeight(1.0, context));
|
||||
}
|
||||
|
||||
VertTable::const_iterator vti = _vert_tab.find(vtx);
|
||||
if (vti != _vert_tab.end())
|
||||
return vti->_index;
|
||||
|
||||
if (_vert_count == _mesh->numVerts) {
|
||||
int nsize = _vert_count*2 + 100;
|
||||
_mesh->setNumVerts(nsize, _vert_count?TRUE:FALSE);
|
||||
}
|
||||
vtx._index = _vert_count++;
|
||||
_vert_tab.insert(vtx);
|
||||
_mesh->setVert(vtx._index, vtx._pos.get_x(), vtx._pos.get_y(), vtx._pos.get_z());
|
||||
return vtx._index;
|
||||
}
|
||||
|
||||
int MaxEggMesh::GetTVert(TexCoordd uv)
|
||||
{
|
||||
if (_tvert_tab.count(uv))
|
||||
return _tvert_tab[uv];
|
||||
if (_tvert_count == _mesh->numTVerts) {
|
||||
int nsize = _tvert_count*2 + 100;
|
||||
_mesh->setNumTVerts(nsize, _tvert_count?TRUE:FALSE);
|
||||
}
|
||||
int idx = _tvert_count++;
|
||||
_mesh->setTVert(idx, uv.get_x(), uv.get_y(), 0.0);
|
||||
_tvert_tab[uv] = idx;
|
||||
return idx;
|
||||
}
|
||||
|
||||
int MaxEggMesh::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;
|
||||
}
|
||||
|
||||
MaxEggMesh *MaxEggImporter::GetMesh(EggVertexPool *pool)
|
||||
{
|
||||
MaxEggMesh *result = _mesh_tab[pool];
|
||||
if (result == 0) {
|
||||
string name = pool->get_name();
|
||||
int nsize = name.size();
|
||||
if ((nsize > 6) && (name.rfind(".verts")==(nsize-6)))
|
||||
name.resize(nsize-6);
|
||||
result = new MaxEggMesh;
|
||||
result->_importer = this;
|
||||
result->_name = name;
|
||||
result->_obj = CreateNewTriObject();
|
||||
result->_mesh = &result->_obj->GetMesh();
|
||||
result->_mesh->setMapSupport(0, TRUE);
|
||||
result->_node = _ip->CreateObjectNode(result->_obj);
|
||||
result->_dobj = 0;
|
||||
result->_skin_mod = 0;
|
||||
result->_iskin = 0;
|
||||
result->_iskin_import = 0;
|
||||
result->_vert_count = 0;
|
||||
result->_tvert_count = 0;
|
||||
result->_cvert_count = 0;
|
||||
result->_face_count = 0;
|
||||
result->_node->SetName((TCHAR*)(name.c_str()));
|
||||
_mesh_tab[pool] = result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int MaxEggMesh::AddFace(int v0, int v1, int v2, int tv0, int tv1, int tv2, int cv0, int cv1, int cv2, int tex)
|
||||
{
|
||||
static int dump = 0;
|
||||
if (_face_count == _mesh->numFaces) {
|
||||
int nsize = _face_count*2 + 100;
|
||||
BOOL keep = _mesh->numFaces ? TRUE:FALSE;
|
||||
_mesh->setNumFaces(nsize, keep);
|
||||
_mesh->setNumTVFaces(nsize, keep, _face_count);
|
||||
_mesh->setNumVCFaces(nsize, keep, _face_count);
|
||||
}
|
||||
int idx = _face_count++;
|
||||
_mesh->faces[idx].setVerts(v0,v1,v2);
|
||||
_mesh->faces[idx].smGroup = 1;
|
||||
_mesh->faces[idx].flags = EDGE_ALL | HAS_TVERTS;
|
||||
_mesh->faces[idx].setMatID(tex);
|
||||
_mesh->tvFace[idx].setTVerts(tv0,tv1,tv2);
|
||||
_mesh->vcFace[idx].setTVerts(cv0,cv1,cv2);
|
||||
return idx;
|
||||
}
|
||||
|
||||
EggGroup *MaxEggMesh::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 MaxEggMesh::CreateSkinModifier(void)
|
||||
{
|
||||
vector <MaxEggJoint *> joints;
|
||||
|
||||
_dobj = CreateDerivedObject(_obj);
|
||||
_node->SetObjectRef(_dobj);
|
||||
_skin_mod = (Modifier*)CreateInstance(OSM_CLASS_ID, SKIN_CLASSID);
|
||||
_iskin = (ISkin*)_skin_mod->GetInterface(I_SKIN);
|
||||
_iskin_import = (ISkinImportData*)_skin_mod->GetInterface(I_SKINIMPORTDATA);
|
||||
_dobj->SetAFlag(A_LOCK_TARGET);
|
||||
_dobj->AddModifier(_skin_mod);
|
||||
_dobj->ClearAFlag(A_LOCK_TARGET);
|
||||
GetCOREInterface()->ForceCompleteRedraw();
|
||||
|
||||
VertTable::const_iterator vert;
|
||||
for (vert=_vert_tab.begin(); vert != _vert_tab.end(); ++vert) {
|
||||
for (int i=0; i<vert->_weights.size(); i++) {
|
||||
double strength = vert->_weights[i].first;
|
||||
MaxEggJoint *joint = _importer->FindJoint(vert->_weights[i].second);
|
||||
if (!joint->_inskin) {
|
||||
joint->_inskin = true;
|
||||
joints.push_back(joint);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i=0; i<joints.size(); i++) {
|
||||
BOOL last = (i == (joints.size()-1)) ? TRUE : FALSE;
|
||||
_iskin_import->AddBoneEx(joints[i]->_node, last);
|
||||
joints[i]->_inskin = false;
|
||||
}
|
||||
|
||||
_importer->_ip->SetCommandPanelTaskMode(TASK_MODE_MODIFY);
|
||||
_importer->_ip->SelectNode(_node);
|
||||
GetCOREInterface()->ForceCompleteRedraw();
|
||||
|
||||
for (vert=_vert_tab.begin(); vert != _vert_tab.end(); ++vert) {
|
||||
Tab<INode*> maxJoints;
|
||||
Tab<float> maxWeights;
|
||||
maxJoints.ZeroCount();
|
||||
maxWeights.ZeroCount();
|
||||
for (int i=0; i<vert->_weights.size(); i++) {
|
||||
float strength = (float)(vert->_weights[i].first);
|
||||
MaxEggJoint *joint = _importer->FindJoint(vert->_weights[i].second);
|
||||
maxWeights.Append(1,&strength);
|
||||
maxJoints.Append(1,&(joint->_node));
|
||||
}
|
||||
_iskin_import->AddWeights(_node, vert->_index, maxJoints, maxWeights);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TraverseEggData
|
||||
//
|
||||
// We have an EggData in memory, and now we're going to copy that
|
||||
// over into the max scene graph.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void MaxEggImporter::TraverseEggNode(EggNode *node, EggGroup *context)
|
||||
{
|
||||
vector<int> vertIndices;
|
||||
vector<int> tvertIndices;
|
||||
vector<int> cvertIndices;
|
||||
|
||||
if (node->is_of_type(EggPolygon::get_class_type())) {
|
||||
EggPolygon *poly = DCAST(EggPolygon, node);
|
||||
|
||||
int texid;
|
||||
LMatrix3d uvtrans = LMatrix3d::ident_mat();
|
||||
if (poly->has_texture()) {
|
||||
EggTexture *tex = poly->get_texture(0);
|
||||
texid = GetTex(tex->get_fullpath().to_os_specific())->_id;
|
||||
if (tex->has_transform())
|
||||
uvtrans = tex->get_transform();
|
||||
} else {
|
||||
texid = GetTex("")->_id;
|
||||
}
|
||||
|
||||
EggPolygon::const_iterator ci;
|
||||
MaxEggMesh *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 (int i=1; i<vertIndices.size()-1; i++)
|
||||
mesh->AddFace(vertIndices[0], vertIndices[i], vertIndices[i+1],
|
||||
tvertIndices[0], tvertIndices[i], tvertIndices[i+1],
|
||||
cvertIndices[0], cvertIndices[i], cvertIndices[i+1],
|
||||
texid);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MaxEggImporter::TraverseEggData(EggData *data)
|
||||
{
|
||||
MeshIterator ci;
|
||||
JointIterator ji;
|
||||
TexIterator ti;
|
||||
lgfile = fopen("MaxEggImporter.log","w");
|
||||
|
||||
SuspendAnimate();
|
||||
SuspendSetKeyMode();
|
||||
AnimateOff();
|
||||
_next_tex = 0;
|
||||
|
||||
TraverseEggNode(data, NULL);
|
||||
|
||||
for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) {
|
||||
MaxEggMesh *mesh = (*ci);
|
||||
mesh->_mesh->setNumVerts(mesh->_vert_count, TRUE);
|
||||
mesh->_mesh->setNumTVerts(mesh->_tvert_count, TRUE);
|
||||
mesh->_mesh->setNumVertCol(mesh->_cvert_count, TRUE);
|
||||
mesh->_mesh->setNumFaces(mesh->_face_count, TRUE);
|
||||
mesh->_mesh->setNumTVFaces(mesh->_face_count, TRUE, mesh->_face_count);
|
||||
mesh->_mesh->setNumVCFaces(mesh->_face_count, TRUE, mesh->_face_count);
|
||||
mesh->_mesh->InvalidateTopologyCache();
|
||||
mesh->_mesh->InvalidateGeomCache();
|
||||
mesh->_mesh->buildNormals();
|
||||
}
|
||||
|
||||
double thickness = 0.0;
|
||||
for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) {
|
||||
double dfo = ((*ji)->_pos).Length();
|
||||
if (dfo > thickness) thickness = dfo;
|
||||
}
|
||||
thickness = thickness * 0.025;
|
||||
for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) {
|
||||
MaxEggJoint *joint = *ji;
|
||||
joint->ChooseEndPos(thickness);
|
||||
joint->CreateMaxBone();
|
||||
}
|
||||
|
||||
for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) {
|
||||
MaxEggMesh *mesh = (*ci);
|
||||
EggGroup *joint = mesh->GetControlJoint();
|
||||
if (joint) mesh->CreateSkinModifier();
|
||||
}
|
||||
|
||||
if (_next_tex) {
|
||||
TSTR name;
|
||||
MultiMtl *mtl = NewDefaultMultiMtl();
|
||||
mtl->SetNumSubMtls(_next_tex);
|
||||
for (ti = _tex_tab.begin(); ti != _tex_tab.end(); ++ti) {
|
||||
MaxEggTex *tex = *ti;
|
||||
mtl->SetSubMtlAndName(tex->_id, tex->_mat, name);
|
||||
}
|
||||
for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) {
|
||||
MaxEggMesh *mesh = *ci;
|
||||
mesh->_node->SetMtl(mtl);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (lgfile) fclose(lgfile);
|
||||
|
||||
ResumeSetKeyMode();
|
||||
ResumeAnimate();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Plugin Initialization
|
||||
|
|
|
|||
|
|
@ -0,0 +1,712 @@
|
|||
// Filename: maxEggImport.cxx
|
||||
// Created by: jyelon (15Jul05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 MaxEggLoader. This class
|
||||
// does the actual work of copying an EggData tree into the max 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 <stdio.h>
|
||||
#include "Max.h"
|
||||
#include "maxImportRes.h"
|
||||
#include "istdplug.h"
|
||||
#include "stdmat.h"
|
||||
#include "decomp.h"
|
||||
#include "shape.h"
|
||||
#include "simpobj.h"
|
||||
#include "iparamb2.h"
|
||||
#include "iskin.h"
|
||||
#include "modstack.h"
|
||||
|
||||
#include "maxEggLoader.h"
|
||||
|
||||
class MaxEggMesh;
|
||||
class MaxEggJoint;
|
||||
class MaxEggTex;
|
||||
|
||||
NotifyCategoryDeclNoExport(maxloader);
|
||||
NotifyCategoryDef(maxloader, "");
|
||||
|
||||
class MaxEggLoader
|
||||
{
|
||||
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);
|
||||
MaxEggMesh *GetMesh(EggVertexPool *pool);
|
||||
MaxEggJoint *FindJoint(EggGroup *joint);
|
||||
MaxEggJoint *MakeJoint(EggGroup *joint, EggGroup *context);
|
||||
MaxEggTex *GetTex(const string &fn);
|
||||
void CreateSkinModifier(MaxEggMesh *M);
|
||||
|
||||
typedef phash_map<EggVertexPool *, MaxEggMesh *> MeshTable;
|
||||
typedef second_of_pair_iterator<MeshTable::const_iterator> MeshIterator;
|
||||
typedef phash_map<EggGroup *, MaxEggJoint *> JointTable;
|
||||
typedef second_of_pair_iterator<JointTable::const_iterator> JointIterator;
|
||||
typedef phash_map<string, MaxEggTex *> TexTable;
|
||||
typedef second_of_pair_iterator<TexTable::const_iterator> TexIterator;
|
||||
|
||||
MeshTable _mesh_tab;
|
||||
JointTable _joint_tab;
|
||||
TexTable _tex_tab;
|
||||
int _next_tex;
|
||||
};
|
||||
|
||||
static FILE *lgfile;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// MaxEggTex
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class MaxEggTex
|
||||
{
|
||||
public:
|
||||
string _path;
|
||||
int _id;
|
||||
StdMat *_mat;
|
||||
BitmapTex *_bmt;
|
||||
};
|
||||
|
||||
MaxEggTex *MaxEggLoader::GetTex(const string &fn)
|
||||
{
|
||||
if (_tex_tab.count(fn))
|
||||
return _tex_tab[fn];
|
||||
|
||||
BitmapTex *bmt = NewDefaultBitmapTex();
|
||||
bmt->SetMapName((TCHAR*)(fn.c_str()));
|
||||
StdMat *mat = NewDefaultStdMat();
|
||||
mat->SetSubTexmap(ID_DI, bmt);
|
||||
mat->SetTexmapAmt(ID_DI, 1.0, 0);
|
||||
mat->EnableMap(ID_DI, TRUE);
|
||||
mat->SetActiveTexmap(bmt);
|
||||
GetCOREInterface()->ActivateTexture(bmt, mat);
|
||||
|
||||
MaxEggTex *res = new MaxEggTex;
|
||||
res->_path = fn;
|
||||
res->_id = _next_tex ++;
|
||||
res->_bmt = bmt;
|
||||
res->_mat = mat;
|
||||
|
||||
_tex_tab[fn] = res;
|
||||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// MaxEggJoint
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class MaxEggJoint
|
||||
{
|
||||
public:
|
||||
Point3 _xv,_yv,_zv;
|
||||
Point3 _pos;
|
||||
Point3 _endpos;
|
||||
Point3 _zaxis;
|
||||
double _thickness;
|
||||
bool _inskin;
|
||||
SimpleObject2 *_bone;
|
||||
INode *_node;
|
||||
EggGroup *_egg_joint;
|
||||
MaxEggJoint *_parent;
|
||||
vector <MaxEggJoint *> _children;
|
||||
|
||||
public:
|
||||
MaxEggJoint *ChooseBestChild(Point3 dir);
|
||||
void ChooseEndPos(double thickness);
|
||||
void CreateMaxBone(void);
|
||||
};
|
||||
|
||||
MaxEggJoint *MaxEggLoader::FindJoint(EggGroup *joint)
|
||||
{
|
||||
if (joint==0) return 0;
|
||||
return _joint_tab[joint];
|
||||
}
|
||||
|
||||
MaxEggJoint *MaxEggLoader::MakeJoint(EggGroup *joint, EggGroup *context)
|
||||
{
|
||||
MaxEggJoint *parent = FindJoint(context);
|
||||
MaxEggJoint *result = new MaxEggJoint;
|
||||
LMatrix4d t = joint->get_transform();
|
||||
if (parent) {
|
||||
result->_xv = parent->_xv*((float)t(0,0)) + parent->_yv*((float)t(0,1)) + parent->_zv*((float)t(0,2));
|
||||
result->_yv = parent->_xv*((float)t(1,0)) + parent->_yv*((float)t(1,1)) + parent->_zv*((float)t(1,2));
|
||||
result->_zv = parent->_xv*((float)t(2,0)) + parent->_yv*((float)t(2,1)) + parent->_zv*((float)t(2,2));
|
||||
result->_pos = parent->_xv*((float)t(3,0)) + parent->_yv*((float)t(3,1)) + parent->_zv*((float)t(3,2)) + parent->_pos;
|
||||
} else {
|
||||
result->_xv = Point3(((float)t(0,0)), ((float)t(0,1)), ((float)t(0,2)));
|
||||
result->_yv = Point3(((float)t(1,0)), ((float)t(1,1)), ((float)t(1,2)));
|
||||
result->_zv = Point3(((float)t(2,0)), ((float)t(2,1)), ((float)t(2,2)));
|
||||
result->_pos = Point3(((float)t(3,0)), ((float)t(3,1)), ((float)t(3,2)));
|
||||
}
|
||||
result->_endpos = Point3(0,0,0);
|
||||
result->_zaxis = Point3(0,0,0);
|
||||
result->_thickness = 0.0;
|
||||
result->_inskin = false;
|
||||
result->_bone = 0;
|
||||
result->_node = 0;
|
||||
result->_egg_joint = joint;
|
||||
result->_parent = parent;
|
||||
if (parent) parent->_children.push_back(result);
|
||||
_joint_tab[joint] = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
MaxEggJoint *MaxEggJoint::ChooseBestChild(Point3 dir)
|
||||
{
|
||||
if (dir.Length() < 0.001) return 0;
|
||||
dir = dir.Normalize();
|
||||
double firstbest = -1000;
|
||||
MaxEggJoint *firstchild = 0;
|
||||
Point3 firstpos = _pos;
|
||||
double secondbest = 0;
|
||||
for (int i=0; i<_children.size(); i++) {
|
||||
MaxEggJoint *child = _children[i];
|
||||
Point3 tryfwd = child->_pos - _pos;
|
||||
if ((child->_pos != firstpos) && (tryfwd.Length() > 0.001)) {
|
||||
Point3 trydir = tryfwd.Normalize();
|
||||
double quality = trydir % dir;
|
||||
if (quality > firstbest) {
|
||||
secondbest = firstbest;
|
||||
firstbest = quality;
|
||||
firstpos = child->_pos;
|
||||
firstchild = child;
|
||||
} else if (quality > secondbest) {
|
||||
secondbest = quality;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (firstbest > secondbest + 0.1)
|
||||
return firstchild;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MaxEggJoint::ChooseEndPos(double thickness)
|
||||
{
|
||||
Point3 parentpos(0,0,0);
|
||||
Point3 parentendpos(0,0,1);
|
||||
if (_parent) {
|
||||
parentpos = _parent->_pos;
|
||||
parentendpos = _parent->_endpos;
|
||||
}
|
||||
Point3 fwd = _pos - parentpos;
|
||||
if (fwd.Length() < 0.001) {
|
||||
fwd = parentendpos - parentpos;
|
||||
}
|
||||
fwd = fwd.Normalize();
|
||||
MaxEggJoint *child = ChooseBestChild(fwd);
|
||||
if (child == 0) {
|
||||
_endpos = fwd * ((float)(thickness * 0.8)) + _pos;
|
||||
_thickness = thickness * 0.8;
|
||||
} else {
|
||||
_endpos = child->_pos;
|
||||
_thickness = (_endpos - _pos).Length();
|
||||
if (_thickness > thickness) _thickness = thickness;
|
||||
}
|
||||
Point3 orient = (_endpos - _pos).Normalize();
|
||||
Point3 altaxis = orient ^ Point3(0,-1,0);
|
||||
if (altaxis.Length() < 0.001) altaxis = orient ^ Point3(0,0,1);
|
||||
_zaxis = (altaxis ^ orient).Normalize();
|
||||
}
|
||||
|
||||
void MaxEggJoint::CreateMaxBone(void)
|
||||
{
|
||||
Point3 fwd = _endpos - _pos;
|
||||
double len = fwd.Length();
|
||||
Point3 txv = fwd * ((float)(1.0/len));
|
||||
Point3 tzv = _zaxis;
|
||||
Point3 tyv = tzv ^ txv;
|
||||
Point3 row1 = Point3(txv % _xv, txv % _yv, txv % _zv);
|
||||
Point3 row2 = Point3(tyv % _xv, tyv % _yv, tyv % _zv);
|
||||
Point3 row3 = Point3(tzv % _xv, tzv % _yv, tzv % _zv);
|
||||
Matrix3 oomat(row1,row2,row3,Point3(0,0,0));
|
||||
Quat ooquat(oomat);
|
||||
_bone = (SimpleObject2*)CreateInstance(GEOMOBJECT_CLASS_ID, BONE_OBJ_CLASSID);
|
||||
_node = GetCOREInterface()->CreateObjectNode(_bone);
|
||||
_node->SetNodeTM(0, Matrix3(_xv, _yv, _zv, _pos));
|
||||
IParamBlock2 *blk = _bone->pblock2;
|
||||
for (int i=0; i<blk->NumParams(); i++) {
|
||||
TSTR n = blk->GetLocalName(i);
|
||||
if (strcmp(n, "Length")==0) blk->SetValue(i,0,(float)len);
|
||||
else if (strcmp(n, "Width")==0) blk->SetValue(i,0,(float)_thickness);
|
||||
else if (strcmp(n, "Height")==0) blk->SetValue(i,0,(float)_thickness);
|
||||
}
|
||||
Point3 boneColor = GetUIColor(COLOR_BONES);
|
||||
_node->SetWireColor(RGB(int(boneColor.x*255.0f), int(boneColor.y*255.0f), int(boneColor.z*255.0f) ));
|
||||
_node->SetBoneNodeOnOff(TRUE, 0);
|
||||
_node->SetRenderable(FALSE);
|
||||
_node->SetName((TCHAR*)(_egg_joint->get_name().c_str()));
|
||||
_node->SetObjOffsetRot(ooquat);
|
||||
if (_parent) {
|
||||
_node->Detach(0, 1);
|
||||
_parent->_node->AttachChild(_node, 1);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// MaxEggMesh
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef pair<double, EggGroup *> MaxEggWeight;
|
||||
|
||||
struct MaxEggVertex
|
||||
{
|
||||
Vertexd _pos;
|
||||
Normald _normal;
|
||||
vector<MaxEggWeight> _weights;
|
||||
int _index;
|
||||
};
|
||||
|
||||
struct MEV_Compare: public stl_hash_compare<MaxEggVertex>
|
||||
{
|
||||
size_t operator()(const MaxEggVertex &key) const
|
||||
{
|
||||
return key._pos.add_hash(key._normal.get_hash());
|
||||
}
|
||||
bool operator()(const MaxEggVertex &k1, const MaxEggVertex &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 (int i=0; i<k1._weights.size(); i++) {
|
||||
double d = k1._weights[i].first - k2._weights[i].first;
|
||||
if (d < 0) return true;
|
||||
if (d > 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<MaxEggVertex, MEV_Compare> VertTable;
|
||||
typedef phash_map<TexCoordd, int> TVertTable;
|
||||
typedef phash_map<Colorf, int> CVertTable;
|
||||
|
||||
class MaxEggMesh
|
||||
{
|
||||
public:
|
||||
|
||||
string _name;
|
||||
TriObject *_obj;
|
||||
Mesh *_mesh;
|
||||
INode *_node;
|
||||
IDerivedObject *_dobj;
|
||||
Modifier *_skin_mod;
|
||||
ISkin *_iskin;
|
||||
ISkinImportData *_iskin_import;
|
||||
int _vert_count;
|
||||
int _tvert_count;
|
||||
int _cvert_count;
|
||||
int _face_count;
|
||||
|
||||
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, int tex);
|
||||
EggGroup *GetControlJoint(void);
|
||||
};
|
||||
|
||||
#define CTRLJOINT_DEFORM ((EggGroup*)((char*)(-1)))
|
||||
|
||||
int MaxEggMesh::GetVert(EggVertex *vert, EggGroup *context)
|
||||
{
|
||||
MaxEggVertex 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(MaxEggWeight(membership, egg_joint));
|
||||
}
|
||||
if (vtx._weights.size()==0) {
|
||||
if (context != 0)
|
||||
vtx._weights.push_back(MaxEggWeight(1.0, context));
|
||||
}
|
||||
|
||||
VertTable::const_iterator vti = _vert_tab.find(vtx);
|
||||
if (vti != _vert_tab.end())
|
||||
return vti->_index;
|
||||
|
||||
if (_vert_count == _mesh->numVerts) {
|
||||
int nsize = _vert_count*2 + 100;
|
||||
_mesh->setNumVerts(nsize, _vert_count?TRUE:FALSE);
|
||||
}
|
||||
vtx._index = _vert_count++;
|
||||
_vert_tab.insert(vtx);
|
||||
_mesh->setVert(vtx._index, vtx._pos.get_x(), vtx._pos.get_y(), vtx._pos.get_z());
|
||||
return vtx._index;
|
||||
}
|
||||
|
||||
int MaxEggMesh::GetTVert(TexCoordd uv)
|
||||
{
|
||||
if (_tvert_tab.count(uv))
|
||||
return _tvert_tab[uv];
|
||||
if (_tvert_count == _mesh->numTVerts) {
|
||||
int nsize = _tvert_count*2 + 100;
|
||||
_mesh->setNumTVerts(nsize, _tvert_count?TRUE:FALSE);
|
||||
}
|
||||
int idx = _tvert_count++;
|
||||
_mesh->setTVert(idx, uv.get_x(), uv.get_y(), 0.0);
|
||||
_tvert_tab[uv] = idx;
|
||||
return idx;
|
||||
}
|
||||
|
||||
int MaxEggMesh::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;
|
||||
}
|
||||
|
||||
MaxEggMesh *MaxEggLoader::GetMesh(EggVertexPool *pool)
|
||||
{
|
||||
MaxEggMesh *result = _mesh_tab[pool];
|
||||
if (result == 0) {
|
||||
string name = pool->get_name();
|
||||
int nsize = name.size();
|
||||
if ((nsize > 6) && (name.rfind(".verts")==(nsize-6)))
|
||||
name.resize(nsize-6);
|
||||
result = new MaxEggMesh;
|
||||
result->_name = name;
|
||||
result->_obj = CreateNewTriObject();
|
||||
result->_mesh = &result->_obj->GetMesh();
|
||||
result->_mesh->setMapSupport(0, TRUE);
|
||||
result->_node = GetCOREInterface()->CreateObjectNode(result->_obj);
|
||||
result->_dobj = 0;
|
||||
result->_skin_mod = 0;
|
||||
result->_iskin = 0;
|
||||
result->_iskin_import = 0;
|
||||
result->_vert_count = 0;
|
||||
result->_tvert_count = 0;
|
||||
result->_cvert_count = 0;
|
||||
result->_face_count = 0;
|
||||
result->_node->SetName((TCHAR*)(name.c_str()));
|
||||
_mesh_tab[pool] = result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int MaxEggMesh::AddFace(int v0, int v1, int v2, int tv0, int tv1, int tv2, int cv0, int cv1, int cv2, int tex)
|
||||
{
|
||||
static int dump = 0;
|
||||
if (_face_count == _mesh->numFaces) {
|
||||
int nsize = _face_count*2 + 100;
|
||||
BOOL keep = _mesh->numFaces ? TRUE:FALSE;
|
||||
_mesh->setNumFaces(nsize, keep);
|
||||
_mesh->setNumTVFaces(nsize, keep, _face_count);
|
||||
_mesh->setNumVCFaces(nsize, keep, _face_count);
|
||||
}
|
||||
int idx = _face_count++;
|
||||
_mesh->faces[idx].setVerts(v0,v1,v2);
|
||||
_mesh->faces[idx].smGroup = 1;
|
||||
_mesh->faces[idx].flags = EDGE_ALL | HAS_TVERTS;
|
||||
_mesh->faces[idx].setMatID(tex);
|
||||
_mesh->tvFace[idx].setTVerts(tv0,tv1,tv2);
|
||||
_mesh->vcFace[idx].setTVerts(cv0,cv1,cv2);
|
||||
return idx;
|
||||
}
|
||||
|
||||
EggGroup *MaxEggMesh::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 MaxEggLoader::CreateSkinModifier(MaxEggMesh *M)
|
||||
{
|
||||
vector <MaxEggJoint *> joints;
|
||||
|
||||
M->_dobj = CreateDerivedObject(M->_obj);
|
||||
M->_node->SetObjectRef(M->_dobj);
|
||||
M->_skin_mod = (Modifier*)CreateInstance(OSM_CLASS_ID, SKIN_CLASSID);
|
||||
M->_iskin = (ISkin*)M->_skin_mod->GetInterface(I_SKIN);
|
||||
M->_iskin_import = (ISkinImportData*)M->_skin_mod->GetInterface(I_SKINIMPORTDATA);
|
||||
M->_dobj->SetAFlag(A_LOCK_TARGET);
|
||||
M->_dobj->AddModifier(M->_skin_mod);
|
||||
M->_dobj->ClearAFlag(A_LOCK_TARGET);
|
||||
GetCOREInterface()->ForceCompleteRedraw();
|
||||
|
||||
VertTable::const_iterator vert;
|
||||
for (vert=M->_vert_tab.begin(); vert != M->_vert_tab.end(); ++vert) {
|
||||
for (int i=0; i<vert->_weights.size(); i++) {
|
||||
double strength = vert->_weights[i].first;
|
||||
MaxEggJoint *joint = FindJoint(vert->_weights[i].second);
|
||||
if (!joint->_inskin) {
|
||||
joint->_inskin = true;
|
||||
joints.push_back(joint);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i=0; i<joints.size(); i++) {
|
||||
BOOL last = (i == (joints.size()-1)) ? TRUE : FALSE;
|
||||
M->_iskin_import->AddBoneEx(joints[i]->_node, last);
|
||||
joints[i]->_inskin = false;
|
||||
}
|
||||
|
||||
GetCOREInterface()->SetCommandPanelTaskMode(TASK_MODE_MODIFY);
|
||||
GetCOREInterface()->SelectNode(M->_node);
|
||||
GetCOREInterface()->ForceCompleteRedraw();
|
||||
|
||||
for (vert=M->_vert_tab.begin(); vert != M->_vert_tab.end(); ++vert) {
|
||||
Tab<INode*> maxJoints;
|
||||
Tab<float> maxWeights;
|
||||
maxJoints.ZeroCount();
|
||||
maxWeights.ZeroCount();
|
||||
for (int i=0; i<vert->_weights.size(); i++) {
|
||||
float strength = (float)(vert->_weights[i].first);
|
||||
MaxEggJoint *joint = FindJoint(vert->_weights[i].second);
|
||||
maxWeights.Append(1,&strength);
|
||||
maxJoints.Append(1,&(joint->_node));
|
||||
}
|
||||
M->_iskin_import->AddWeights(M->_node, vert->_index, maxJoints, maxWeights);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TraverseEggData
|
||||
//
|
||||
// We have an EggData in memory, and now we're going to copy that
|
||||
// over into the max scene graph.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void MaxEggLoader::TraverseEggNode(EggNode *node, EggGroup *context)
|
||||
{
|
||||
vector<int> vertIndices;
|
||||
vector<int> tvertIndices;
|
||||
vector<int> cvertIndices;
|
||||
|
||||
if (node->is_of_type(EggPolygon::get_class_type())) {
|
||||
EggPolygon *poly = DCAST(EggPolygon, node);
|
||||
|
||||
int texid;
|
||||
LMatrix3d uvtrans = LMatrix3d::ident_mat();
|
||||
if (poly->has_texture()) {
|
||||
EggTexture *tex = poly->get_texture(0);
|
||||
texid = GetTex(tex->get_fullpath().to_os_specific())->_id;
|
||||
if (tex->has_transform())
|
||||
uvtrans = tex->get_transform();
|
||||
} else {
|
||||
texid = GetTex("")->_id;
|
||||
}
|
||||
|
||||
EggPolygon::const_iterator ci;
|
||||
MaxEggMesh *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 (int i=1; i<vertIndices.size()-1; i++)
|
||||
mesh->AddFace(vertIndices[0], vertIndices[i], vertIndices[i+1],
|
||||
tvertIndices[0], tvertIndices[i], tvertIndices[i+1],
|
||||
cvertIndices[0], cvertIndices[i], cvertIndices[i+1],
|
||||
texid);
|
||||
} 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 MaxEggLoader::ConvertEggData(EggData *data, bool merge, bool model, bool anim)
|
||||
{
|
||||
if (!merge) {
|
||||
maxloader_cat.error() << "Currently, only 'merge' mode is implemented.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((anim) || (!model)) {
|
||||
maxloader_cat.error() << "Currently, only model-loading is implemented.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
MeshIterator ci;
|
||||
JointIterator ji;
|
||||
TexIterator ti;
|
||||
lgfile = fopen("MaxEggLoader.log","w");
|
||||
|
||||
SuspendAnimate();
|
||||
SuspendSetKeyMode();
|
||||
AnimateOff();
|
||||
_next_tex = 0;
|
||||
|
||||
TraverseEggNode(data, NULL);
|
||||
|
||||
for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) {
|
||||
MaxEggMesh *mesh = (*ci);
|
||||
mesh->_mesh->setNumVerts(mesh->_vert_count, TRUE);
|
||||
mesh->_mesh->setNumTVerts(mesh->_tvert_count, TRUE);
|
||||
mesh->_mesh->setNumVertCol(mesh->_cvert_count, TRUE);
|
||||
mesh->_mesh->setNumFaces(mesh->_face_count, TRUE);
|
||||
mesh->_mesh->setNumTVFaces(mesh->_face_count, TRUE, mesh->_face_count);
|
||||
mesh->_mesh->setNumVCFaces(mesh->_face_count, TRUE, mesh->_face_count);
|
||||
mesh->_mesh->InvalidateTopologyCache();
|
||||
mesh->_mesh->InvalidateGeomCache();
|
||||
mesh->_mesh->buildNormals();
|
||||
}
|
||||
|
||||
double thickness = 0.0;
|
||||
for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) {
|
||||
double dfo = ((*ji)->_pos).Length();
|
||||
if (dfo > thickness) thickness = dfo;
|
||||
}
|
||||
thickness = thickness * 0.025;
|
||||
for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) {
|
||||
MaxEggJoint *joint = *ji;
|
||||
joint->ChooseEndPos(thickness);
|
||||
joint->CreateMaxBone();
|
||||
}
|
||||
|
||||
for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) {
|
||||
MaxEggMesh *mesh = (*ci);
|
||||
EggGroup *joint = mesh->GetControlJoint();
|
||||
if (joint) CreateSkinModifier(mesh);
|
||||
}
|
||||
|
||||
if (_next_tex) {
|
||||
TSTR name;
|
||||
MultiMtl *mtl = NewDefaultMultiMtl();
|
||||
mtl->SetNumSubMtls(_next_tex);
|
||||
for (ti = _tex_tab.begin(); ti != _tex_tab.end(); ++ti) {
|
||||
MaxEggTex *tex = *ti;
|
||||
mtl->SetSubMtlAndName(tex->_id, tex->_mat, name);
|
||||
}
|
||||
for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) {
|
||||
MaxEggMesh *mesh = *ci;
|
||||
mesh->_node->SetMtl(mtl);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (lgfile) fclose(lgfile);
|
||||
|
||||
ResumeSetKeyMode();
|
||||
ResumeAnimate();
|
||||
|
||||
maxloader_cat.info() << "Egg import successful\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaxEggLoader::ConvertEggFile(const char *name, bool merge, bool model, bool anim)
|
||||
{
|
||||
EggData data;
|
||||
Filename datafn = Filename::from_os_specific(name);
|
||||
if (!data.read(datafn)) {
|
||||
maxloader_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 MaxLoadEggData(EggData *data, bool merge, bool model, bool anim)
|
||||
{
|
||||
MaxEggLoader loader;
|
||||
return loader.ConvertEggData(data, merge, model, anim);
|
||||
}
|
||||
|
||||
bool MaxLoadEggFile(const char *name, bool merge, bool model, bool anim)
|
||||
{
|
||||
MaxEggLoader loader;
|
||||
return loader.ConvertEggFile(name, merge, model, anim);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Filename: maxEggLoader.h
|
||||
// Created by: jyelon (15jul05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 MAXEGGLOADER_H
|
||||
#define MAXEGGLOADER_H
|
||||
|
||||
class EggData;
|
||||
|
||||
bool MaxLoadEggData(EggData *data, bool merge, bool model, bool anim);
|
||||
bool MaxLoadEggFile(const char *name, bool merge, bool model, bool anim);
|
||||
|
||||
#endif
|
||||
|
||||
Loading…
Reference in New Issue