// Copyright (C) 2000 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
///////////////////////////////////////////////////////////////////////////////
// EXPORTER.CPP
//
// DESCR:
// Main MAX Class Implementation
//
// CHANGE LOG:
// 12/99 : DY : Created
// 09/2001 : rjc : modifications to bring it up to 3ds max r4.2 spec
//
///////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "exporter.h"
#include <time.h>
///////////////////////////////////////////////////////////////////////////////
// MAX Class Descriptor
//
///////////////////////////////////////////////////////////////////////////////
class MyExporterClassDesc : public ClassDesc2
{
public:
int IsPublic() { return TRUE; }
void * Create(BOOL loading) { return new MyExporter; }
const TCHAR * ClassName() { return GetString(IDS_CLASSNAME); }
SClass_ID SuperClassID() { return SCENE_EXPORT_CLASS_ID; }
Class_ID ClassID() { return MYEXP_CLASSID; }
const TCHAR* Category() { return _T(""); }
// Hardwired name, used by MAX Script as unique identifier (not localized)
const TCHAR* InternalName() { return _T("MyExporter"); }
HINSTANCE HInstance() { return g_hInstance; }
};
static MyExporterClassDesc g_ExportCD;
ClassDesc* GetSceneExportDesc()
{
return &g_ExportCD;
}
///////////////////////////////////////////////////////////////////////////////
// Constructor/Destructor
//
///////////////////////////////////////////////////////////////////////////////
MyExporter::MyExporter()
: m_exportSelected(false)
, m_suppressPrompts(false)
, m_ip(NULL)
, m_expip(NULL)
, m_fileStream(NULL)
{
}
MyExporter::~MyExporter()
{
}
///////////////////////////////////////////////////////////////////////////////
// (SceneExport overrides)
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Returns the number of file name extensions supported by the plug-in.
///////////////////////////////////////////////////////////////////////////////
int MyExporter::ExtCount()
{
return 1;
}
///////////////////////////////////////////////////////////////////////////////
// Returns the 'n-th' file name extension (i.e. "3DS").
///////////////////////////////////////////////////////////////////////////////
const TCHAR * MyExporter::Ext(int n)
{
switch(n) {
case 0:
return (_T(MYEXP_EXT));
}
return _T("");
}
///////////////////////////////////////////////////////////////////////////////
// Returns a long ASCII description of the file type being exported
// (i.e. "Autodesk 3D Studio File").
///////////////////////////////////////////////////////////////////////////////
const TCHAR * MyExporter::LongDesc()
{
// (NOTE: Unlike the extension, this, and various other subsequent
// description strings can be localized, so we keep 'em in the string table)
return GetString(IDS_LONGDESC);
}
///////////////////////////////////////////////////////////////////////////////
// Returns a short ASCII description of the file type being exported
// (i.e. "3D Studio").
///////////////////////////////////////////////////////////////////////////////
const TCHAR * MyExporter::ShortDesc()
{
return GetString(IDS_SHORTDESC);
}
///////////////////////////////////////////////////////////////////////////////
// Returns the ASCII Author name.
///////////////////////////////////////////////////////////////////////////////
const TCHAR * MyExporter::AuthorName()
{
return GetString(IDS_AUTHOR);
}
///////////////////////////////////////////////////////////////////////////////
// Returns the ASCII Copyright message for the plug-in.
///////////////////////////////////////////////////////////////////////////////
const TCHAR * MyExporter::CopyrightMessage()
{
return GetString(IDS_COPYRIGHT);
}
///////////////////////////////////////////////////////////////////////////////
// Returns the first message string that is displayed.
///////////////////////////////////////////////////////////////////////////////
const TCHAR * MyExporter::OtherMessage1()
{
return GetString(IDS_OTHER1);
}
///////////////////////////////////////////////////////////////////////////////
// Returns the second message string that is displayed.
///////////////////////////////////////////////////////////////////////////////
const TCHAR * MyExporter::OtherMessage2()
{
return GetString(IDS_OTHER2);
}
///////////////////////////////////////////////////////////////////////////////
// Returns the version number of the export plug-in.
// The format is the version number * 100 (i.e. v3.01 = 301).
///////////////////////////////////////////////////////////////////////////////
unsigned int MyExporter::Version()
{
return MYEXP_VER;
}
///////////////////////////////////////////////////////////////////////////////
// About box Dialog handler
///////////////////////////////////////////////////////////////////////////////
static BOOL CALLBACK AboutDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
MyExporter * myexp = (MyExporter*)GetWindowLong(hWnd,GWL_USERDATA);
if (!myexp && msg != WM_INITDIALOG)
return FALSE;
switch (msg) {
case WM_INITDIALOG:
// Update class pointer
myexp = (MyExporter*)lParam;
SetWindowLong(hWnd,GWL_USERDATA,lParam);
break;
case WM_DESTROY:
break;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
EndDialog(hWnd,1);
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
// Show the aboutbox
///////////////////////////////////////////////////////////////////////////////
void MyExporter::ShowAbout(HWND hWnd)
{
DialogBoxParam(g_hInstance,
MAKEINTRESOURCE(IDD_ABOUT),
hWnd,
AboutDlgProc,
(LPARAM)this);
}
///////////////////////////////////////////////////////////////////////////////
// This method is called for the plug-in to perform its file export.
///////////////////////////////////////////////////////////////////////////////
int MyExporter::DoExport(const TCHAR *name, ExpInterface *ei, Interface *i, BOOL suppressPrompts, DWORD options)
{
TCHAR buf[256];
// cache export session stuff for utility methods
m_exportSelected = (options & SCENE_EXPORT_SELECTED);
m_suppressPrompts = !!suppressPrompts;
m_ip = i;
m_expip = ei;
// open file
m_fileStream = ::_tfopen(name, _T("wt"));
if (!m_fileStream) {
::sprintf(buf, GetString(IDS_OPENFILEERR), name);
::MessageBox(i->GetMAXHWnd(), buf, GetString(IDS_EXPCAPTION), MB_OK | MB_ICONSTOP);
return FALSE; // fail
}
// get and write out "global" header information
DoHeader();
// get and write out scene information
DoNodes();
// get and write out tailer information (if any)
DoTailer();
// close file
::fclose(m_fileStream);
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
// (utility fcns)
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// This method is called by MAX to determine if one or more export options are
// supported by a plug-in for a given extension.
// It should return TRUE if all option bits set are supported for this
// extension; otherwise FALSE.
///////////////////////////////////////////////////////////////////////////////
BOOL MyExporter::SupportsOptions(int ext, DWORD options)
{
// (from the SDK helpfile)
// "This parameter [options] specifies which options are being queried,
// and may have more than one option specified. At present,
// the only export option is SCENE_EXPORT_SELECTED, but this may
// change in the future. If more than one option is specified in
// this field, the plugin should only return TRUE if all of the
// options are supported. If one or more of the options are not
// supported, the plugin should return FALSE."
if (options & SCENE_EXPORT_SELECTED)
return TRUE;
else
return FALSE;
}
///////////////////////////////////////////////////////////////////////////////
// Utility fcn to enumerate over nodes
///////////////////////////////////////////////////////////////////////////////
void MyExporter::DoHeader()
{
// write out a basic header line
struct tm *newtime;
time_t aclock;
char buf[256];
::time(&aclock);
newtime = ::localtime(&aclock);
::strcpy(buf, ::asctime(newtime));
buf[strlen(buf) - 1] = '\0'; // remove extra newline
::fprintf(m_fileStream, "BEGIN MYEXPORTER Version:<%d> Date:<%s>\n",MYEXP_VER,buf);
// write out basic header info here
::fprintf(m_fileStream, "BEGIN HEADER\n");
// export material info used in scene
MtlBaseLib * scenemats = m_ip->GetSceneMtls();
int i,j; // for loops
if (scenemats) {
for (i = 0; i < scenemats->Count(); i++) {
// DoSomething(scenemats[i]);
MtlBase * mtl = (*scenemats)[i];
::fprintf(m_fileStream, "BEGIN MTL Name:<%s> FullName:<%s>\n", mtl->GetName(), mtl->GetFullName());
if (IsMtl(mtl) && mtl->IsMultiMtl()) {
// multi-mtl
Mtl * m = (Mtl *)mtl;
::fprintf(m_fileStream, " multimtl -- submtls:\n");
for (j = 0; j < m->NumSubMtls(); j++) {
Mtl *sm = m->GetSubMtl(j);
if (sm) {
// NOTE: For this tutorial, we only go one "level" deep
::fprintf(m_fileStream, " Name:<%s>\n", sm->GetName());
}
}
} else {
// submtls or texmaps
for (j = 0; j < mtl->NumSubTexmaps(); j++) {
Texmap * tmap = mtl->GetSubTexmap(j);
if (tmap) {
// NOTE: For this tutorial, we only go one subtex "level"
// deep, although in reality, we can go much deeper
// (e.g. mtl with checker diffuse, that in turn has another
// checker as a subtex, etc)
::fprintf(m_fileStream, " subtex -- Name:<%s> UVWSrc:<%d> MapChannel:<%d> \n", tmap->GetName(), tmap->GetUVWSource(), tmap->GetMapChannel());
// for this sample, if one of the first level subtex's is a
// bitmaptex, dump out some more info. It should be clear
// that similar actions can be taken with other typical subtexs
// (RGBMult, etc)
if (tmap->ClassID() == Class_ID(BMTEX_CLASS_ID, 0)) {
BitmapTex *bmt = (BitmapTex*) tmap;
::fprintf(m_fileStream, " Bitmap Tex -- File:<%s>\n", bmt->GetMapName());
// (Sidenote: There are supposedly some cases where this
// might not return the full filename + path)
}
}
}
}
::fprintf(m_fileStream, "END MTL\n");
}
}
// export ambient scene light
Color ambLight = m_ip->GetAmbient(m_ip->GetTime(), FOREVER);
COLORREF ambColor = (DWORD)ambLight;
::fprintf(m_fileStream,"AMBIENT LIGHT rgb:<%d,%d,%d>\n",
GetRValue(ambColor), GetGValue(ambColor), GetBValue(ambColor));
::fprintf(m_fileStream, "END HEADER\n");
}
void MyExporter::DoNodes()
{
// walk the scene or selected nodes and export the desired information
int numChildren = m_ip->GetRootNode()->NumberOfChildren();
// Call our node enumerator.
// The nodeEnum function will recurse into itself and
// export each object found in the scene.
for (int idx = 0; idx < numChildren; idx++) {
if (m_ip->GetCancel())
break;
nodeEnum(m_ip->GetRootNode()->GetChildNode(idx));
}
}
void MyExporter::DoTailer()
{
::fprintf(m_fileStream, "END MYEXPORTER\n");
}
BOOL MyExporter::nodeEnum(INode* node)
{
if (!node)
return FALSE;
// if we're only exporting selected nodes, and
// the given node isn't selected, skip it
if (m_exportSelected && node->Selected() == FALSE)
return FALSE;
// Stop recursing if the user pressed Cancel
if (m_ip->GetCancel())
return FALSE;
// The ObjectState is a 'thing' that flows down the pipeline containing
// all information about the object. By calling EvalWorldState() we tell
// max to eveluate the object at end of the pipeline.
ObjectState os = node->EvalWorldState(m_ip->GetTime());
// The obj member of ObjectState is the actual object we will export.
if (os.obj) {
// We look at the super class ID to determine the type of the object.
switch(os.obj->SuperClassID()) {
case GEOMOBJECT_CLASS_ID:
ExportGeomObject(node);
break;
case LIGHT_CLASS_ID:
ExportLightObject(node);
break;
default:
break;
}
}
// For each child of this node, we recurse into ourselves
// until no more children are found.
for (int c = 0; c < node->NumberOfChildren(); c++) {
if (!nodeEnum(node->GetChildNode(c)))
return FALSE;
}
return TRUE;
}
void MyExporter::ExportGeomObject(INode * node)
{
int i; // for loops
Point3 vert;
int numTVerts, chanloop;
TimeValue currtime = m_ip->GetTime();
ObjectState os = node->EvalWorldState(currtime);
if (!os.obj)
return;
// Target camera "targets" are actually geomobjects, so we skip them here.
if (os.obj->ClassID() == Class_ID(TARGET_CLASS_ID, 0))
return;
::fprintf(m_fileStream, "BEGIN GEOMOBJECT Name:<%s>\n",node->GetName());
///////////////////////////////////
// dump mtl info for this node
Mtl * nodemtl = node->GetMtl();
if (nodemtl) {
::fprintf(m_fileStream, " mtl -- name:<%s>\n", nodemtl->GetName());
} else {
// no mat assigned to node, print out 0-255 RGB color
DWORD col = node->GetWireColor();
::fprintf(m_fileStream," color -- rgb:<%d,%d,%d>\n",
GetRValue(col), GetGValue(col), GetBValue(col));
}
///////////////////////////////////
// get and dump the node matrix, mainly for xform and rot info
Matrix3 nodepivot = node->GetNodeTM(currtime);
Point3 row;
row = nodepivot.GetRow(0);
::fprintf(m_fileStream,"BEGIN TM\n Row 0:<%f,%f,%f>\n", row.x, row.y, row.z);
row = nodepivot.GetRow(1);
::fprintf(m_fileStream," Row 1:<%f,%f,%f>\n", row.x, row.y, row.z);
row = nodepivot.GetRow(2);
::fprintf(m_fileStream," Row 2:<%f,%f,%f>\n", row.x, row.y, row.z);
row = nodepivot.GetRow(3);
::fprintf(m_fileStream," Row 3:<%f,%f,%f>\nEND TM\n", row.x, row.y, row.z);
///////////////////////////////////
// export geometric data
Matrix3 tm = node->GetObjTMAfterWSM(currtime);
if (os.obj->ClassID() == Class_ID(PATCHOBJ_CLASS_ID, 0) ||
os.obj->ClassID() == Class_ID(PATCHGRID_CLASS_ID, 0)) {
// Patches
bool delPatch = false;
Object *obj = os.obj;
if (obj && obj->CanConvertToType(Class_ID(PATCHOBJ_CLASS_ID, 0))) {
PatchObject * patchobj = NULL;
patchobj = (PatchObject *) obj->ConvertToType(0, Class_ID(PATCHOBJ_CLASS_ID, 0));
if (obj != patchobj)
delPatch = true; // we own the copy
if (patchobj) {
PatchMesh * patchmesh = &(patchobj->patch);
::fprintf(m_fileStream, "BEGIN PATCH NumVerts:<%d> NumVecs:<%d> NumPatches:<%d> NumEdges:<%d>\n",
patchmesh->getNumVerts(),
patchmesh->getNumVecs(),
patchmesh->getNumPatches(),
patchmesh->getNumEdges());
// export vertices
for (i = 0; i < patchmesh->getNumVerts(); i++) {
vert = tm * patchmesh->getVert(i).p;
::fprintf(m_fileStream, " vertex %d -- pos:<%f,%f,%f> veccount:<%d>\n", i, vert.x, vert.y, vert.z, patchmesh->getVert(i).vectors.Count());
}
// export vectors
for (i = 0; i < patchmesh->getNumVecs(); i++) {
vert = patchmesh->getVec(i).p;
::fprintf(m_fileStream, " vector %d -- vec:<%f,%f,%f> vertind:<%d>\n", i, vert.x, vert.y, vert.z, patchmesh->getVec(i).vert);
}
// export edges
for (i = 0; i < patchmesh->getNumEdges(); i++) {
PatchEdge * workedge = &(patchmesh->edges[i]);
if (workedge)
::fprintf(m_fileStream, " edge %d -- vertind:<%d,%d> vecind:<%d,%d> patchind:<%d,%d>\n", i, workedge->v1, workedge->v2, workedge->vec12, workedge->vec21, workedge->patches[0], workedge->patches[1]);
}
// export patches
for (i = 0; i < patchmesh->getNumPatches(); i++) {
Patch * workpatch = &(patchmesh->patches[i]);
if (workpatch) {
if (workpatch->type == PATCH_TRI) {
::fprintf(m_fileStream, " tripatch %d -- ",i);
// get corner vert indices
::fprintf(m_fileStream, " vertind:<%d,%d,%d>",
workpatch->v[0], workpatch->v[1], workpatch->v[2]);
// get tangent vector indices
::fprintf(m_fileStream, " vecind:<%d,%d,%d,%d,%d,%d>",
workpatch->vec[0],
workpatch->vec[1],
workpatch->vec[2],
workpatch->vec[3],
workpatch->vec[4],
workpatch->vec[5]);
// get interior vert indices
::fprintf(m_fileStream, " internal vertind:<%d,%d,%d>",
workpatch->interior[0], workpatch->interior[1], workpatch->interior[2]);
// get edge indices
::fprintf(m_fileStream, " edge ind:<%d,%d,%d>",
workpatch->edge[0], workpatch->edge[1], workpatch->edge[2]);
::fprintf(m_fileStream, "\n");
} else if (workpatch->type == PATCH_QUAD) {
::fprintf(m_fileStream, " quadpatch %d -- ",i);
// get corner vert indices
::fprintf(m_fileStream, " vertind:<%d,%d,%d,%d>", workpatch->v[0], workpatch->v[1], workpatch->v[2], workpatch->v[3]);
// get tangent vector indices
::fprintf(m_fileStream, " vecind:<%d,%d,%d,%d,%d,%d,%d,%d>",
workpatch->vec[0],
workpatch->vec[1],
workpatch->vec[2],
workpatch->vec[3],
workpatch->vec[4],
workpatch->vec[5],
workpatch->vec[6],
workpatch->vec[7]);
// get interior vert indices
::fprintf(m_fileStream, " internal vertind:<%d,%d,%d,%d>", workpatch->interior[0], workpatch->interior[1], workpatch->interior[2], workpatch->interior[3]);
// get edge indices
::fprintf(m_fileStream, " edge ind:<%d,%d,%d,%d>", workpatch->edge[0], workpatch->edge[1], workpatch->edge[2], workpatch->edge[3]);
::fprintf(m_fileStream, "\n");
} // (otherwise, unknown type, don't output)
}
}
// export patch texture vertices info
// first, channel 1
numTVerts = patchmesh->getNumTVerts();
if (numTVerts) {
::fprintf(m_fileStream, " texture channel 1 -- numverts:<%d>\n", numTVerts);
for (i = 0; i < numTVerts; i++) {
UVVert tvert = patchmesh->getTVert(i);
::fprintf(m_fileStream, " UVW tvert %d:<%f,%f,%f>\n", i, tvert.x, tvert.y, tvert.z);
}
// now, print tvert indices used by tvpatches (always 4)
for (i = 0; i < patchmesh->getNumPatches(); i++) {
TVPatch tvpatch = patchmesh->getTVPatch(i);
::fprintf(m_fileStream, " TVPatch %d -- tvertind:<%d,%d,%d,%d>\n",
tvpatch.tv[0], tvpatch.tv[1], tvpatch.tv[2], tvpatch.tv[3]);
}
}
// now, rest of channels
for (chanloop = 2; chanloop < MAX_MESHMAPS - 1; chanloop++) {
numTVerts = patchmesh->getNumMapVerts(chanloop);
if (numTVerts > 0) {
::fprintf(m_fileStream, " texture channel %d -- numverts:<%d>\n", chanloop, numTVerts);
for (i = 0; i < numTVerts; i++) {
UVVert tvert = patchmesh->getMapVert(chanloop, i);
::fprintf(m_fileStream, " UVW tvert %d:<%f,%f,%f>\n", i, tvert.x, tvert.y, tvert.z);
}
// now, print tvert indices used by tvpatches
for (i = 0; i < patchmesh->getNumPatches(); i++) {
TVPatch tvpatch = patchmesh->getTVPatchChannel(chanloop,i);
::fprintf(m_fileStream, " TVPatch %d -- tvertind:<%d,%d,%d,%d>\n",
tvpatch.tv[0], tvpatch.tv[1], tvpatch.tv[2], tvpatch.tv[3]);
}
}
}
::fprintf(m_fileStream, "END PATCH\n");
// del patchobject, if it was generated
if (delPatch)
delete patchobj;
}
}
} else {
// Treat everything else as trimeshes (geomobjects should all
// be able to convert themselves at least. If we just wanted
// collapsed meshes, we could check for TRIOBJ_CLASS_ID)
// first, get the triobject mesh
bool delMesh = false;
Object *obj = os.obj;
if (obj && obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0))) {
TriObject * tri = NULL;
tri = (TriObject *) obj->ConvertToType(0, Class_ID(TRIOBJ_CLASS_ID, 0));
if (obj != tri)
delMesh = true; // we own the copy
if (tri) {
Mesh * mesh = &(tri->GetMesh());
assert(mesh);
mesh->buildNormals();
::fprintf(m_fileStream, "BEGIN MESH NumVerts:<%d> NumFaces:<%d>\n",mesh->getNumVerts(),mesh->getNumFaces());
// Export the vertices
for (i = 0; i < mesh->getNumVerts(); i++) {
vert = tm * mesh->verts[i];
::fprintf(m_fileStream, " vertex %d:<%f,%f,%f>\n", i, vert.x, vert.y, vert.z);
}
// export faces
for (i = 0; i < mesh->getNumFaces(); i++) {
::fprintf(m_fileStream, " face %d -- verts:<%d,%d,%d> edgevis:<%d,%d,%d> smoothgrp:<0x%x> matid:<%d>\n", i,
mesh->faces[i].v[0],
mesh->faces[i].v[1],
mesh->faces[i].v[2],
mesh->faces[i].getEdgeVis(0) ? 1 : 0,
mesh->faces[i].getEdgeVis(1) ? 1 : 0,
mesh->faces[i].getEdgeVis(2) ? 1 : 0,
mesh->faces[i].getSmGroup(),
mesh->faces[i].getMatID());
}
// export texture vertices info (note: assumes not using face mapping)
// (for MAX 3, we iterate over texture channels, but not color-per-vert
// channel)
// first, channel 1, the regular UV channel
numTVerts = mesh->getNumTVerts();
if (numTVerts) {
::fprintf(m_fileStream, " texture channel 1 -- numverts:<%d>\n", numTVerts);
for (i = 0; i < numTVerts; i++) {
UVVert tvert = mesh->tVerts[i];
::fprintf(m_fileStream, " UVW tvert %d:<%f,%f,%f>\n", i, tvert.x, tvert.y, tvert.z);
}
// now, print tvert indices used by tvfaces
for (i = 0; i < mesh->getNumFaces(); i++) {
TVFace tface = mesh->tvFace[i];
::fprintf(m_fileStream, " TVFace %d -- tvertind:<%d,%d,%d>\n",
i, tface.t[0], tface.t[1], tface.t[2]);
}
}
// now, rest of channels
for (chanloop = 2; chanloop < MAX_MESHMAPS - 1; chanloop++) {
if (mesh->mapSupport(chanloop)) {
numTVerts = mesh->getNumMapVerts(chanloop);
::fprintf(m_fileStream, " texture channel %d -- numverts:<%d>\n", chanloop, numTVerts);
for (i = 0; i < numTVerts; i++) {
UVVert tvert = mesh->mapVerts(chanloop)[i];
::fprintf(m_fileStream, " UVW tvert %d:<%f,%f,%f>\n", i, tvert.x, tvert.y, tvert.z);
}
// now, print tvert indices used by tvfaces
for (i = 0; i < mesh->getNumFaces(); i++) {
TVFace tface = mesh->mapFaces(chanloop)[i];
::fprintf(m_fileStream, " TVFace %d -- tvertind:<%d,%d,%d>\n",
i, tface.t[0], tface.t[1], tface.t[2]);
}
}
}
::fprintf(m_fileStream, "END MESH\n");
// del triobject, if it was generated
if (delMesh)
delete tri;
}
}
}
::fprintf(m_fileStream, "END GEOMOBJECT\n");
}
void MyExporter::ExportLightObject(INode * node)
{
TimeValue currtime = m_ip->GetTime();
ObjectState os = node->EvalWorldState(currtime);
if (!os.obj)
return;
GenLight* light = (GenLight*)os.obj;
struct LightState ls;
light->EvalLightState(currtime, FOREVER, &ls);
if (! light->GetUseLight())
return; // only export lights that are on for simplicity
::fprintf(m_fileStream, "BEGIN LIGHT Name:<%s> Type:<",node->GetName());
// light type
switch(light->Type()) {
case OMNI_LIGHT:
fprintf(m_fileStream, "OMNI>\n");
break;
case TSPOT_LIGHT:
fprintf(m_fileStream, "TARGET SPOT>\n");
break;
case DIR_LIGHT:
fprintf(m_fileStream, "DIRECTIONAL>\n");
break;
case FSPOT_LIGHT:
fprintf(m_fileStream, "FREE SPOT>\n");
break;
case TDIR_LIGHT:
default:
fprintf(m_fileStream, "TARGETED DIRECTIONAL>\n");
break;
}
///////////////////////////////////
// color, intensity info
COLORREF lightcol = (DWORD)ls.color;
::fprintf(m_fileStream," light color -- rgb:<%d,%d,%d>\n",
GetRValue(lightcol), GetGValue(lightcol), GetBValue(lightcol));
::fprintf(m_fileStream," light intensity -- mult:<%f>\n", ls.intens);
///////////////////////////////////
// get and dump the node matrix, mainly for xform and rot info
// also dump target TM, if the light has a target
Matrix3 nodepivot = node->GetNodeTM(currtime);
Point3 row;
row = nodepivot.GetRow(0);
::fprintf(m_fileStream,"BEGIN TM\n Row 0:<%f,%f,%f>\n", row.x, row.y, row.z);
row = nodepivot.GetRow(1);
::fprintf(m_fileStream," Row 1:<%f,%f,%f>\n", row.x, row.y, row.z);
row = nodepivot.GetRow(2);
::fprintf(m_fileStream," Row 2:<%f,%f,%f>\n", row.x, row.y, row.z);
row = nodepivot.GetRow(3);
::fprintf(m_fileStream," Row 3:<%f,%f,%f>\nEND TM\n", row.x, row.y, row.z);
INode* target = node->GetTarget();
if (target) {
nodepivot = target->GetNodeTM(currtime);
row = nodepivot.GetRow(0);
::fprintf(m_fileStream,"BEGIN TARGET TM\n Row 0:<%f,%f,%f>\n", row.x, row.y, row.z);
row = nodepivot.GetRow(1);
::fprintf(m_fileStream," Row 1:<%f,%f,%f>\n", row.x, row.y, row.z);
row = nodepivot.GetRow(2);
::fprintf(m_fileStream," Row 2:<%f,%f,%f>\n", row.x, row.y, row.z);
row = nodepivot.GetRow(3);
::fprintf(m_fileStream," Row 3:<%f,%f,%f>\nEND TARGET TM\n", row.x, row.y, row.z);
}
///////////////////////////////////
// export shadow info, if applicable
if (light->GetShadow()) {
int shadtype = light->GetShadowType();
::fprintf(m_fileStream," shadow -- type:<");
switch (shadtype) {
case -1:
::fprintf(m_fileStream, "GENERATOR (null)>\n");
break;
case 0:
::fprintf(m_fileStream, "SHADOW MAPS>\n");
break;
case 1:
::fprintf(m_fileStream, "RAYTRACED>\n");
break;
default:
::fprintf(m_fileStream, "GENERATOR (0x%x)>\n", shadtype);
break;
}
}
::fprintf(m_fileStream, "END LIGHT\n");
}