1
0
forked from 0ad/0ad

Initial revision of 3DS MAX exporter for PMD and PSA files.

This was SVN commit r314.
This commit is contained in:
notpete 2004-05-29 21:10:50 +00:00
parent 52f5b707ee
commit 210d77c9b3
33 changed files with 3828 additions and 0 deletions

125
source/tools/pmdexp/DllEntry.cpp Executable file
View File

@ -0,0 +1,125 @@
/**********************************************************************
*<
FILE: DllEntry.cpp
DESCRIPTION: Contains the Dll Entry stuff
CREATED BY:
HISTORY:
*> Copyright (c) 2000, All Rights Reserved.
**********************************************************************/
#include "PMDExp.h"
#include "PSAExp.h"
#include "PSProp.h"
#include "MaxInc.h"
#define PMDEXP_CLASS_ID Class_ID(0x71d92656, 0x136330c5)
#define PSAEXP_CLASS_ID Class_ID(0x6cf86c73, 0x54e0844)
HINSTANCE hInstance;
static int controlsInit = FALSE;
TCHAR* GetString(int id)
{
static TCHAR buf[256];
if (hInstance) {
if (!LoadString(hInstance, id, buf, sizeof(buf))) {
return NULL;
}
return buf;
}
return NULL;
}
//////////////////////////////////////////////////////////////////////////////////////
// PMDExpClassDesc: required class to expose PMDExp to MAX
class PMDExpClassDesc : public ClassDesc2
{
public:
int IsPublic() { return TRUE; }
void * Create(BOOL loading = FALSE) { return new PMDExp(); }
const TCHAR * ClassName() { return GetString(IDS_PSA_CLASS_NAME); }
SClass_ID SuperClassID() { return SCENE_EXPORT_CLASS_ID; }
Class_ID ClassID() { return PMDEXP_CLASS_ID; }
const TCHAR* Category() { return GetString(IDS_CATEGORY); }
const TCHAR* InternalName() { return _T("PMDExp"); }
HINSTANCE HInstance() { return hInstance; }
};
static PMDExpClassDesc PMDExpDesc;
ClassDesc2* GetPMDExpDesc() { return &PMDExpDesc; }
//////////////////////////////////////////////////////////////////////////////////////
// PSAExpClassDesc: required class to expose PSAExp to MAX
class PSAExpClassDesc : public ClassDesc2
{
public:
int IsPublic() { return TRUE; }
void * Create(BOOL loading = FALSE) { return new PSAExp(); }
const TCHAR * ClassName() { return GetString(IDS_PSA_CLASS_NAME); }
SClass_ID SuperClassID() { return SCENE_EXPORT_CLASS_ID; }
Class_ID ClassID() { return PSAEXP_CLASS_ID; }
const TCHAR* Category() { return GetString(IDS_CATEGORY); }
const TCHAR* InternalName() { return _T("PSAExp"); }
HINSTANCE HInstance() { return hInstance; }
};
static PSAExpClassDesc PSAExpDesc;
ClassDesc2* GetPSAExpDesc() { return &PSAExpDesc; }
BOOL WINAPI DllMain(HINSTANCE hinstDLL,ULONG fdwReason,LPVOID lpvReserved)
{
hInstance = hinstDLL; // Hang on to this DLL's instance handle.
if (!controlsInit) {
controlsInit = TRUE;
InitCustomControls(hInstance); // Initialize MAX's custom controls
InitCommonControls(); // Initialize Win95 controls
}
return (TRUE);
}
__declspec(dllexport) const TCHAR* LibDescription()
{
return GetString(IDS_LIBDESCRIPTION);
}
__declspec(dllexport) int LibNumberClasses()
{
return 3;
}
__declspec(dllexport) ClassDesc* LibClassDesc(int i)
{
switch(i) {
case 0: return GetPMDExpDesc();
case 1: return GetPSAExpDesc();
case 2: return GetPSPropDesc();
default: return 0;
}
}
__declspec(dllexport) ULONG LibVersion()
{
return VERSION_3DSMAX;
}
__declspec( dllexport ) ULONG CanAutoDefer()
{
return 1;
}

463
source/tools/pmdexp/ExpMesh.cpp Executable file
View File

@ -0,0 +1,463 @@
#include "ExpMesh.h"
#include "ExpUtil.h"
#include "ExpSkeleton.h"
#include "VertexTree.h"
#include "VNormal.h"
#include "phyexp.h"
////////////////////////////////////////////////////////////////////////////////
// TMNegParity: return whether the given matrix has a negative scale or not
inline bool TMNegParity(Matrix3 &Mat)
{
return (DotProd(CrossProd(Mat.GetRow(0),Mat.GetRow(1)),Mat.GetRow(2)) < 0.0) ? 1 : 0;
}
////////////////////////////////////////////////////////////////////////////////
// GetTriObjectFromNode: return a pointer to a TriObject
// given an INode or return NULL if the node cannot be converted
// to a TriObject
static TriObject* GetTriObjectFromNode(INode* node,bool& deleteIt)
{
deleteIt = false;
Object* obj=node->EvalWorldState(0).obj;
if (obj) {
if (obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0))) {
TriObject *tri=(TriObject*) obj->ConvertToType(0,Class_ID(TRIOBJ_CLASS_ID,0));
// note that the TriObject should only be deleted if the pointer to it is
// not equal to the object pointer that called ConvertToType()
if (obj != tri) {
deleteIt = true;
}
return tri;
}
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// GetPhysiqueFromNode: return a pointer to a Physique modifier found
// in the modifier stack of the given INode, or return NULL is no Physique
// modifier can be found
static Modifier* GetPhysiqueFromNode(INode* node)
{
// Get object from node. Abort if no object.
Object* object=node->GetObjectRef();
if (!object) return 0;
// ss derived object?
if (object->SuperClassID()==GEN_DERIVOB_CLASS_ID) {
// yes -> cast
IDerivedObject* derivedObj=static_cast<IDerivedObject*>(object);
// iterate over all entries of the modifier stack
int modStackIndex=0;
while (modStackIndex<derivedObj->NumModifiers()) {
// get current modifier
Modifier* modifier=derivedObj->GetModifier(modStackIndex);
Class_ID clsid=modifier->ClassID();
// check if it's a Physique
if (modifier->ClassID()==Class_ID(PHYSIQUE_CLASS_ID_A, PHYSIQUE_CLASS_ID_B)) {
// yes -> return it
return modifier;
}
// advance to next modifier stack entry
modStackIndex++;
}
}
// not found ..
return 0;
}
PMDExpMesh::PMDExpMesh(INode* node,const ExpSkeleton* skeleton)
: m_Node(node), m_Skeleton(skeleton)
{
}
bool PMDExpMesh::IsMesh(Object* obj)
{
assert(obj);
if (obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0))) {
return true;
} else {
return false;
}
}
////////////////////////////////////////////////////////////////////////////////
// InsertBlend: insert the given bone/weight blend into the given blend set
void PMDExpMesh::InsertBlend(unsigned char bone,float weight,SVertexBlend& blend)
{
// get position where this blend should be inserted
int i=0;
while (weight<blend.m_Weight[i]) i++;
if (i>=SVertexBlend::SIZE) {
// all other blends carry greater weight; reject this blend
return;
}
for (int j=SVertexBlend::SIZE-2;j>=i;j--) {
blend.m_Bone[j+1]=blend.m_Bone[j];
blend.m_Weight[j+1]=blend.m_Weight[j];
}
blend.m_Bone[i]=bone;
blend.m_Weight[i]=weight;
}
void PMDExpMesh::BuildVertexBlends(Mesh& mesh,VBlendList& blends)
{
// allocate blends
int numVerts=mesh.getNumVerts();
blends.resize(mesh.getNumVerts());
// set all blends to null
for (int i=0;i<numVerts;i++) {
memset(blends[i].m_Bone,0xff,sizeof(blends[i].m_Bone));
memset(blends[i].m_Weight,0,sizeof(blends[i].m_Weight));
}
// query presence of physique modifier first
Modifier* physique=GetPhysiqueFromNode(m_Node);
if (!physique) {
// no Physique, no blends: no support for Skin at present
// LogError("No physique export");
return;
}
// get physique export interface
IPhysiqueExport *phyExport=(IPhysiqueExport*) physique->GetInterface(I_PHYINTERFACE);
if(phyExport) {
// get ModContext interface from export interface for this INode
IPhyContextExport *contextExport=(IPhyContextExport*) phyExport->GetContextInterface(m_Node);
if(contextExport) {
// export all the vertices as if they are rigid ..
contextExport->ConvertToRigid(TRUE);
// .. and disable blending
contextExport->AllowBlending(FALSE);
// check number of vertices assigned to physique matches mesh total
if (contextExport->GetNumberVertices()!=mesh.getNumVerts()) {
// LogError("vtx mismatch!\n");
return;
}
for (int i=0;i<numVerts;i++) {
SVertexBlend& blend=blends[i];
// get export interface for this vertex
IPhyVertexExport* vertexexport=contextExport->GetVertexInterface(i);
if (vertexexport) {
// get type of vertex
int type=vertexexport->GetVertexType();
if (type==RIGID_TYPE) {
IPhyRigidVertex* rigidVertex=(IPhyRigidVertex*) vertexexport;
// get attached bone
INode* boneNode=rigidVertex->GetNode();
if (boneNode) {
// store blend
blend.m_Bone[0]=m_Skeleton->FindBoneByNode(boneNode);
if (blend.m_Bone[0]==0xff) {
// LogError("Failed to find bonenode %s (0x%p)\n",boneNode->GetName(),boneNode);
}
blend.m_Weight[0]=1.0f;
}
} else {
// must be RIGID_BLENDED_TYPE vertex
IPhyBlendedRigidVertex* blendedVertex=(IPhyBlendedRigidVertex*) vertexexport;
// get number of nodes affecting vertex; clamp to SVertexBlend::SIZE
int numBones=blendedVertex->GetNumberNodes();
for (int boneindex=0;boneindex<numBones;boneindex++) {
// get weight of boneindex'th bone
float boneWeight=blendedVertex->GetWeight(boneindex);
if (boneWeight>0.001f) {
// get boneindex'th bone
INode* boneNode=blendedVertex->GetNode(boneindex);
// store blend - (need to check for prior bones using same bone?)
unsigned char bone=m_Skeleton->FindBoneByNode(boneNode);
if (bone==0xff) {
//LogError("Failed to find bonenode %s (0x%p)\n",boneNode->GetName(),boneNode);
} else {
InsertBlend(bone,boneWeight,blend);
}
}
}
#if 0
if (blend.m_Bone[0]==0xff) {
// ugh - all bones must have zero weight .. use the root bone with a weight of 1?
blend.m_Bone[0]=0;
blend.m_Weight[0]=1;
}
#else
if (blend.m_Bone[0]==0xff) {
// ugh - all bones must have zero weight .. try again and assign all bones equal weight
// TODO, RC 13/03/04 - log warning for this; most likely user error in enveloping/bone assignment
for (boneindex=0;boneindex<numBones;boneindex++) {
float boneWeight=1.0f;
// get boneindex'th bone
INode* boneNode=blendedVertex->GetNode(boneindex);
// store blend - (need to check for prior bones using same bone?)
unsigned char bone=m_Skeleton->FindBoneByNode(boneNode);
if (bone==0xff) {
//LogError("Failed to find bonenode %s (0x%p)\n",boneNode->GetName(),boneNode);
} else {
InsertBlend(bone,boneWeight,blend);
}
}
}
#endif
// normalise bone weights of this blend such that they sum to 1
int j;
float totalweight=0;
for (j=0;j<SVertexBlend::SIZE && blend.m_Bone[j]!=0xff;j++) {
totalweight+=blend.m_Weight[j];
}
for (j=0;j<SVertexBlend::SIZE && blend.m_Bone[j]!=0xff;j++) {
blend.m_Weight[j]/=totalweight;
}
}
// done with this vertex
contextExport->ReleaseVertexInterface(vertexexport);
} else {
//LogError("No vertexexport interface!\n");
}
}
} else {
//LogError("No contextexport interface!\n");
}
}
}
static CVector3D SkinVertex(const ExpSkeleton* skeleton,const CVector3D& pos,const SVertexBlend& blend)
{
CVector3D result(0,0,0);
for (int i=0;i<SVertexBlend::SIZE && blend.m_Bone[i]!=0xff;i++) {
const CMatrix3D& m=skeleton->m_Bones[blend.m_Bone[i]]->m_Transform;
CVector3D tmp=m.Transform(pos);
result+=tmp*blend.m_Weight[i];
}
return result;
}
static CVector3D SkinNormal(const ExpSkeleton* skeleton,const CVector3D& pos,const SVertexBlend& blend)
{
CMatrix3D minv,minvtrans;
CVector3D result(0,0,0);
for (int i=0;i<SVertexBlend::SIZE && blend.m_Bone[i]!=0xff;i++) {
const CMatrix3D& m=skeleton->m_Bones[blend.m_Bone[i]]->m_Transform;
m.GetInverse(minv);
minv.GetTranspose(minvtrans);
CVector3D tmp=minvtrans.Transform(pos);
result+=tmp*blend.m_Weight[i];
}
return result;
}
static CVector3D UnskinPoint(const ExpSkeleton* skeleton,const CVector3D& pos,const SVertexBlend& blend)
{
CMatrix3D m,minv;
m.SetZero();
for (int i=0;i<SVertexBlend::SIZE && blend.m_Bone[i]!=0xff;i++) {
const CMatrix3D& m2=skeleton->m_Bones[blend.m_Bone[i]]->m_Transform;
m+=m2*blend.m_Weight[i];
}
m.GetInverse(minv);
return minv.Transform(pos);
}
static CVector3D UnskinNormal(const ExpSkeleton* skeleton,const CVector3D& nrm,const SVertexBlend& blend)
{
CMatrix3D m,minv,minvtrans;
m.SetZero();
for (int i=0;i<SVertexBlend::SIZE && blend.m_Bone[i]!=0xff;i++) {
const CMatrix3D& m2=skeleton->m_Bones[blend.m_Bone[i]]->m_Transform;
m+=m2*blend.m_Weight[i];
}
m.GetInverse(minv);
minv.GetTranspose(minvtrans);
minvtrans.GetInverse(m);
return m.Rotate(nrm);
}
CVector3D* PMDExpMesh::BuildVertexPoints(Mesh& mesh,VBlendList& vblends)
{
// get transform to world space
Matrix3 tm=m_Node->GetObjectTM(0);
bool negScale=TMNegParity(tm);
int numverts=mesh.getNumVerts();
CVector3D* transPts=new CVector3D[numverts];
// transform each vertex and store in output array
for (int i=0;i<numverts;i++) {
Point3 maxpos=mesh.getVert(i)*tm;
transPts[i]=CVector3D(maxpos.x,maxpos.z,maxpos.y);
}
if (m_Skeleton) {
BuildVertexBlends(mesh,vblends);
for (i=0;i<numverts;i++) {
transPts[i]=UnskinPoint(m_Skeleton,transPts[i],vblends[i]);
}
}
return transPts;
}
VNormal* PMDExpMesh::BuildVertexNormals(Mesh& mesh,VBlendList& vblends)
{
// get transform to world space
Matrix3 tm=m_Node->GetObjectTM(0);
bool negScale=TMNegParity(tm);
// allocate basis vectors for dot product lighting
VNormal* vnormals=new VNormal[mesh.getNumVerts()];
for (u32 i=0;i<mesh.getNumFaces();++i) {
// build face normal
Point3 P0=mesh.getVert(mesh.faces[i].v[0])*tm;
Point3 P1=mesh.getVert(mesh.faces[i].v[1])*tm;
Point3 P2=mesh.getVert(mesh.faces[i].v[2])*tm;
Point3 e0=P1-P0;
Point3 e1=P2-P0;
Point3 faceNormal=e0^e1;
if (negScale) faceNormal*=-1;
CVector3D N(faceNormal.x,faceNormal.z,faceNormal.y);
N.Normalize();
// accumulate normal
vnormals[mesh.faces[i].v[0]].add(N,mesh.faces[i].smGroup);
vnormals[mesh.faces[i].v[1]].add(N,mesh.faces[i].smGroup);
vnormals[mesh.faces[i].v[2]].add(N,mesh.faces[i].smGroup);
}
for (i=0;i<mesh.getNumVerts();i++) {
if (m_Skeleton) {
VNormal* vnorm=&vnormals[i];
vnorm->normalize();
while (vnorm) {
vnorm->_normal=UnskinNormal(m_Skeleton,vnorm->_normal,vblends[i]);
vnorm=vnorm->next;
}
}
vnormals[i].normalize();
}
// .. and return them
return vnormals;
}
void PMDExpMesh::BuildVerticesAndFaces(Mesh& mesh,VertexList& vertices,CVector3D* vpoints,VBlendList& vblends,VNormal* vnormals,FaceList& faces)
{
// assume worst case and reserve enough space up front ..
u32 numFaces=mesh.getNumFaces();
vertices.reserve(numFaces*3);
// initialise outgoing face array
faces.resize(numFaces);
// create a vertex tree setup to fill unique vertices into outgoing array
VertexTree<UniqueVertexCmp> vtxtree(vertices);
// get transform to world space
Matrix3 tm=m_Node->GetObjectTM(0);
bool negScale=TMNegParity(tm);
// iterate through faces
for (u32 i=0;i<numFaces;++i) {
for (int k=0;k<3;++k) {
ExpVertex vtx;
vtx.m_Index=mesh.faces[i].v[k];
// get position
vtx.m_Pos=vpoints[vtx.m_Index];
// get UVs
if (mesh.getNumTVerts()) {
const TVFace& tvface=mesh.tvFace[i];
const UVVert& uv=mesh.getTVert(tvface.t[k]);
vtx.m_UVs[0]=uv.x;
vtx.m_UVs[1]=uv.y;
} else {
vtx.m_UVs[0]=0;
vtx.m_UVs[1]=0;
}
VNormal* vnrm=vnormals[mesh.faces[i].v[k]].get(mesh.faces[i].smGroup);
vtx.m_Normal=vnrm ? vnrm->_normal : CVector3D(0,0,0);
faces[i].m_V[k]=vtxtree.insert(vtx);
}
if (negScale) {
int t=faces[i].m_V[1];
faces[i].m_V[1]=faces[i].m_V[2];
faces[i].m_V[2]=t;
}
faces[i].m_MAXindex=i;
faces[i].m_Smooth=mesh.faces[i].smGroup;
}
}
ExpMesh* PMDExpMesh::Build()
{
// get mesh from node
bool delTriObj;
TriObject* triObj=GetTriObjectFromNode(m_Node,delTriObj);
Mesh& mesh=triObj->mesh;
ExpMesh* expmesh=new ExpMesh;
// build vertex positions/blends from given mesh data
CVector3D* vpoints=BuildVertexPoints(mesh,expmesh->m_Blends);
// build vertex normals from mesh data and vertex positions
VNormal* vnormals=BuildVertexNormals(mesh,expmesh->m_Blends);
// build face and vertex lists
BuildVerticesAndFaces(mesh,expmesh->m_Vertices,vpoints,expmesh->m_Blends,vnormals,expmesh->m_Faces);
// clean up ..
delete[] vnormals;
delete[] vpoints;
if (delTriObj) {
triObj->DeleteThis();
}
return expmesh;
}

81
source/tools/pmdexp/ExpMesh.h Executable file
View File

@ -0,0 +1,81 @@
#ifndef __EXPMESH_H
#define __EXPMESH_H
#include <vector>
#include "MaxInc.h"
#include "lib\types.h"
#include "Vector3D.h"
#include "ExpVertex.h"
class VNormal;
class ExpSkeleton;
////////////////////////////////////////////////////////////////////////
// ExpFace: face declaration used in building mesh geometry
struct ExpFace {
// vertex indices
u32 m_V[3];
// index of this face in max's face list (necessary, since extra
// faces may be created in fixing t-junctions, but it's still
// necessary to map back to MAX for eg. getting material on face)
u32 m_MAXindex;
// smoothing group
u32 m_Smooth;
// face normal
CVector3D m_Normal;
// face area
float m_Area;
};
// handy typedefs
typedef std::vector<u32> IndexList;
typedef std::vector<CVector3D> PointList;
typedef std::vector<ExpFace> FaceList;
typedef std::vector<ExpVertex> VertexList;
typedef std::vector<SVertexBlend> VBlendList;
////////////////////////////////////////////////////////////////////////
// ExpMesh: mesh type used in building mesh geometry
class ExpMesh
{
public:
// list of faces in mesh
FaceList m_Faces;
// list of vertices used by mesh
VertexList m_Vertices;
// list of vertex blends used by mesh
VBlendList m_Blends;
};
////////////////////////////////////////////////////////////////////////
// PMDExpMesh: class used for building output meshes
class PMDExpMesh
{
public:
PMDExpMesh(INode* node,const ExpSkeleton* skeleton);
static bool IsMesh(Object* obj);
ExpMesh* Build();
private:
// the node we're constructing the mesh from
INode* m_Node;
// the skeleton attached to the mesh, if any
const ExpSkeleton* m_Skeleton;
// construct list of vertices and faces used by mesh
void BuildVerticesAndFaces(Mesh& mesh,VertexList& vertices,CVector3D* vpoints,VBlendList& vblends,VNormal* vnormals,FaceList& faces);
// build and return vertex normals, accounting for smoothing groups
VNormal* BuildVertexNormals(Mesh& mesh,VBlendList& vblends);
// build and return vertex blends (determined by Physique), if any
void BuildVertexBlends(Mesh& mesh,VBlendList& blends);
// insert the given bone/weight blend into the given blend set
void InsertBlend(unsigned char bone,float weight,SVertexBlend& blend);
CVector3D* BuildVertexPoints(Mesh& mesh,VBlendList& vblends);
};
#endif

44
source/tools/pmdexp/ExpProp.cpp Executable file
View File

@ -0,0 +1,44 @@
#include "PSProp.h"
#include "ExpProp.h"
#include "ExpUtil.h"
#include "decomp.h"
PMDExpProp::PMDExpProp(INode* node) : m_Node(node)
{
}
bool PMDExpProp::IsProp(Object* obj)
{
return obj->ClassID()==PSPROP_CLASS_ID ? true : false;
}
ExpProp* PMDExpProp::Build()
{
ExpProp* prop=new ExpProp;
prop->m_Name=m_Node->GetName();
prop->m_Parent=m_Node->GetParentNode();
// build local transformation matrix
INode *parent;
Matrix3 parentTM, nodeTM, localTM;
nodeTM = m_Node->GetNodeTM(0);
parent = m_Node->GetParentNode();
parentTM = parent->GetNodeTM(0);
localTM = nodeTM*Inverse(parentTM);
// decompose it to get translation and rotation
AffineParts parts;
decomp_affine(localTM,&parts);
// get translation from affine parts
MAXtoGL(parts.t);
prop->m_Position=CVector3D(parts.t.x,parts.t.y,parts.t.z);
// get rotation from affine parts
prop->m_Rotation.m_V.X=parts.q.x;
prop->m_Rotation.m_V.Y=parts.q.z;
prop->m_Rotation.m_V.Z=parts.q.y;
prop->m_Rotation.m_W=parts.q.w;
return prop;
}

38
source/tools/pmdexp/ExpProp.h Executable file
View File

@ -0,0 +1,38 @@
#ifndef _EXPPROP_H
#define _EXPPROP_H
#include "CStr.h"
#include "Vector3D.h"
#include "Quaternion.h"
////////////////////////////////////////////////////////////////////////
// ExpProp: prop object used on export
class ExpProp
{
public:
// name of prop
CStr m_Name;
// position relative to parent
CVector3D m_Position;
// rotation relative to parent
CQuaternion m_Rotation;
// parent node
INode* m_Parent;
};
////////////////////////////////////////////////////////////////////////
// PMDExpProp: class used for building output props
class PMDExpProp
{
public:
PMDExpProp(INode* node);
static bool IsProp(Object* obj);
ExpProp* Build();
private:
// the node we're constructing the prop from
INode* m_Node;
};
#endif

View File

@ -0,0 +1,173 @@
#include "ExpSkeleton.h"
#include "ExpUtil.h"
#include "bipexp.h"
#include "decomp.h"
#include "ModelDef.h"
#include "SkeletonAnimDef.h"
/////////////////////////////////////////////////////////////////////////////////
// ExpSkeleton constructor
ExpSkeleton::ExpSkeleton()
{
}
/////////////////////////////////////////////////////////////////////////////////
// ExpSkeleton destructor
ExpSkeleton::~ExpSkeleton()
{
for (int i=0;i<m_Bones.size();i++) {
delete m_Bones[i];
}
}
/////////////////////////////////////////////////////////////////////////////////
// IsFootprints: return true if given node is biped footprints, else false
bool ExpSkeleton::IsFootprints(INode* node)
{
// get nodes transform control
Control* c=node->GetTMController();
// check classID for footprints
return (c && (c->ClassID()==FOOTPRINT_CLASS_ID)) ? true : false;
}
/////////////////////////////////////////////////////////////////////////////////
// IsBone: return true if given node is a skeletal biped bone, else false
bool ExpSkeleton::IsBone(INode* node)
{
// get nodes transform control
Control* c=node->GetTMController();
// check classID for either a root or a child bone
return (c && (c->ClassID()==BIPSLAVE_CONTROL_CLASS_ID || c->ClassID()==BIPBODY_CONTROL_CLASS_ID)) ? true : false;
}
/////////////////////////////////////////////////////////////////////////////////
// IsSkeleton: return true if given node is the root of a skeleton, else false
bool ExpSkeleton::IsSkeletonRoot(INode* node)
{
// get nodes transform control
Control* c=node->GetTMController();
// check for biped root
return (c && c->ClassID()==BIPBODY_CONTROL_CLASS_ID) ? true : false;
}
/////////////////////////////////////////////////////////////////////////////////
// BuildSkeletons: build all skeletons from given root node
void ExpSkeleton::BuildSkeletons(INode* node,std::vector<ExpSkeleton*>& skeletons)
{
if (IsSkeletonRoot(node)) {
// build skeleton from this node - Build traverses all children
// of given node
ExpSkeleton* skeleton=new ExpSkeleton;
skeleton->Build(node,0);
skeletons.push_back(skeleton);
} else {
// traverse into children as this object wasn't a skeleton root
for (int i=0;i<node->NumberOfChildren();i++) {
BuildSkeletons(node->GetChildNode(i),skeletons);
}
}
}
////////////////////////////////////////////////////////////////////////////////
// FindBoneByNode: search skeleton looking for matching bone using given node;
// return index of given node in the skeleton, 0xff if not found
u8 ExpSkeleton::FindBoneByNode(INode* boneNode) const
{
if (!boneNode) return 0xff;
for (int j=0;j<m_Bones.size();j++) {
ExpBone* bone=m_Bones[j];
if (bone->m_Node==boneNode) return j;
}
return 0xff;
}
/////////////////////////////////////////////////////////////////////////////////
// Build: traverse node heirachy adding bones to skeleton
void ExpSkeleton::Build(INode* node,ExpBone* parent)
{
if (IsBone(node)) {
// build bone
ExpBone* bone=new ExpBone;
bone->m_Node=node;
bone->m_Parent=parent;
// get bone's translation and rotation relative to root at time 0
GetBoneTransformComponents(node,0,bone->m_Translation,bone->m_Rotation);
// build transform from bone to object space
CMatrix3D m;
bone->m_Transform.SetIdentity();
bone->m_Transform.Rotate(bone->m_Rotation);
bone->m_Transform.Translate(bone->m_Translation);
// add bone to parent's list of children and complete bone list
if (parent) parent->m_Children.push_back(bone);
m_Bones.push_back(bone);
char buf[256];
sprintf(buf,"bonenode 0x%p (%s) added\n",node,node->GetName());
OutputDebugString(buf);
for (int i=0;i<node->NumberOfChildren();i++) {
Build(node->GetChildNode(i),bone);
}
}
}
/////////////////////////////////////////////////////////////////////////////////
// BuildAnimation: build and return a complete animation for this skeleton over
// given time range
CSkeletonAnimDef* ExpSkeleton::BuildAnimation(TimeValue start,TimeValue end,float rate)
{
CSkeletonAnimDef* anim=new CSkeletonAnimDef;
anim->m_Name="God Knows";
anim->m_NumFrames=1+(end-start)/rate;
anim->m_NumKeys=m_Bones.size();
anim->m_FrameTime=rate;
anim->m_Keys=new CSkeletonAnimDef::Key[anim->m_NumFrames*anim->m_NumKeys];
u32 counter=0;
TimeValue t=start;
while (t<end) {
for (int i=0;i<m_Bones.size();i++) {
CSkeletonAnimDef::Key& key=anim->m_Keys[counter++];
GetBoneTransformComponents(m_Bones[i]->m_Node,t,key.m_Translation,key.m_Rotation);
}
t+=rate;
}
return anim;
}
///////////////////////////////////////////////////////////////////////////////////////
// GetBoneTransformComponents: calculate the translation and rotation
// values of the given bone, relative to the root bone, at the given time
void ExpSkeleton::GetBoneTransformComponents(INode* node,TimeValue t,
CVector3D& trans,CQuaternion& rot)
{
Matrix3 nodeTM=node->GetNodeTM(t);
nodeTM.NoScale();
// decompose it to get translation and rotation
AffineParts parts;
decomp_affine(nodeTM,&parts);
// get translation from affine parts
MAXtoGL(parts.t);
trans=CVector3D(parts.t.x,parts.t.y,parts.t.z);
// get rotation from affine parts
rot.m_V.X=parts.q.x;
rot.m_V.Y=parts.q.z;
rot.m_V.Z=parts.q.y;
rot.m_W=parts.q.w;
}

View File

@ -0,0 +1,74 @@
#ifndef __EXPSKELETON_H
#define __EXPSKELETON_H
#include <vector>
#include "MaxInc.h"
#include "res/res.h"
#include "Matrix3D.h"
#include "Vector3D.h"
#include "Quaternion.h"
class CSkeleton;
class CSkeletonAnimDef;
////////////////////////////////////////////////////////////////////////
// ExpBone: bone type used during export
class ExpBone
{
public:
// MAX bone node
INode* m_Node;
// transform from object to this bones space at time 0
CMatrix3D m_Transform;
// translation relative to root bone at time 0
CVector3D m_Translation;
// rotation relative to root bone at time 0
CQuaternion m_Rotation;
// parent of this bone; 0 for root bone
ExpBone* m_Parent;
// children of this bone
std::vector<ExpBone*> m_Children;
};
////////////////////////////////////////////////////////////////////////
// ExpSkeleton:
class ExpSkeleton
{
public:
////////////////////////////////////////////////////////////////////////
// static methods for skeleton creation, destruction and type queries:
// build all skeletons from given root node
static void BuildSkeletons(INode* node,std::vector<ExpSkeleton*>& skeletons);
// return true if given node is a skeletal biped bone, else false
static bool IsBone(INode* node);
// return true if given node is biped footprints, else false
static bool IsFootprints(INode* node);
// return true if given node is the root of a skeleton, else false
static bool IsSkeletonRoot(INode* node);
public:
// constructor, destructor
ExpSkeleton();
~ExpSkeleton();
// search skeleton looking for matching bone using given node;
// return index of given node in the skeleton, 0xff if not found
u8 FindBoneByNode(INode* boneNode) const;
// build and return a complete animation for this skeleton over given time range
CSkeletonAnimDef* BuildAnimation(TimeValue start,TimeValue end,float rate);
private:
// traverse node heirachy adding bones to skeleton
void Build(INode* node,ExpBone* parent=0);
// calculate the translation and rotation values of the given bone,
// relative to the root bone, at the given time
void GetBoneTransformComponents(INode* node,TimeValue t,CVector3D& trans,CQuaternion& rot);
public:
// list of bones in skeleton; root bone is m_Bones[0]
std::vector<ExpBone*> m_Bones;
};
#endif

12
source/tools/pmdexp/ExpUtil.cpp Executable file
View File

@ -0,0 +1,12 @@
#include "MaxInc.h"
#include "ExpUtil.h"
//////////////////////////////////////////////////////////////////////
// MAXtoGL: convert point from MAX's coordinate system to that used
// within the engine
void MAXtoGL(Point3 &pnt)
{
float tmp = pnt.y;
pnt.y = pnt.z;
pnt.z = tmp;
}

9
source/tools/pmdexp/ExpUtil.h Executable file
View File

@ -0,0 +1,9 @@
#ifndef _EXPUTIL_H
#define _EXPUTIL_H
class Point3;
extern void MAXtoGL(Point3 &pnt);
#endif

22
source/tools/pmdexp/ExpVertex.h Executable file
View File

@ -0,0 +1,22 @@
#ifndef __EXPVERTEX_H
#define __EXPVERTEX_H
#include "lib\types.h"
#include "Vector3D.h"
#include "ModelDef.h"
////////////////////////////////////////////////////////////////////////
// ExpVertex: vertex type used in building mesh geometry
struct ExpVertex {
// index into original meshes point list
unsigned int m_Index;
// object space position
CVector3D m_Pos;
// object space normal
CVector3D m_Normal;
// uv coordinates
float m_UVs[2];
};
#endif

15
source/tools/pmdexp/MaxInc.h Executable file
View File

@ -0,0 +1,15 @@
#ifndef _MAXINC_H
#define _MAXINC_H
#define timeval MAX_timeval
//#define ERROR MAX_ERROR
#include "Max.h"
#include "iparamb2.h"
#include "iparamm2.h"
#include "istdplug.h"
#include "resource.h"
#undef timeval
#endif

276
source/tools/pmdexp/PMDExp.cpp Executable file
View File

@ -0,0 +1,276 @@
#include "PMDExp.h"
#include "ExpMesh.h"
#include "ExpProp.h"
#include "ExpSkeleton.h"
#undef PI
#include "ModelDef.h"
//////////////////////////////////////////////////////////////////////
// PMDExp constructor
PMDExp::PMDExp()
{
}
//////////////////////////////////////////////////////////////////////
// PMDExp destructor
PMDExp::~PMDExp()
{
}
//////////////////////////////////////////////////////////////////////
// ExtCount: return the number of file name extensions supported
// by the plug-in.
int PMDExp::ExtCount()
{
return 1;
}
//////////////////////////////////////////////////////////////////////
// Ext: return the ith file name extension
const TCHAR* PMDExp::Ext(int n)
{
return _T("pmd");
}
//////////////////////////////////////////////////////////////////////
// LongDesc: return long ASCII description
const TCHAR* PMDExp::LongDesc()
{
return _T("Prometheus Model Data");
}
//////////////////////////////////////////////////////////////////////
// ShortDesc: return short ASCII description
const TCHAR* PMDExp::ShortDesc()
{
return _T("Prometheus Model");
}
//////////////////////////////////////////////////////////////////////
// AuthorName: return author name
const TCHAR* PMDExp::AuthorName()
{
return _T("Rich Cross");
}
//////////////////////////////////////////////////////////////////////
// CopyrightMessage: return copyright message
const TCHAR* PMDExp::CopyrightMessage()
{
return _T("(c) Wildfire Games 2004");
}
//////////////////////////////////////////////////////////////////////
// OtherMessage1: return some other message (or don't, in this case)
const TCHAR* PMDExp::OtherMessage1()
{
return _T("");
}
//////////////////////////////////////////////////////////////////////
// OtherMessage2: return some other message (or don't, in this case)
const TCHAR* PMDExp::OtherMessage2()
{
return _T("");
}
//////////////////////////////////////////////////////////////////////
// Version: return version number * 100 (i.e. v3.01 = 301)
unsigned int PMDExp::Version()
{
return 1;
}
//////////////////////////////////////////////////////////////////////
// ShowAbout: show an about box (or don't, in this case)
void PMDExp::ShowAbout(HWND hWnd)
{
}
//////////////////////////////////////////////////////////////////////
// SupportsOptions: return true for each option supported by each
// extension the exporter supports
BOOL PMDExp::SupportsOptions(int ext, DWORD options)
{
// return TRUE to indicate export selected supported
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// DoExport: actually perform the export to the given filename
int PMDExp::DoExport(const TCHAR *name,ExpInterface *ei,Interface *ip, BOOL suppressPrompts, DWORD options)
{
// result of the export: assume we'll fail somewhere along the way
BOOL res=FALSE;
// save off the interface ptr
m_IP=ip;
// save off the options
m_Options=options;
// build any skeletons in MAXs heirarchy before going any further
std::vector<ExpSkeleton*> skeletons;
ExpSkeleton::BuildSkeletons(m_IP->GetRootNode(),skeletons);
if (skeletons.size()>1) {
MessageBox(GetActiveWindow(),"Found more than one skeleton in scene","Error",MB_OK);
} else {
// build list of meshes and props from nodes in MAXs heirarchy
std::vector<ExpMesh*> meshes;
std::vector<ExpProp*> props;
ExpSkeleton* skeleton=skeletons.size()>0 ? skeletons[0] : 0;
BuildOutputList(m_IP->GetRootNode(),skeleton,meshes,props);
if (meshes.size()==0) {
// hmm .. nothing there?
MessageBox(GetActiveWindow(),"Failed to find any meshes to export","Error",MB_OK);
} else {
// build a model from the node tree and any skeleton in scene
CModelDef* model=BuildModel(meshes,props,skeleton);
if (!model) {
MessageBox(GetActiveWindow(),"Failed to create model","Error",MB_OK);
} else {
try {
CModelDef::Save(name,model);
res=TRUE;
} catch (...) {
res=FALSE;
}
MessageBox(GetActiveWindow(),res ? "Export Complete" : "Error saving model",res ? "Info" : "Error",MB_OK);
}
for (int i=0;i<meshes.size();i++) {
delete meshes[i];
}
}
}
// clean up
for (int i=0;i<skeletons.size();i++) {
delete skeletons[i];
}
// return result
return res;
}
/////////////////////////////////////////////////////////////////////////////////
// BuildOutputList: traverse heirarchy collecting meshes/props
void PMDExp::BuildOutputList(INode* node,ExpSkeleton* skeleton,
std::vector<ExpMesh*>& meshes,std::vector<ExpProp*>& props)
{
// get object attached to node
ObjectState os=node->EvalWorldState(0);
if (os.obj) {
// handle export selected
if ((m_Options & SCENE_EXPORT_SELECTED) && !node->Selected()) {
// ignore ..
} else {
// mesh?
bool isMesh=true; // assume so
if (isMesh && !PMDExpMesh::IsMesh(os.obj)) isMesh=false;
if (isMesh && ExpSkeleton::IsBone(node)) isMesh=false;
if (isMesh && ExpSkeleton::IsFootprints(node)) isMesh=false;
if (isMesh) {
PMDExpMesh meshbuilder(node,skeleton);
ExpMesh* mesh=meshbuilder.Build();
meshes.push_back(mesh);
} else {
// not a mesh - a prop?
if (PMDExpProp::IsProp(os.obj)) {
PMDExpProp propbuilder(node);
ExpProp* prop=propbuilder.Build();
props.push_back(prop);
}
}
}
}
// traverse into children
for (int i=0;i<node->NumberOfChildren();i++) {
BuildOutputList(node->GetChildNode(i),skeleton,meshes,props);
}
}
/////////////////////////////////////////////////////////////////////////////////
// BuildModel: weld together given list of meshes, and attach props; return
// result as a CModelDef
CModelDef* PMDExp::BuildModel(std::vector<ExpMesh*>& meshes,std::vector<ExpProp*>& props,
ExpSkeleton* skeleton)
{
SVertexBlend nullBlend;
memset(nullBlend.m_Bone,0xff,sizeof(nullBlend.m_Bone));
memset(nullBlend.m_Weight,0,sizeof(nullBlend.m_Weight));
// sum up total number of vertices and faces
u32 totalVerts=0,totalFaces=0;
for (int i=0;i<meshes.size();i++) {
totalVerts+=meshes[i]->m_Vertices.size();
totalFaces+=meshes[i]->m_Faces.size();
}
CModelDef* mdl=new CModelDef;
mdl->m_NumVertices=totalVerts;
mdl->m_pVertices=new SModelVertex[totalVerts];
mdl->m_NumFaces=totalFaces;
mdl->m_pFaces=new SModelFace[totalFaces];
mdl->m_NumBones=skeleton ? skeleton->m_Bones.size() : 0;
mdl->m_Bones=new CBoneState[mdl->m_NumBones];
// build vertices
int vcount=0;
for (i=0;i<meshes.size();i++) {
const VertexList& verts=meshes[i]->m_Vertices;
const VBlendList& blends=meshes[i]->m_Blends;
for (int j=0;j<verts.size();j++) {
mdl->m_pVertices[vcount].m_Coords=verts[j].m_Pos;
mdl->m_pVertices[vcount].m_Norm=verts[j].m_Normal;
mdl->m_pVertices[vcount].m_U=verts[j].m_UVs[0];
mdl->m_pVertices[vcount].m_V=verts[j].m_UVs[1];
mdl->m_pVertices[vcount].m_Blend=blends.size()>0 ? blends[verts[j].m_Index] : nullBlend;
vcount++;
}
}
// build faces
int fcount=0;
int offset=0;
for (i=0;i<meshes.size();i++) {
const FaceList& faces=meshes[i]->m_Faces;
for (int j=0;j<faces.size();j++) {
mdl->m_pFaces[fcount].m_Verts[0]=faces[j].m_V[0]+offset;
mdl->m_pFaces[fcount].m_Verts[1]=faces[j].m_V[1]+offset;
mdl->m_pFaces[fcount].m_Verts[2]=faces[j].m_V[2]+offset;
fcount++;
}
offset+=meshes[i]->m_Vertices.size();
}
// build bones
for (i=0;i<mdl->m_NumBones;i++) {
mdl->m_Bones[i].m_Translation=skeleton->m_Bones[i]->m_Translation;
mdl->m_Bones[i].m_Rotation=skeleton->m_Bones[i]->m_Rotation;
}
// attach props
mdl->m_NumPropPoints=props.size();
mdl->m_PropPoints=new SPropPoint[mdl->m_NumPropPoints];
for (i=0;i<mdl->m_NumPropPoints;i++) {
mdl->m_PropPoints[i].m_Name=props[i]->m_Name;
mdl->m_PropPoints[i].m_Position=props[i]->m_Position;
mdl->m_PropPoints[i].m_Rotation=props[i]->m_Rotation;
mdl->m_PropPoints[i].m_BoneIndex=skeleton ? skeleton->FindBoneByNode(props[i]->m_Parent) : 0xff;
}
// all done
return mdl;
}

144
source/tools/pmdexp/PMDExp.dsw Executable file
View File

@ -0,0 +1,144 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "DyMaxLight"=..\dymaxlight\DyMaxLight.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
"$/dev/src/tools/max/dymaxlight", ZVAAAAAA
..\dymaxlight
end source code control
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "arbvp_c"=..\..\arbvp_c\arbvp_c.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
"$/dev/src/tools/arbvp_c", LRBAAAAA
..\..\arbvp_c
end source code control
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "common"=..\..\..\common\common.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
"$/dev/src/common", LVAAAAAA
..\..\..\common
end source code control
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "dy"=..\..\..\dy\dy.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
"$/dev/src/dy", NVAAAAAA
..\..\..\dy
end source code control
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "dyexp"=.\dyexp.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
"$/dev/src/tools/max/dyexp", YVAAAAAA
.
end source code control
}}}
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name dy
End Project Dependency
Begin Project Dependency
Project_Dep_Name DyMaxLight
End Project Dependency
Begin Project Dependency
Project_Dep_Name common
End Project Dependency
Begin Project Dependency
Project_Dep_Name filesys
End Project Dependency
Begin Project Dependency
Project_Dep_Name luacore
End Project Dependency
}}}
###############################################################################
Project: "filesys"=..\..\..\filesys\filesys.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
"$/dev/src/filesys", RSBAAAAA
..\..\..\filesys
end source code control
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "luacore"=..\..\..\lua\luacore\luacore.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
"$/dev/src/lua/luacore", RVBAAAAA
..\..\..\lua\luacore
end source code control
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

53
source/tools/pmdexp/PMDExp.h Executable file
View File

@ -0,0 +1,53 @@
#ifndef __PMDEXP_H
#define __PMDEXP_H
// necessary includes
#include "MaxInc.h"
#include <vector>
// necessary declarations
class ExpMesh;
class ExpProp;
class ExpSkeleton;
class CModelDef;
/////////////////////////////////////////////////////////////////
// PMDExp:
class PMDExp : public SceneExport
{
public:
PMDExp();
~PMDExp();
// standard stuff that Max requires
int ExtCount(); // Number of extensions supported
const TCHAR* Ext(int n); // Extension #n (i.e. "3DS")
const TCHAR* LongDesc(); // Long ASCII description (i.e. "Autodesk 3D Studio File")
const TCHAR* ShortDesc(); // Short ASCII description (i.e. "3D Studio")
const TCHAR* AuthorName(); // ASCII Author name
const TCHAR* CopyrightMessage(); // ASCII Copyright message
const TCHAR* OtherMessage1(); // Other message #1
const TCHAR* OtherMessage2(); // Other message #2
unsigned int Version(); // Version number * 100 (i.e. v3.01 = 301)
void ShowAbout(HWND hWnd); // Show DLL's "About..." box
BOOL SupportsOptions(int ext, DWORD options);
int DoExport(const TCHAR *name,ExpInterface *ei,Interface *i, BOOL suppressPrompts=FALSE, DWORD options=0);
private:
// BuildOutputList: traverse heirarchy collecting meshes/props
void BuildOutputList(INode* node,ExpSkeleton* skeleton,
std::vector<ExpMesh*>& meshes,std::vector<ExpProp*>& props);
// WeldMeshes: weld together given list of meshes; return result as a CModelDef
CModelDef* BuildModel(std::vector<ExpMesh*>& meshes,std::vector<ExpProp*>& props,ExpSkeleton* skeleton);
// pointer to MAXs Interface object
Interface* m_IP;
// handle to the export parameters window
HWND m_Params;
// export options
DWORD m_Options;
};
#endif

BIN
source/tools/pmdexp/PMDExp.opt Executable file

Binary file not shown.

View File

@ -0,0 +1 @@
35

168
source/tools/pmdexp/PMDExp.rc Executable file
View File

@ -0,0 +1,168 @@
//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_NEW_POINTPARAM DIALOG DISCARDABLE 0, 0, 108, 110
STYLE WS_CHILD | WS_VISIBLE
FONT 8, "MS Sans Serif"
BEGIN
CONTROL "Axis Tripod",IDC_POINT_AXIS,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,12,24,53,10
CONTROL "",IDC_POINT_SIZE,"CustEdit",WS_TABSTOP,49,63,28,10
RTEXT "Size:",IDC_STATIC,19,63,27,8
CONTROL "",IDC_POINT_SIZESPIN,"SpinnerControl",0x0,78,63,7,10
CONTROL "Center Marker",IDC_POINT_MARKER,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,12,12,63,10
CONTROL "Cross",IDC_POINT_CROSS,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,12,36,33,10
CONTROL "Box",IDC_POINT_BOX,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,12,48,33,10
GROUPBOX "Display:",IDC_STATIC,5,1,98,105
CONTROL "Constant Screen Size",IDC_POINT_SCREENSIZE,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,12,78,84,10
CONTROL "Draw On Top",IDC_POINT_DRAWONTOP,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,12,91,59,10
END
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
#ifndef _MAC
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 5,0,0,0
PRODUCTVERSION 5,0,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "Comments", "TECH: \0"
VALUE "CompanyName", "\0"
VALUE "FileDescription", "PMD File Export\0"
VALUE "FileVersion", "5.0.0.0\0"
VALUE "InternalName", "PMDExp\0"
VALUE "LegalCopyright", "\0"
VALUE "LegalTrademarks", "3D Studio MAX, Biped, Character Studio, Heidi, Kinetix and Physique are registered trademarks and 3ds max, combustion, Discreet, DWG Unplugged, DXF, FLI and FLC are trademarks of Autodesk, Inc.\0"
VALUE "OriginalFilename", "PMDExp.dle\0"
VALUE "PrivateBuild", "\0"
VALUE "ProductName", "3ds max\0"
VALUE "ProductVersion", "5.0.0.0\0"
VALUE "SpecialBuild", "\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // !_MAC
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE DISCARDABLE
BEGIN
IDS_LIBDESCRIPTION "Prometheus Export Tools"
IDS_CATEGORY "Exporters"
IDS_PMD_CLASS_NAME "PMDExp"
IDS_PARAMS "Parameters"
IDS_PSA_CLASS_NAME "PSAExp"
IDS_DB_POINT "PSProp"
IDS_DB_POINTHELPER_CLASS "Prop Point"
IDS_DB_POINT_CLASS "Prop Point"
END
STRINGTABLE DISCARDABLE
BEGIN
IDS_POINT_PARAMS "Parameters"
IDS_POINT_SIZE "Size"
IDS_POINT_CENTERMARKER "Center Marker"
IDS_POINT_AXISTRIPOD "Axis Tripod"
IDS_POINT_CROSS "Cross"
IDS_POINT_BOX "Box"
IDS_POINT_SCREENSIZE "Constant Screen Size"
IDS_POINT_HELPER_NAME "PSProp"
IDS_POINT_DRAWONTOP "Draw On Top"
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@ -0,0 +1,8 @@
LIBRARY pmdexp5
EXPORTS
LibDescription @1
LibNumberClasses @2
LibClassDesc @3
LibVersion @4
SECTIONS
.data READ WRITE

189
source/tools/pmdexp/PMDExp5.dsp Executable file
View File

@ -0,0 +1,189 @@
# Microsoft Developer Studio Project File - Name="PMDExp5" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=PMDExp5 - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "PMDExp5.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "PMDExp5.mak" CFG="PMDExp5 - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "PMDExp5 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "PMDExp5 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""$/dev/dylan/plugins/PMDExp", YVAAAAAA"
# PROP Scc_LocalPath "."
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "PMDExp5 - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "ReleaseR5"
# PROP Intermediate_Dir "ReleaseR5"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /YX /FD /c
# ADD CPP /nologo /G5 /MT /W3 /GX /I "d:\3dsmax5\maxsdk\include" /I "..\\" /I "..\lib" /I "..\ps" /I "..\simulation" /I "..\terrain" /D "NDEBUG" /D "_USRDLL" /D "_3DSMAX_" /D "_WINDOWS" /D "WIN32" /D "_NO_WINMAIN_" /FD /LD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x809 /d "NDEBUG"
# ADD RSC /l 0x809 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
# ADD LINK32 pslib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib /nologo /base:"0x50810000" /subsystem:windows /dll /machine:I386 /out:"d:\3dsmax5\plugins\pmdexp5.dle" /libpath:"d:\3dsmax5\maxsdk\lib" /libpath:"..\libs" /release
# SUBTRACT LINK32 /pdb:none
!ELSEIF "$(CFG)" == "PMDExp5 - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "DebugR5"
# PROP Intermediate_Dir "DebugR5"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /YX /FD /GZ /c
# ADD CPP /nologo /G6 /MTd /W3 /GX /ZI /Od /I "d:\3dsmax5\maxsdk\include" /I "..\\" /I "..\lib" /I "..\ps" /I "..\simulation" /I "..\terrain" /D "_DEBUG" /D "_USRDLL" /D "_3DSMAX_" /D "_WINDOWS" /D "WIN32" /D "_NO_WINMAIN_" /FD /LD /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x809 /d "_DEBUG"
# ADD RSC /l 0x809 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 pslib_d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib /nologo /base:"0x50810000" /subsystem:windows /dll /map /debug /machine:I386 /out:"d:\3dsmax5\plugins\pmdexp5.dle" /pdbtype:sept /libpath:"d:\3dsmax5\maxsdk\lib" /libpath:"..\libs"
# SUBTRACT LINK32 /pdb:none
!ENDIF
# Begin Target
# Name "PMDExp5 - Win32 Release"
# Name "PMDExp5 - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\DllEntry.cpp
# End Source File
# Begin Source File
SOURCE=.\ExpMesh.cpp
# End Source File
# Begin Source File
SOURCE=.\ExpSkeleton.cpp
# End Source File
# Begin Source File
SOURCE=.\ExpUtil.cpp
# End Source File
# Begin Source File
SOURCE=.\PMDExp.cpp
# End Source File
# Begin Source File
SOURCE=.\PMDExp.rc
# End Source File
# Begin Source File
SOURCE=.\PMDExp5.def
# End Source File
# Begin Source File
SOURCE=.\PSAExp.cpp
# End Source File
# Begin Source File
SOURCE=.\PSProp.cpp
# End Source File
# Begin Source File
SOURCE=.\VNormal.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\ExpMesh.h
# End Source File
# Begin Source File
SOURCE=.\ExpSkeleton.h
# End Source File
# Begin Source File
SOURCE=.\ExpUtil.h
# End Source File
# Begin Source File
SOURCE=.\ExpVertex.h
# End Source File
# Begin Source File
SOURCE=.\PMDExp.h
# End Source File
# Begin Source File
SOURCE=.\PSAExp.h
# End Source File
# Begin Source File
SOURCE=.\PSProp.h
# End Source File
# Begin Source File
SOURCE=.\resource.h
# End Source File
# Begin Source File
SOURCE=.\Tree.h
# End Source File
# Begin Source File
SOURCE=.\VertexTree.h
# End Source File
# Begin Source File
SOURCE=.\VNormal.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

View File

@ -0,0 +1,8 @@
LIBRARY pmdexp6
EXPORTS
LibDescription @1
LibNumberClasses @2
LibClassDesc @3
LibVersion @4
SECTIONS
.data READ WRITE

193
source/tools/pmdexp/PMDExp6.dsp Executable file
View File

@ -0,0 +1,193 @@
# Microsoft Developer Studio Project File - Name="PMDExp6" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=PMDExp6 - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "PMDExp6.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "PMDExp6.mak" CFG="PMDExp6 - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "PMDExp6 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "PMDExp6 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""$/dev/dylan/plugins/PMDExp", YVAAAAAA"
# PROP Scc_LocalPath "."
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "PMDExp6 - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "ReleaseR6"
# PROP Intermediate_Dir "ReleaseR6"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /YX /FD /c
# ADD CPP /nologo /G5 /MT /W3 /GX /I "d:\3dsmax6\maxsdk\include" /I "..\\" /I "..\lib" /I "..\ps" /I "..\simulation" /I "..\terrain" /D "NDEBUG" /D "_USRDLL" /D "_3DSMAX_" /D "_WINDOWS" /D "WIN32" /D "_NO_WINMAIN_" /FD /LD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x809 /d "NDEBUG"
# ADD RSC /l 0x809 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
# ADD LINK32 pslib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib /nologo /base:"0x50810000" /entry:"" /subsystem:windows /dll /machine:I386 /out:"d:\3dsmax6\plugins\pmdexp6.dle" /libpath:"d:\3dsmax6\maxsdk\lib" /libpath:"..\libs" /release
# SUBTRACT LINK32 /pdb:none
!ELSEIF "$(CFG)" == "PMDExp6 - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "DebugR6"
# PROP Intermediate_Dir "DebugR6"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /YX /FD /GZ /c
# ADD CPP /nologo /G6 /MTd /W3 /Gm /GX /ZI /Od /I "d:\3dsmax6\maxsdk\include" /I "..\\" /I "..\lib" /I "..\ps" /I "..\simulation" /I "..\terrain" /D "_DEBUG" /D "_USRDLL" /D "_3DSMAX_" /D "_WINDOWS" /D "WIN32" /D "_NO_WINMAIN_" /FD /LD /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x809 /d "_DEBUG"
# ADD RSC /l 0x809 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 pslib_d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib core.lib geom.lib gfx.lib mesh.lib maxutil.lib maxscrpt.lib paramblk2.lib /nologo /base:"0x50810000" /subsystem:windows /dll /debug /machine:I386 /out:"d:\3dsmax6\plugins\pmdexp6.dle" /pdbtype:sept /libpath:"d:\3dsmax6\maxsdk\lib" /libpath:"..\libs"
# SUBTRACT LINK32 /pdb:none
!ENDIF
# Begin Target
# Name "PMDExp6 - Win32 Release"
# Name "PMDExp6 - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\DllEntry.cpp
# End Source File
# Begin Source File
SOURCE=.\ExpMesh.cpp
# End Source File
# Begin Source File
SOURCE=.\ExpProp.cpp
# End Source File
# Begin Source File
SOURCE=.\ExpSkeleton.cpp
# End Source File
# Begin Source File
SOURCE=.\ExpUtil.cpp
# End Source File
# Begin Source File
SOURCE=.\PMDExp.cpp
# End Source File
# Begin Source File
SOURCE=.\PMDExp.rc
# End Source File
# Begin Source File
SOURCE=.\PMDExp6.def
# End Source File
# Begin Source File
SOURCE=.\PSAExp.cpp
# End Source File
# Begin Source File
SOURCE=.\PSProp.cpp
# End Source File
# Begin Source File
SOURCE=.\VNormal.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\ExpMesh.h
# End Source File
# Begin Source File
SOURCE=.\ExpProp.h
# End Source File
# Begin Source File
SOURCE=.\ExpSkeleton.h
# End Source File
# Begin Source File
SOURCE=.\ExpUtil.h
# End Source File
# Begin Source File
SOURCE=.\ExpVertex.h
# End Source File
# Begin Source File
SOURCE=.\MaxInc.h
# End Source File
# Begin Source File
SOURCE=.\PMDExp.h
# End Source File
# Begin Source File
SOURCE=.\resource.h
# End Source File
# Begin Source File
SOURCE=.\Tree.h
# End Source File
# Begin Source File
SOURCE=.\VertexTree.h
# End Source File
# Begin Source File
SOURCE=.\VNormal.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

143
source/tools/pmdexp/PSAExp.cpp Executable file
View File

@ -0,0 +1,143 @@
#include "PSAExp.h"
#include "ExpMesh.h"
#include "ExpSkeleton.h"
#undef PI
#include "ModelDef.h"
#include "SkeletonAnim.h"
//////////////////////////////////////////////////////////////////////
// PSAExp constructor
PSAExp::PSAExp()
{
}
//////////////////////////////////////////////////////////////////////
// PSAExp destructor
PSAExp::~PSAExp()
{
}
//////////////////////////////////////////////////////////////////////
// ExtCount: return the number of file name extensions supported
// by the plug-in.
int PSAExp::ExtCount()
{
return 1;
}
//////////////////////////////////////////////////////////////////////
// Ext: return the ith file name extension
const TCHAR* PSAExp::Ext(int n)
{
return _T("psa");
}
//////////////////////////////////////////////////////////////////////
// LongDesc: return long ASCII description
const TCHAR* PSAExp::LongDesc()
{
return _T("Prometheus Skeleton Anim");
}
//////////////////////////////////////////////////////////////////////
// ShortDesc: return short ASCII description
const TCHAR* PSAExp::ShortDesc()
{
return _T("Prometheus Anim");
}
//////////////////////////////////////////////////////////////////////
// AuthorName: return author name
const TCHAR* PSAExp::AuthorName()
{
return _T("Rich Cross");
}
//////////////////////////////////////////////////////////////////////
// CopyrightMessage: return copyright message
const TCHAR* PSAExp::CopyrightMessage()
{
return _T("(c) Wildfire Games 2004");
}
//////////////////////////////////////////////////////////////////////
// OtherMessage1: return some other message (or don't, in this case)
const TCHAR* PSAExp::OtherMessage1()
{
return _T("");
}
//////////////////////////////////////////////////////////////////////
// OtherMessage2: return some other message (or don't, in this case)
const TCHAR* PSAExp::OtherMessage2()
{
return _T("");
}
//////////////////////////////////////////////////////////////////////
// Version: return version number * 100 (i.e. v3.01 = 301)
unsigned int PSAExp::Version()
{
return 1;
}
//////////////////////////////////////////////////////////////////////
// ShowAbout: show an about box (or don't, in this case)
void PSAExp::ShowAbout(HWND hWnd)
{
}
//////////////////////////////////////////////////////////////////////
// SupportsOptions: return true for each option supported by each
// extension the exporter supports
BOOL PSAExp::SupportsOptions(int ext, DWORD options)
{
// return TRUE to indicate export selected supported
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// DoExport: actually perform the export to the given filename
int PSAExp::DoExport(const TCHAR *name,ExpInterface *ei,Interface *ip, BOOL suppressPrompts, DWORD options)
{
// result of the export: assume we'll fail somewhere along the way
BOOL res=FALSE;
// save off the interface ptr
m_IP=ip;
// save off the options
m_Options=options;
// build any skeletons in MAXs heirarchy before going any further
std::vector<ExpSkeleton*> skeletons;
ExpSkeleton::BuildSkeletons(m_IP->GetRootNode(),skeletons);
if (skeletons.size()>1) {
MessageBox(GetActiveWindow(),"Found more than one skeleton in scene","Error",MB_OK);
} else if (skeletons.size()==0) {
MessageBox(GetActiveWindow(),"No skeletons found in scene","Error",MB_OK);
} else {
// build an animation from first skeleton
ExpSkeleton* skeleton=skeletons[0];
Interval interval=m_IP->GetAnimRange();
CSkeletonAnimDef* anim=skeleton->BuildAnimation(interval.Start(),interval.End(),1000/30);
try {
CSkeletonAnimDef::Save(name,anim);
res=TRUE;
} catch (...) {
res=FALSE;
}
MessageBox(GetActiveWindow(),res ? "Export Complete" : "Error saving model",res ? "Info" : "Error",MB_OK);
}
// clean up
for (int i=0;i<skeletons.size();i++) {
delete skeletons[i];
}
// return result
return res;
}

49
source/tools/pmdexp/PSAExp.h Executable file
View File

@ -0,0 +1,49 @@
#ifndef __PSAEXP_H
#define __PSAEXP_H
// necessary includes
#include "MaxInc.h"
#include <vector>
// necessary declarations
class ExpMesh;
class ExpSkeleton;
class CModelDef;
class CSkeleton;
/////////////////////////////////////////////////////////////////
// PSAExp:
class PSAExp : public SceneExport
{
public:
PSAExp();
~PSAExp();
// standard stuff that Max requires
int ExtCount(); // Number of extensions supported
const TCHAR* Ext(int n); // Extension #n (i.e. "3DS")
const TCHAR* LongDesc(); // Long ASCII description (i.e. "Autodesk 3D Studio File")
const TCHAR* ShortDesc(); // Short ASCII description (i.e. "3D Studio")
const TCHAR* AuthorName(); // ASCII Author name
const TCHAR* CopyrightMessage(); // ASCII Copyright message
const TCHAR* OtherMessage1(); // Other message #1
const TCHAR* OtherMessage2(); // Other message #2
unsigned int Version(); // Version number * 100 (i.e. v3.01 = 301)
void ShowAbout(HWND hWnd); // Show DLL's "About..." box
BOOL SupportsOptions(int ext, DWORD options);
int DoExport(const TCHAR *name,ExpInterface *ei,Interface *i, BOOL suppressPrompts=FALSE, DWORD options=0);
private:
// pointer to MAXs Interface object
Interface* m_IP;
// handle to the export parameters window
HWND m_Params;
// export options
DWORD m_Options;
// list of all skeletons found in scene
std::vector<ExpSkeleton*> m_Skeletons;
};
#endif

924
source/tools/pmdexp/PSProp.cpp Executable file
View File

@ -0,0 +1,924 @@
/**********************************************************************
*<
FILE: pthelp.cpp
DESCRIPTION: A point helper implementation
CREATED BY:
HISTORY: created 14 July 1995
*> Copyright (c) 1995, All Rights Reserved.
**********************************************************************/
#include "PSProp.h"
//------------------------------------------------------
// in prim.cpp - The dll instance handle
extern HINSTANCE hInstance;
#define AXIS_LENGTH 20.0f
#define ZFACT (float).005;
void AxisViewportRect(ViewExp *vpt, const Matrix3 &tm, float length, Rect *rect);
void DrawAxis(ViewExp *vpt, const Matrix3 &tm, float length, BOOL screenSize);
Box3 GetAxisBox(ViewExp *vpt, const Matrix3 &tm,float length,int resetTM);
//////////////////////////////////////////////////////////////////////////////////////
// PSPropClassDesc : required class to expose PSProp to MAX
class PSPropClassDesc : public ClassDesc2
{
public:
int IsPublic() { return 1; }
void * Create(BOOL loading = FALSE) { return new PSPropObject; }
const TCHAR * ClassName() { return GetString(IDS_DB_POINT_CLASS); }
SClass_ID SuperClassID() { return HELPER_CLASS_ID; }
Class_ID ClassID() { return PSPROP_CLASS_ID; }
const TCHAR* Category() { return _T("PS Helpers"); }
const TCHAR* InternalName() {return _T("PSProp");}
HINSTANCE HInstance() {return hInstance;}
};
PSPropClassDesc pointHelpObjDesc;
ClassDesc* GetPSPropDesc() { return &pointHelpObjDesc; }
// class variable for point class.
IObjParam *PSPropObject::ip = NULL;
PSPropObject *PSPropObject::editOb = NULL;
//HWND PSPropObject::hParams = NULL;
//IObjParam *PSPropObject::iObjParams;
//int PSPropObject::dlgShowAxis = TRUE;
//float PSPropObject::dlgAxisLength = AXIS_LENGTH;
void resetPointParams()
{
//PSPropObject::dlgShowAxis = TRUE;
//PSPropObject::dlgAxisLength = AXIS_LENGTH;
}
#define PBLOCK_REF_NO 0
// The following two enums are transfered to the istdplug.h by AG: 01/20/2002
// in order to access the parameters for use in Spline IK Control modifier
// and the Spline IK Solver
// block IDs
//enum { pointobj_params, };
// pointobj_params IDs
// enum {
// pointobj_size, pointobj_centermarker, pointobj_axistripod,
// pointobj_cross, pointobj_box, pointobj_screensize, pointobj_drawontop };
// per instance block
static ParamBlockDesc2 pointobj_param_blk(
pointobj_params, _T("PointObjectParameters"), 0, &pointHelpObjDesc, P_AUTO_CONSTRUCT+P_AUTO_UI, PBLOCK_REF_NO,
//rollout
IDD_NEW_POINTPARAM, IDS_POINT_PARAMS, 0, 0, NULL,
// params
pointobj_size, _T("size"), TYPE_FLOAT, P_ANIMATABLE, IDS_POINT_SIZE,
p_default, 20.0,
p_ms_default, 20.0,
p_range, 0.0f, float(1.0E30),
p_ui, TYPE_SPINNER, EDITTYPE_UNIVERSE, IDC_POINT_SIZE, IDC_POINT_SIZESPIN, SPIN_AUTOSCALE,
end,
pointobj_centermarker, _T("centermarker"), TYPE_BOOL, P_ANIMATABLE, IDS_POINT_CENTERMARKER,
p_default, FALSE,
p_ui, TYPE_SINGLECHEKBOX, IDC_POINT_MARKER,
end,
pointobj_axistripod, _T("axistripod"), TYPE_BOOL, P_ANIMATABLE, IDS_POINT_AXISTRIPOD,
p_default, FALSE,
p_ui, TYPE_SINGLECHEKBOX, IDC_POINT_AXIS,
end,
pointobj_cross, _T("cross"), TYPE_BOOL, P_ANIMATABLE, IDS_POINT_CROSS,
p_default, TRUE,
p_ui, TYPE_SINGLECHEKBOX, IDC_POINT_CROSS,
end,
pointobj_box, _T("box"), TYPE_BOOL, P_ANIMATABLE, IDS_POINT_BOX,
p_default, FALSE,
p_ui, TYPE_SINGLECHEKBOX, IDC_POINT_BOX,
end,
pointobj_screensize, _T("constantscreensize"), TYPE_BOOL, P_ANIMATABLE, IDS_POINT_SCREENSIZE,
p_default, FALSE,
p_ui, TYPE_SINGLECHEKBOX, IDC_POINT_SCREENSIZE,
end,
pointobj_drawontop, _T("drawontop"), TYPE_BOOL, P_ANIMATABLE, IDS_POINT_DRAWONTOP,
p_default, FALSE,
p_ui, TYPE_SINGLECHEKBOX, IDC_POINT_DRAWONTOP,
end,
end
);
/*
INT_PTR CALLBACK PointParamProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
PSPropObject *po = (PSPropObject*)GetWindowLongPtr(hWnd,GWLP_USERDATA);
if (!po && msg!=WM_INITDIALOG) return FALSE;
switch (msg) {
case WM_INITDIALOG: {
po = (PSPropObject*)lParam;
SetWindowLongPtr(hWnd,GWLP_USERDATA,lParam);
CheckDlgButton(hWnd,IDC_SHOWAXIS,po->showAxis);
ISpinnerControl *spin =
GetISpinner(GetDlgItem(hWnd,IDC_AXISLENGHSPIN));
spin->SetLimits(10,1000,FALSE);
spin->SetScale(0.1f);
spin->SetValue(po->axisLength,FALSE);
spin->LinkToEdit(GetDlgItem(hWnd,IDC_AXISLENGTH),EDITTYPE_FLOAT);
ReleaseISpinner(spin);
return FALSE;
}
case CC_SPINNER_CHANGE: {
ISpinnerControl *spin = (ISpinnerControl*)lParam;
po->axisLength = spin->GetFVal();
po->NotifyDependents(FOREVER,PART_OBJ,REFMSG_CHANGE);
po->iObjParams->RedrawViews(po->iObjParams->GetTime());
break;
}
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDC_SHOWAXIS:
po->showAxis = IsDlgButtonChecked(hWnd,IDC_SHOWAXIS);
po->NotifyDependents(FOREVER,PART_OBJ,REFMSG_CHANGE);
po->iObjParams->RedrawViews(po->iObjParams->GetTime());
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
*/
void PSPropObject::BeginEditParams(
IObjParam *ip, ULONG flags,Animatable *prev)
{
this->ip = ip;
editOb = this;
pointHelpObjDesc.BeginEditParams(ip, this, flags, prev);
/*
iObjParams = ip;
if (!hParams) {
hParams = ip->AddRollupPage(
hInstance,
MAKEINTRESOURCE(IDD_POINTPARAM),
PointParamProc,
GetString(IDS_DB_PARAMETERS),
(LPARAM)this );
ip->RegisterDlgWnd(hParams);
} else {
SetWindowLongPtr(hParams,GWLP_USERDATA,(LONG_PTR)this);
CheckDlgButton(hParams,IDC_SHOWAXIS,showAxis);
ISpinnerControl *spin =
GetISpinner(GetDlgItem(hParams,IDC_AXISLENGHSPIN));
spin->SetValue(axisLength,FALSE);
ReleaseISpinner(spin);
}
*/
}
void PSPropObject::EndEditParams(
IObjParam *ip, ULONG flags,Animatable *next)
{
editOb = NULL;
this->ip = NULL;
pointHelpObjDesc.EndEditParams(ip, this, flags, next);
ClearAFlag(A_OBJ_CREATING);
/*
dlgShowAxis = IsDlgButtonChecked(hParams, IDC_SHOWAXIS );
ISpinnerControl *spin = GetISpinner(GetDlgItem(hParams,IDC_AXISLENGHSPIN));
dlgAxisLength = spin->GetFVal();
ReleaseISpinner(spin);
if (flags&END_EDIT_REMOVEUI) {
ip->UnRegisterDlgWnd(hParams);
ip->DeleteRollupPage(hParams);
hParams = NULL;
} else {
SetWindowLongPtr(hParams,GWLP_USERDATA,0);
}
iObjParams = NULL;
*/
}
PSPropObject::PSPropObject()
{
pointHelpObjDesc.MakeAutoParamBlocks(this);
showAxis = TRUE; //dlgShowAxis;
axisLength = 10.0f; //dlgAxisLength;
suspendSnap = FALSE;
SetAFlag(A_OBJ_CREATING);
}
PSPropObject::~PSPropObject()
{
DeleteAllRefsFromMe();
}
IParamArray *PSPropObject::GetParamBlock()
{
return (IParamArray*)pblock2;
}
int PSPropObject::GetParamBlockIndex(int id)
{
if (pblock2 && id>=0 && id<pblock2->NumParams()) return id;
else return -1;
}
class PointHelpObjCreateCallBack: public CreateMouseCallBack {
PSPropObject *ob;
public:
int proc( ViewExp *vpt,int msg, int point, int flags, IPoint2 m, Matrix3& mat );
void SetObj(PSPropObject *obj) { ob = obj; }
};
int PointHelpObjCreateCallBack::proc(ViewExp *vpt,int msg, int point, int flags, IPoint2 m, Matrix3& mat ) {
#ifdef _OSNAP
if (msg == MOUSE_FREEMOVE)
{
#ifdef _3D_CREATE
vpt->SnapPreview(m,m,NULL, SNAP_IN_3D);
#else
vpt->SnapPreview(m,m,NULL, SNAP_IN_PLANE);
#endif
}
#endif
if (msg==MOUSE_POINT||msg==MOUSE_MOVE) {
switch(point) {
case 0: {
// Find the node and plug in the wire color
ULONG handle;
ob->NotifyDependents(FOREVER, (PartID)&handle, REFMSG_GET_NODE_HANDLE);
INode *node;
node = GetCOREInterface()->GetINodeByHandle(handle);
if (node) {
Point3 color(0,0,1);// = GetUIColor(COLOR_POINT_OBJ);
node->SetWireColor(RGB(color.x*255.0f, color.y*255.0f, color.z*255.0f));
}
ob->suspendSnap = TRUE;
#ifdef _3D_CREATE
mat.SetTrans(vpt->SnapPoint(m,m,NULL,SNAP_IN_3D));
#else
mat.SetTrans(vpt->SnapPoint(m,m,NULL,SNAP_IN_PLANE));
#endif
break;
}
case 1:
#ifdef _3D_CREATE
mat.SetTrans(vpt->SnapPoint(m,m,NULL,SNAP_IN_3D));
#else
mat.SetTrans(vpt->SnapPoint(m,m,NULL,SNAP_IN_PLANE));
#endif
if (msg==MOUSE_POINT) {
ob->suspendSnap = FALSE;
return 0;
}
break;
}
} else
if (msg == MOUSE_ABORT) {
return CREATE_ABORT;
}
return 1;
}
static PointHelpObjCreateCallBack pointHelpCreateCB;
CreateMouseCallBack* PSPropObject::GetCreateMouseCallBack() {
pointHelpCreateCB.SetObj(this);
return(&pointHelpCreateCB);
}
void PSPropObject::SetExtendedDisplay(int flags)
{
extDispFlags = flags;
}
void PSPropObject::GetLocalBoundBox(
TimeValue t, INode* inode, ViewExp* vpt, Box3& box )
{
Matrix3 tm = inode->GetObjectTM(t);
float size;
int screenSize;
pblock2->GetValue(pointobj_size, t, size, FOREVER);
pblock2->GetValue(pointobj_screensize, t, screenSize, FOREVER);
float zoom = 1.0f;
if (screenSize) {
zoom = vpt->GetScreenScaleFactor(tm.GetTrans())*ZFACT;
}
if (zoom==0.0f) zoom = 1.0f;
size *= zoom;
box = Box3(Point3(0,0,0), Point3(0,0,0));
box += Point3(size*0.5f, 0.0f, 0.0f);
box += Point3( 0.0f, size*0.5f, 0.0f);
box += Point3( 0.0f, 0.0f, size*0.5f);
box += Point3(-size*0.5f, 0.0f, 0.0f);
box += Point3( 0.0f, -size*0.5f, 0.0f);
box += Point3( 0.0f, 0.0f, -size*0.5f);
box.EnlargeBy(10.0f/zoom);
/*
if (showAxis)
box = GetAxisBox(vpt,tm,showAxis?axisLength:0.0f, TRUE);
else
box = Box3(Point3(0,0,0), Point3(0,0,0));
*/
}
void PSPropObject::GetWorldBoundBox(
TimeValue t, INode* inode, ViewExp* vpt, Box3& box )
{
Matrix3 tm;
tm = inode->GetObjectTM(t);
Box3 lbox;
GetLocalBoundBox(t, inode, vpt, lbox);
box = Box3(tm.GetTrans(), tm.GetTrans());
for (int i=0; i<8; i++) {
box += lbox * tm;
}
/*
if(!(extDispFlags & EXT_DISP_ZOOM_EXT) && showAxis)
box = GetAxisBox(vpt,tm,showAxis?axisLength:0.0f, FALSE);
else
box = Box3(tm.GetTrans(), tm.GetTrans());
*/
}
void PSPropObject::Snap(TimeValue t, INode* inode, SnapInfo *snap, IPoint2 *p, ViewExp *vpt)
{
if(suspendSnap)
return;
Matrix3 tm = inode->GetObjectTM(t);
GraphicsWindow *gw = vpt->getGW();
gw->setTransform(tm);
Matrix3 invPlane = Inverse(snap->plane);
// Make sure the vertex priority is active and at least as important as the best snap so far
if(snap->vertPriority > 0 && snap->vertPriority <= snap->priority) {
Point2 fp = Point2((float)p->x, (float)p->y);
Point2 screen2;
IPoint3 pt3;
Point3 thePoint(0,0,0);
// If constrained to the plane, make sure this point is in it!
if(snap->snapType == SNAP_2D || snap->flags & SNAP_IN_PLANE) {
Point3 test = thePoint * tm * invPlane;
if(fabs(test.z) > 0.0001) // Is it in the plane (within reason)?
return;
}
gw->wTransPoint(&thePoint,&pt3);
screen2.x = (float)pt3.x;
screen2.y = (float)pt3.y;
// Are we within the snap radius?
int len = (int)Length(screen2 - fp);
if(len <= snap->strength) {
// Is this priority better than the best so far?
if(snap->vertPriority < snap->priority) {
snap->priority = snap->vertPriority;
snap->bestWorld = thePoint * tm;
snap->bestScreen = screen2;
snap->bestDist = len;
}
else
if(len < snap->bestDist) {
snap->priority = snap->vertPriority;
snap->bestWorld = thePoint * tm;
snap->bestScreen = screen2;
snap->bestDist = len;
}
}
}
}
int PSPropObject::DrawAndHit(TimeValue t, INode *inode, ViewExp *vpt)
{
float size;
int centerMarker, axisTripod, cross, box, screenSize, drawOnTop;
// Color color = inode->GetWireColor();
Interval ivalid = FOREVER;
pblock2->GetValue(pointobj_size, t, size, ivalid);
pblock2->GetValue(pointobj_centermarker, t, centerMarker, ivalid);
pblock2->GetValue(pointobj_axistripod, t, axisTripod, ivalid);
pblock2->GetValue(pointobj_cross, t, cross, ivalid);
pblock2->GetValue(pointobj_box, t, box, ivalid);
pblock2->GetValue(pointobj_screensize, t, screenSize, ivalid);
pblock2->GetValue(pointobj_drawontop, t, drawOnTop, ivalid);
Matrix3 tm(1);
Point3 pt(0,0,0);
Point3 pts[5];
vpt->getGW()->setTransform(tm);
tm = inode->GetObjectTM(t);
int limits = vpt->getGW()->getRndLimits();
if (drawOnTop) vpt->getGW()->setRndLimits(limits & ~GW_Z_BUFFER);
if (inode->Selected()) {
vpt->getGW()->setColor( TEXT_COLOR, GetUIColor(COLOR_SELECTION) );
vpt->getGW()->setColor( LINE_COLOR, GetUIColor(COLOR_SELECTION) );
} else if (!inode->IsFrozen() && !inode->Dependent()) {
//vpt->getGW()->setColor( TEXT_COLOR, GetUIColor(COLOR_POINT_AXES) );
//vpt->getGW()->setColor( LINE_COLOR, GetUIColor(COLOR_POINT_AXES) );
vpt->getGW()->setColor( TEXT_COLOR, Color(0,0,1));
vpt->getGW()->setColor( LINE_COLOR, Color(0,0,1));
}
if (axisTripod) {
DrawAxis(vpt, tm, size, screenSize);
}
size *= 0.5f;
float zoom = vpt->GetScreenScaleFactor(tm.GetTrans())*ZFACT;
if (screenSize) {
tm.Scale(Point3(zoom,zoom,zoom));
}
vpt->getGW()->setTransform(tm);
if (!inode->IsFrozen() && !inode->Dependent() && !inode->Selected()) {
//vpt->getGW()->setColor(LINE_COLOR, GetUIColor(COLOR_POINT_OBJ));
vpt->getGW()->setColor( LINE_COLOR, Color(0,0,1));
}
if (centerMarker) {
vpt->getGW()->marker(&pt,X_MRKR);
}
if (cross) {
// X
pts[0] = Point3(-size, 0.0f, 0.0f); pts[1] = Point3(size, 0.0f, 0.0f);
vpt->getGW()->polyline(2, pts, NULL, NULL, FALSE, NULL);
// Y
pts[0] = Point3(0.0f, -size, 0.0f); pts[1] = Point3(0.0f, size, 0.0f);
vpt->getGW()->polyline(2, pts, NULL, NULL, FALSE, NULL);
// Z
pts[0] = Point3(0.0f, 0.0f, -size); pts[1] = Point3(0.0f, 0.0f, size);
vpt->getGW()->polyline(2, pts, NULL, NULL, FALSE, NULL);
}
if (box) {
// Make the box half the size
size = size * 0.5f;
// Bottom
pts[0] = Point3(-size, -size, -size);
pts[1] = Point3(-size, size, -size);
pts[2] = Point3( size, size, -size);
pts[3] = Point3( size, -size, -size);
vpt->getGW()->polyline(4, pts, NULL, NULL, TRUE, NULL);
// Top
pts[0] = Point3(-size, -size, size);
pts[1] = Point3(-size, size, size);
pts[2] = Point3( size, size, size);
pts[3] = Point3( size, -size, size);
vpt->getGW()->polyline(4, pts, NULL, NULL, TRUE, NULL);
// Sides
pts[0] = Point3(-size, -size, -size);
pts[1] = Point3(-size, -size, size);
vpt->getGW()->polyline(2, pts, NULL, NULL, FALSE, NULL);
pts[0] = Point3(-size, size, -size);
pts[1] = Point3(-size, size, size);
vpt->getGW()->polyline(2, pts, NULL, NULL, FALSE, NULL);
pts[0] = Point3( size, size, -size);
pts[1] = Point3( size, size, size);
vpt->getGW()->polyline(2, pts, NULL, NULL, FALSE, NULL);
pts[0] = Point3( size, -size, -size);
pts[1] = Point3( size, -size, size);
vpt->getGW()->polyline(2, pts, NULL, NULL, FALSE, NULL);
}
vpt->getGW()->setRndLimits(limits);
return 1;
}
int PSPropObject::HitTest(
TimeValue t, INode *inode, int type, int crossing, int flags, IPoint2 *p, ViewExp *vpt)
{
Matrix3 tm(1);
HitRegion hitRegion;
DWORD savedLimits;
Point3 pt(0,0,0);
vpt->getGW()->setTransform(tm);
GraphicsWindow *gw = vpt->getGW();
Material *mtl = gw->getMaterial();
tm = inode->GetObjectTM(t);
MakeHitRegion(hitRegion, type, crossing, 4, p);
gw->setRndLimits(((savedLimits = gw->getRndLimits())|GW_PICK)&~GW_ILLUM);
gw->setHitRegion(&hitRegion);
gw->clearHitCode();
DrawAndHit(t, inode, vpt);
/*
if (showAxis) {
DrawAxis(vpt,tm,axisLength,screenSize);
}
vpt->getGW()->setTransform(tm);
vpt->getGW()->marker(&pt,X_MRKR);
*/
gw->setRndLimits(savedLimits);
if((hitRegion.type != POINT_RGN) && !hitRegion.crossing)
return TRUE;
return gw->checkHitCode();
}
int PSPropObject::Display(
TimeValue t, INode* inode, ViewExp *vpt, int flags)
{
DrawAndHit(t, inode, vpt);
/*
Matrix3 tm(1);
Point3 pt(0,0,0);
vpt->getGW()->setTransform(tm);
tm = inode->GetObjectTM(t);
if (showAxis) {
DrawAxis(vpt,tm,axisLength,inode->Selected(),inode->IsFrozen());
}
vpt->getGW()->setTransform(tm);
if(!inode->IsFrozen())
vpt->getGW()->setColor(LINE_COLOR,GetUIColor(COLOR_POINT_OBJ));
vpt->getGW()->marker(&pt,X_MRKR);
*/
return(0);
}
//
// Reference Managment:
//
// This is only called if the object MAKES references to other things.
RefResult PSPropObject::NotifyRefChanged(
Interval changeInt, RefTargetHandle hTarget,
PartID& partID, RefMessage message )
{
switch (message) {
case REFMSG_CHANGE:
if (editOb==this) InvalidateUI();
break;
}
return(REF_SUCCEED);
}
void PSPropObject::InvalidateUI()
{
pointobj_param_blk.InvalidateUI(pblock2->LastNotifyParamID());
}
Interval PSPropObject::ObjectValidity(TimeValue t)
{
float size;
int centerMarker, axisTripod, cross, box, screenSize, drawOnTop;
Interval ivalid = FOREVER;
pblock2->GetValue(pointobj_size, t, size, ivalid);
pblock2->GetValue(pointobj_centermarker, t, centerMarker, ivalid);
pblock2->GetValue(pointobj_axistripod, t, axisTripod, ivalid);
pblock2->GetValue(pointobj_cross, t, cross, ivalid);
pblock2->GetValue(pointobj_box, t, box, ivalid);
pblock2->GetValue(pointobj_screensize, t, screenSize, ivalid);
pblock2->GetValue(pointobj_drawontop, t, drawOnTop, ivalid);
return ivalid;
}
ObjectState PSPropObject::Eval(TimeValue t)
{
return ObjectState(this);
}
RefTargetHandle PSPropObject::Clone(RemapDir& remap)
{
PSPropObject* newob = new PSPropObject();
newob->showAxis = showAxis;
newob->axisLength = axisLength;
newob->ReplaceReference(0, pblock2->Clone(remap));
BaseClone(this, newob, remap);
return(newob);
}
void PSPropObject::UpdateParamblockFromVars()
{
SuspendAnimate();
AnimateOff();
pblock2->SetValue(pointobj_size, TimeValue(0), axisLength);
pblock2->SetValue(pointobj_centermarker, TimeValue(0), TRUE);
pblock2->SetValue(pointobj_axistripod, TimeValue(0), showAxis);
pblock2->SetValue(pointobj_cross, TimeValue(0), FALSE);
pblock2->SetValue(pointobj_box, TimeValue(0), FALSE);
pblock2->SetValue(pointobj_screensize, TimeValue(0), TRUE);
ResumeAnimate();
}
class PointHelperPostLoadCallback : public PostLoadCallback {
public:
PSPropObject *pobj;
PointHelperPostLoadCallback(PSPropObject *p) {pobj=p;}
void proc(ILoad *iload) {
pobj->UpdateParamblockFromVars();
}
};
#define SHOW_AXIS_CHUNK 0x0100
#define AXIS_LENGTH_CHUNK 0x0110
#define POINT_HELPER_R4_CHUNKID 0x0120 // new version of point helper for R4 (updated to use PB2)
IOResult PSPropObject::Load(ILoad *iload)
{
ULONG nb;
IOResult res = IO_OK;
BOOL oldVersion = TRUE;
while (IO_OK==(res=iload->OpenChunk())) {
switch (iload->CurChunkID()) {
case SHOW_AXIS_CHUNK:
res = iload->Read(&showAxis,sizeof(showAxis),&nb);
break;
case AXIS_LENGTH_CHUNK:
res = iload->Read(&axisLength,sizeof(axisLength),&nb);
break;
case POINT_HELPER_R4_CHUNKID:
oldVersion = FALSE;
break;
}
res = iload->CloseChunk();
if (res!=IO_OK) return res;
}
if (oldVersion) {
iload->RegisterPostLoadCallback(new PointHelperPostLoadCallback(this));
}
return IO_OK;
}
IOResult PSPropObject::Save(ISave *isave)
{
/*
isave->BeginChunk(SHOW_AXIS_CHUNK);
isave->Write(&showAxis,sizeof(showAxis),&nb);
isave->EndChunk();
isave->BeginChunk(AXIS_LENGTH_CHUNK);
isave->Write(&axisLength,sizeof(axisLength),&nb);
isave->EndChunk();
*/
isave->BeginChunk(POINT_HELPER_R4_CHUNKID);
isave->EndChunk();
return IO_OK;
}
/*--------------------------------------------------------------------*/
//
// Stole this from scene.cpp
// Probably couldn't hurt to make an API...
//
//
void Text( ViewExp *vpt, TCHAR *str, Point3 &pt )
{
vpt->getGW()->text( &pt, str );
}
static void DrawAnAxis( ViewExp *vpt, Point3 axis )
{
Point3 v1, v2, v[3];
v1 = axis * (float)0.9;
if ( axis.x != 0.0 || axis.y != 0.0 ) {
v2 = Point3( axis.y, -axis.x, axis.z ) * (float)0.1;
} else {
v2 = Point3( axis.x, axis.z, -axis.y ) * (float)0.1;
}
v[0] = Point3(0.0,0.0,0.0);
v[1] = axis;
vpt->getGW()->polyline( 2, v, NULL, NULL, FALSE, NULL );
v[0] = axis;
v[1] = v1+v2;
vpt->getGW()->polyline( 2, v, NULL, NULL, FALSE, NULL );
v[0] = axis;
v[1] = v1-v2;
vpt->getGW()->polyline( 2, v, NULL, NULL, FALSE, NULL );
}
void DrawAxis(ViewExp *vpt, const Matrix3 &tm, float length, BOOL screenSize)
{
Matrix3 tmn = tm;
float zoom;
// Get width of viewport in world units: --DS
zoom = vpt->GetScreenScaleFactor(tmn.GetTrans())*ZFACT;
if (screenSize) {
tmn.Scale( Point3(zoom,zoom,zoom) );
}
vpt->getGW()->setTransform( tmn );
Text( vpt, _T("x"), Point3(length,0.0f,0.0f) );
DrawAnAxis( vpt, Point3(length,0.0f,0.0f) );
Text( vpt, _T("y"), Point3(0.0f,length,0.0f) );
DrawAnAxis( vpt, Point3(0.0f,length,0.0f) );
Text( vpt, _T("z"), Point3(0.0f,0.0f,length) );
DrawAnAxis( vpt, Point3(0.0f,0.0f,length) );
}
//--- RB 7/17/2000: the code below seems to be unused ---------------------------------------------------
Box3 GetAxisBox(ViewExp *vpt, const Matrix3 &tm,float length,int resetTM)
{
Matrix3 tmn = tm;
Box3 box;
float zoom;
// Get width of viewport in world units: --DS
zoom = vpt->GetScreenScaleFactor(tmn.GetTrans())*ZFACT;
if (zoom==0.0f) zoom = 1.0f;
// tmn.Scale(Point3(zoom,zoom,zoom));
length *= zoom;
if(resetTM)
tmn.IdentityMatrix();
box += Point3(0.0f,0.0f,0.0f) * tmn;
box += Point3(length,0.0f,0.0f) * tmn;
box += Point3(0.0f,length,0.0f) * tmn;
box += Point3(0.0f,0.0f,length) * tmn;
box += Point3(-length/5.f,0.0f,0.0f) * tmn;
box += Point3(0.0f,-length/5.f,0.0f) * tmn;
box += Point3(0.0f,0.0f,-length/5.0f) * tmn;
box.EnlargeBy(10.0f/zoom);
return box;
}
inline void EnlargeRectIPoint3( RECT *rect, IPoint3& pt )
{
if ( pt.x < rect->left ) rect->left = pt.x;
if ( pt.x > rect->right ) rect->right = pt.x;
if ( pt.y < rect->top ) rect->top = pt.y;
if ( pt.y > rect->bottom ) rect->bottom = pt.y;
}
// This is a guess - need to find real w/h.
#define FONT_HEIGHT 11
#define FONT_WIDTH 9
static void AxisRect( GraphicsWindow *gw, Point3 axis, Rect *rect )
{
Point3 v1, v2, v;
IPoint3 iv;
v1 = axis * (float)0.9;
if ( axis.x != 0.0 || axis.y != 0.0 ) {
v2 = Point3( axis.y, -axis.x, axis.z ) * (float)0.1;
} else {
v2 = Point3( axis.x, axis.z, -axis.y ) * (float)0.1;
}
v = axis;
gw->wTransPoint( &v, &iv );
EnlargeRectIPoint3( rect, iv);
iv.x += FONT_WIDTH;
iv.y -= FONT_HEIGHT;
EnlargeRectIPoint3( rect, iv);
v = v1+v2;
gw->wTransPoint( &v, &iv );
EnlargeRectIPoint3( rect, iv);
v = v1-v2;
gw->wTransPoint( &v, &iv );
EnlargeRectIPoint3( rect, iv);
}
void AxisViewportRect(ViewExp *vpt, const Matrix3 &tm, float length, Rect *rect)
{
Matrix3 tmn = tm;
float zoom;
IPoint3 wpt;
Point3 pt;
GraphicsWindow *gw = vpt->getGW();
// Get width of viewport in world units: --DS
zoom = vpt->GetScreenScaleFactor(tmn.GetTrans())*ZFACT;
tmn.Scale( Point3(zoom,zoom,zoom) );
gw->setTransform( tmn );
pt = Point3(0.0f, 0.0f, 0.0f);
gw->wTransPoint( &pt, &wpt );
rect->left = rect->right = wpt.x;
rect->top = rect->bottom = wpt.y;
AxisRect( gw, Point3(length,0.0f,0.0f),rect );
AxisRect( gw, Point3(0.0f,length,0.0f),rect );
AxisRect( gw, Point3(0.0f,0.0f,length),rect );
rect->right += 2;
rect->bottom += 2;
rect->left -= 2;
rect->top -= 2;
}

95
source/tools/pmdexp/PSProp.h Executable file
View File

@ -0,0 +1,95 @@
#ifndef _PSPROP_H
#define _PSPROP_H
#include "MaxInc.h"
TCHAR *GetString(int id);
#define PSPROP_CLASS_ID Class_ID(0x353f201d, 0x3d01408d)
extern ClassDesc* GetPSPropDesc();
class PSPropObject : public HelperObject
{
public:
static IObjParam *ip;
static PSPropObject *editOb;
IParamBlock2 *pblock2;
// Class vars
/*
static HWND hParams;
static IObjParam *iObjParams;
static int dlgShowAxis;
static float dlgAxisLength;
*/
// Snap suspension flag (TRUE during creation only)
BOOL suspendSnap;
// Old params... these are for loading old files only. Params are now stored in pb2.
BOOL showAxis;
float axisLength;
// For use by display system
int extDispFlags;
// inherited virtual methods for Reference-management
RefResult NotifyRefChanged( Interval changeInt, RefTargetHandle hTarget,
PartID& partID, RefMessage message );
PSPropObject();
~PSPropObject();
// From BaseObject
int HitTest(TimeValue t, INode* inode, int type, int crossing, int flags, IPoint2 *p, ViewExp *vpt);
void Snap(TimeValue t, INode* inode, SnapInfo *snap, IPoint2 *p, ViewExp *vpt);
void SetExtendedDisplay(int flags);
int Display(TimeValue t, INode* inode, ViewExp *vpt, int flags);
CreateMouseCallBack* GetCreateMouseCallBack();
void BeginEditParams( IObjParam *ip, ULONG flags,Animatable *prev);
void EndEditParams( IObjParam *ip, ULONG flags,Animatable *next);
TCHAR *GetObjectName() {return GetString(IDS_POINT_HELPER_NAME);}
// From Object
ObjectState Eval(TimeValue time);
void InitNodeName(TSTR& s) { s = GetString(IDS_DB_POINT); }
ObjectHandle ApplyTransform(Matrix3& matrix) {return this;}
int CanConvertToType(Class_ID obtype) {return FALSE;}
Object* ConvertToType(TimeValue t, Class_ID obtype) {assert(0);return NULL;}
void GetWorldBoundBox(TimeValue t, INode *mat, ViewExp *vpt, Box3& box );
void GetLocalBoundBox(TimeValue t, INode *mat, ViewExp *vpt, Box3& box );
int DoOwnSelectHilite() { return 1; }
Interval ObjectValidity(TimeValue t);
int UsesWireColor() {return TRUE;}
// Animatable methods
void DeleteThis() { delete this; }
Class_ID ClassID() { return PSPROP_CLASS_ID; }
void GetClassName(TSTR& s) { s = TSTR(GetString(IDS_DB_POINTHELPER_CLASS)); }
int IsKeyable(){ return 0;}
int NumSubs() { return 1; }
Animatable* SubAnim(int i) { return pblock2; }
TSTR SubAnimName(int i) { return TSTR(_T("Parameters"));}
IParamArray *GetParamBlock();
int GetParamBlockIndex(int id);
int NumParamBlocks() { return 1; }
IParamBlock2* GetParamBlock(int i) { return pblock2; }
IParamBlock2* GetParamBlockByID(short id) { return pblock2; }
// From ref
RefTargetHandle Clone(RemapDir& remap = NoRemap());
IOResult Load(ILoad *iload);
IOResult Save(ISave *isave);
int NumRefs() {return 1;}
RefTargetHandle GetReference(int i) {return pblock2;}
void SetReference(int i, RefTargetHandle rtarg) {pblock2=(IParamBlock2*)rtarg;}
// Local methods
void InvalidateUI();
void UpdateParamblockFromVars();
int DrawAndHit(TimeValue t, INode *inode, ViewExp *vpt);
};
#endif

212
source/tools/pmdexp/Tree.h Executable file
View File

@ -0,0 +1,212 @@
#ifndef __TREE_H
#define __TREE_H
//////////////////////////////////////////////////////////////////////////////
// Tree: template class to build a binary tree of elements of class T
template <class T,class Cmp>
class Tree
{
public:
template <class T>
class Node {
public:
Node<T>* _Next;
public:
Node() : _Left(0), _Right(0) {}
int _Index;
T _Element;
Node<T>* _Left;
Node<T>* _Right;
};
public:
Tree();
~Tree();
void Clear();
int Find(T& element);
int Find(Node<T>* _node,T& _vtx);
int Add(T& element);
int Add(Node<T>* _node,T& _vtx,int _index);
// total nodes currently in tree
int Entries() { return _Size; }
void Reserve(int count) { _AllocatedNodes.reserve(count); }
T& operator[](int index) { return _AllocatedNodes[index]->_Element; }
private:
// the root node of the tree
Node<T>* _Root;
// all allocated nodes in tree
std::vector<Node<T>*> _AllocatedNodes;
// size of tree
int _Size;
// the comparison function used to compare two elements in the tree
Cmp _Cmp;
};
//***************************************************************************
// Default Tree constructor - create tree with no allocated nodes
//***************************************************************************
template <class T,class Cmp>
Tree<T,Cmp>::Tree()
{
_Root=0;
_Size=0;
}
//***************************************************************************
// Tree destructor
//***************************************************************************
template <class T,class Cmp>
Tree<T,Cmp>::~Tree()
{
Clear();
}
template <class T,class Cmp>
void Tree<T,Cmp>::Clear()
{
for (int i=0;i<_AllocatedNodes.Entries();i++) {
_NodePile.Release(_AllocatedNodes[i]);
}
_AllocatedNodes.SetSize(0);
_Root=0;
_Size=0;
}
//***************************************************************************
// Add : insert an element into the tree; return the index of the treenode
// at which the element was added, or, if an identical element was already
// in the tree, return it's index
//***************************************************************************
template <class T,class Cmp>
int Tree<T,Cmp>::Add(T& element)
{
if (_Root) {
int index=Add(_Root,element,_Size);
if (index==_Size) {
// element added to tree
_Size++;
} else {
// element not added
}
return index;
} else {
_Root=_NodePile.Allocate();
_AllocatedNodes.Add(_Root);
_Root->_Element=element;
_Root->_Index=0;
_Root->_Left=0;
_Root->_Right=0;
_Size++;
return 0;
}
}
//***************************************************************************
// Add : insert an element into the given node; return the index of the
// treenode at which the element was added, or, if an identical element was
// already in the tree, return it's index
//***************************************************************************
template <class T,class Cmp>
int Tree<T,Cmp>::Add(Node<T>* _node,T& element,int _index)
{
// compare given element with element at given node
int cmp=_Cmp.compare(_node->_Element,element);
if (cmp==0) {
// identical - return index of this node
return _node->_Index;
} else {
if (cmp==-1) {
// this node less than new node
if (_node->_Left) {
// send down left tree
return Add(_node->_Left,element,_index);
} else {
// no left node - create one
_node->_Left=_NodePile.Allocate();
_AllocatedNodes.Add(_node->_Left);
_node->_Left->_Element=element;
_node->_Left->_Index=_index;
_node->_Left->_Left=0;
_node->_Left->_Right=0;
return _index;
}
} else {
// this node greater than new node
if (_node->_Right) {
// send down right tree
return Add(_node->_Right,element,_index);
} else {
// no right node - create one
_node->_Right=_NodePile.Allocate();
_AllocatedNodes.Add(_node->_Right);
_node->_Right->_Element=element;
_node->_Right->_Index=_index;
_node->_Right->_Left=0;
_node->_Right->_Right=0;
return _index;
}
}
}
}
//***************************************************************************
// Find: try and find a matching element in the tree; return the index of the
// treenode at which a match was found, or -1 if no match found
//***************************************************************************
template <class T,class Cmp>
int Tree<T,Cmp>::Find(T& element)
{
return _Root ? Find(_Root,element) : -1;
}
//***************************************************************************
// Find: try and find a matching element in the given node; return the index
// of the treenode at which a match was found, or -1 if no match found
//***************************************************************************
template <class T,class Cmp>
int Tree<T,Cmp>::Find(Node<T>* _node,T& element)
{
// compare given element with element at given node
int cmp=_Cmp.compare(_node->_Element,element);
if (cmp==0) {
// identical - return index of this node
return _node->_Index;
} else {
if (cmp==-1) {
// this node less than new node
if (_node->_Left) {
// send down left tree
return Find(_node->_Left,element);
} else {
// no left node - no match on this subtree
return -1;
}
} else {
// this node greater than new node
if (_node->_Right) {
// send down right tree
return Find(_node->_Right,element);
} else {
// no left node - no match on this subtree
return -1;
}
}
}
}
#endif

56
source/tools/pmdexp/VNormal.cpp Executable file
View File

@ -0,0 +1,56 @@
#include "MaxInc.h"
#include "VNormal.h"
void VNormal::add(CVector3D& n,unsigned int s)
{
if (!(s&smooth) && init) {
if (next) {
next->add(n,s);
} else {
next=new VNormal(n,s);
}
} else {
_normal+=n;
smooth|=s;
init=true;
}
}
VNormal* VNormal::get(unsigned int s)
{
if (smooth&s || !next) {
return this;
} else {
return next->get(s);
}
}
void VNormal::get(unsigned int s,CVector3D& normal)
{
if (smooth&s || !next) {
normal=_normal;
} else {
next->get(s,normal);
}
}
void VNormal::normalize()
{
VNormal *ptr = next, *prev = this;
while (ptr) {
if (ptr->smooth&smooth) {
_normal += ptr->_normal;
prev->next = ptr->next;
delete ptr;
ptr = prev->next;
} else {
prev = ptr;
ptr = ptr->next;
}
}
_normal.Normalize();
if (next) next->normalize();
}

36
source/tools/pmdexp/VNormal.h Executable file
View File

@ -0,0 +1,36 @@
#ifndef __VNORMAL_H
#define __VNORMAL_H
#include "Vector3D.h"
class VNormal
{
public:
CVector3D _normal;
unsigned int smooth;
VNormal *next;
bool init;
VNormal() {
smooth=0;
next=0;
init=false;
_normal=CVector3D(0,0,0);
}
VNormal(CVector3D& n,unsigned int s) {
next=0;
init=true;
_normal=n;
smooth=s;
}
~VNormal() {delete next;}
void add(CVector3D &n,unsigned int s);
VNormal* get(unsigned int s);
void get(unsigned int s,CVector3D& normal);
void normalize();
};
#endif

158
source/tools/pmdexp/VertexTree.h Executable file
View File

@ -0,0 +1,158 @@
#ifndef __VERTEXTREE_H
#define __VERTEXTREE_H
// necessary includes
#include "ExpVertex.h"
////////////////////////////////////////////////////////////////////////////////////////////
// VertexTree: template tree class for building unique vertices in varying fashions; the
// template parameter Cmp specifies a function which compares (and possibly modifies)
// two vertices
// FIXME: ugh .. modifying a vertex already in the tree may cause it to be in the
// wrong position in the tree
template <class Cmp>
class VertexTree
{
private:
struct Node {
Node(int index,ExpVertex& vtx) : _index(index), _vertex(vtx), _left(0), _right(0) {}
// index into the output _vertices array
int _index;
// reference to actual vertex on the node (vertex itself in _vertices array)
ExpVertex& _vertex;
// children
Node* _left;
Node* _right;
};
public:
VertexTree(VertexList& vertices) : _vertices(vertices), _treeroot(0) {}
int insert(const ExpVertex& vtx) {
// copy incoming vertex in case the comparison function wants to modify
// it before storing it ..
ExpVertex copy=vtx;
if (_treeroot) {
return insert(_treeroot,copy);
} else {
_vertices.push_back(copy);
_treeroot=new Node(0,_vertices.back());
return 0;
}
}
int insert(Node* node,ExpVertex& vtx) {
// compare given element with element at given node
Cmp compareFn;
int cmp=compareFn(node->_vertex,vtx);
if (cmp==0) {
// matching vertex found
return node->_index;
} else {
if (cmp==-1) {
// this node less than new node
if (node->_left) {
// send down left tree
return insert(node->_left,vtx);
} else {
// no left node - create one
_vertices.push_back(vtx);
node->_left=new Node(_vertices.size()-1,_vertices.back());
return _vertices.size()-1;
}
} else {
// this node greater than new node
if (node->_right) {
// send down right tree
return insert(node->_right,vtx);
} else {
// no right node - create one
_vertices.push_back(vtx);
node->_right=new Node(_vertices.size()-1,_vertices.back());
return _vertices.size()-1;
}
}
}
}
private:
Node* _treeroot;
VertexList& _vertices;
};
class UniqueVertexCmp {
public:
int operator()(ExpVertex& left,ExpVertex& right) {
// check distance between two vertices ..
CVector3D vec3=left.m_Pos-right.m_Pos;
if (vec3.GetLength()>0.0001f) {
// vertices too far apart to weld .. sort on x,y,z
if (left.m_Pos[0]<right.m_Pos[0]) {
return -1;
} else if (left.m_Pos[0]>right.m_Pos[0]) {
return 1;
} else {
if (left.m_Pos[1]<right.m_Pos[1]) {
return -1;
} else if (left.m_Pos[1]>right.m_Pos[1]) {
return 1;
} else {
if (left.m_Pos[2]<right.m_Pos[2]) {
return -1;
} else {
return 1;
}
}
}
} else {
// weld two points together ..
right.m_Pos=left.m_Pos;
// .. and now compare by texcoords
CVector3D vec2(left.m_UVs[0]-right.m_UVs[0],left.m_UVs[1]-right.m_UVs[1],0);
if (vec2.GetLength()>0.0001f) {
// uvs too far apart to weld .. sort on u,v
if (left.m_UVs[0]<right.m_UVs[0]) {
return -1;
} else if (left.m_UVs[0]>right.m_UVs[0]) {
return 1;
} else {
if (left.m_UVs[1]<right.m_UVs[1]) {
return -1;
} else {
return 1;
}
}
} else {
// weld uvs
right.m_UVs[0]=left.m_UVs[0];
right.m_UVs[1]=left.m_UVs[1];
// compare normals
if (left.m_Normal[0]<right.m_Normal[0]) {
return -1;
} else if (left.m_Normal[0]>right.m_Normal[0]) {
return 1;
} else {
if (left.m_Normal[1]<right.m_Normal[1]) {
return -1;
} else if (left.m_Normal[1]>right.m_Normal[1]) {
return 1;
} else {
if (left.m_Normal[2]<right.m_Normal[2]) {
return -1;
} else if (left.m_Normal[2]>right.m_Normal[2]) {
return 1;
} else {
return 0;
}
}
}
}
}
}
};
#endif

View File

@ -0,0 +1,5 @@
SCC = This is a Source Code Control file
[dyexp.dsp]
SCC_Aux_Path = "D:\Program Files\Microsoft Visual Studio\Common\VSS\data"
SCC_Project_Name = "$/dev/src/tools/max/dyexp", YVAAAAAA

BIN
source/tools/pmdexp/pmdexp.smp Executable file

Binary file not shown.

54
source/tools/pmdexp/resource.h Executable file
View File

@ -0,0 +1,54 @@
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by PMDExp.rc
//
#define IDS_LIBDESCRIPTION 1
#define IDS_CATEGORY 2
#define IDS_CLASS_NAME 3
#define IDS_PMD_CLASS_NAME 3
#define IDS_PARAMS 4
#define IDS_SPIN 5
#define IDS_PSA_CLASS_NAME 6
#define IDD_PANEL 101
#define IDC_CLOSEBUTTON 1000
#define IDC_DOSTUFF 1000
#define IDC_COLOR 1456
#define IDC_EDIT 1490
#define IDC_SPIN 1496
#define IDD_NEW_POINTPARAM 118
#define IDC_POINT_SIZE 1059
#define IDC_POINT_SIZESPIN 1060
#define IDC_POINT_AXIS 1061
#define IDC_POINT_MARKER 1062
#define IDC_POINT_CROSS 1063
#define IDC_POINT_BOX 1064
#define IDC_POINT_SCREENSIZE 1065
#define IDC_POINT_DRAWONTOP 1066
#define IDS_DB_POINT 8
#define IDS_DB_POINTHELPER 9
#define IDS_DB_POINTHELPER_CLASS 10
#define IDS_DB_POINT_CLASS 11
#define IDS_POINT_PARAMS 18
#define IDS_POINT_SIZE 19
#define IDS_POINT_CENTERMARKER 20
#define IDS_POINT_AXISTRIPOD 21
#define IDS_POINT_CROSS 22
#define IDS_POINT_BOX 23
#define IDS_POINT_SCREENSIZE 24
#define IDS_POINT_HELPER_NAME 25
#define IDS_POINT_DRAWONTOP 26
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

BIN
source/tools/pmdexp/vssver.scc Executable file

Binary file not shown.