JurassicParkTrespasser/jp2_pc/Source/Tools/GroffExp/GroffExp.cpp

3732 lines
103 KiB
C++
Raw Permalink Normal View History

2018-01-01 22:07:24 +00:00
/**********************************************************************************************
* Copyright (c) DreamWorks Interactive. 1996
*
* Implementation of module GroffExp.
*
* Bugs:
*
* To do:
*
* 1. Make sure the vertex and face normals are properly exteracted from the iNodes.
*
* 2. Add support to allow the user to move the pivot point without moving the geometry as it
* appears within the GUIApp.
*
**********************************************************************************************
*
* $Log:: /JP2_PC/Source/Tools/GroffExp/GroffExp.cpp $
*
* 21 7/15/97 6:58p Gstull
* Made organizational changes to make management of the exporter more reasonable.
*
* 20 7/14/97 3:36p Gstull
* Made substantial changes to support tasks for the August 18th milestone for attributes,
* object representation, geometry checking, dialog interfacing, logfile support, string tables
* and string support.
*
* 19 6/18/97 7:33p Gstull
* Added changes to support fast exporting.
*
* 18 4/15/97 10:43p Gstull
* Added changes to support export options specified in a dialog box at export time.
*
* 17 4/14/97 7:44p Gstull
* Added changes to support log file management,
*
* 16 3/19/97 6:09p Gstull
* Fixed bugs #18 qnd #19. Fixes resolved problems detecting and reporting material ID range
* errors and objects without geometry.
*
* 15 2/25/97 7:51p Gstull
* Resolved issues with proper object placement in the scene and object validation.
*
* 14 2/24/97 8:03p Gstull
* Changed the target file paths in the exporter to use the relative paths instead.
*
* 13 2/21/97 6:55p Gstull
* Added code to perform a number of additional checks
* on data as well as a new GUI interface class, removal
* of the bump map hack.
*
* 12 12/16/96 11:19p Gstull
* Added progress status bar for Kyle.
*
* 11 12/16/96 3:04p Gstull
* Added fix to force Process_Bitmap to use a temporary palette for loading the transparency
* palette rather than the quantization palette.
*
* 10 12/16/96 11:22a Gstull
* Made changes to support quantization to a single palette.
*
* 9 11/26/96 6:07p Gstull
* Added changes to the file IO for support of write of 0 bytes to sections.
*
* 8 11/20/96 1:13p Gstull
* Slight modifications to the Groff structures for integration into the GUIApp.
*
* 7 11/15/96 7:29p Gstull
* File changes to create initial version of the multi-section groff loader.
*
* 6 11/15/96 11:08a Gstull
* Added substantial changes to the GroffExporter including for support of mutiple section
* files.
*
* 5 11/06/96 7:27p Gstull
* Latest version of groff file exporter. Now handles transparency maps, texture maps and bump
* maps with color quantization.
*
* 4 11/04/96 8:34p Gstull
* Latest version of the new bitmap exporter stuff.
*
* 2 9/16/96 8:27p Gstull
* Update the paths to be project relative.
*
* 1 9/16/96 2:56p Gstull
*
*********************************************************************************************/
#include <stdio.h>
#include <stdarg.h>
//**********************************************************************************************
// Include the main 3D Studio MAX include file.
//
#include "Max.h"
//**********************************************************************************************
// Include file generated by the developer studio containing the #defines for the resources.
//
#include "GroffExp.h"
//**********************************************************************************************
// 3d Studio Max SDK include files.
//
#include "bmmlib.h"
#include "stdmat.h"
#include "istdplug.h"
//**********************************************************************************************
// Jurassic Park II - Trespasser include files.
//
#include "StandardTypes.hpp"
#include "ObjectDef.hpp"
#include "Geometry.hpp"
#include "Lib/Sys/SysLog.hpp"
#include "Bitmap.hpp"
#include "Lib/Sys/Symtab.hpp"
2018-01-01 22:07:24 +00:00
#include "Export.hpp"
#include "GUIInterface.hpp"
#include "Mathematics.hpp"
#include "Lib/Groff/EasyString.hpp"
//**********************************************************************************************
// Local definitions for the export plugin.
//
#define EXPORTER_VERSION_NUMBER 110
//**********************************************************************************************
// Define global classes for this DLL.
//
CGUIInterface guiInterface;
CSysLog slLogfile;
//*********************************************************************************************
// This class forms the interface which is used by 3D Studio MAX to export scenes, from the
// internal representation to a user define format for external use. This interface is NOT
// intended to be used by users directly and should only be invoked by 3D Studio MAX.
//
// Example:
// Since this class forms a DLL, it is called exclusively by 3D Studio MAX during a scene
// export request made by the user.
//
class JP2Export : public SceneExport
//
// Prefix:
//
{
protected:
char shortdesc[40];
public:
//******************************************************************************************
// Constructor.
//
JP2Export
(
)
{
shortdesc[0] = 0;
};
//******************************************************************************************
// Destructor.
//
~JP2Export
(
)
{
};
//******************************************************************************************
// Number of extensions supported by this plug-in.
//
int ExtCount
(
)
{
// Currently there is only one format supported.
return 1;
}
//******************************************************************************************
// Extension number 0 (i.e. "GRF")
//
const TCHAR* Ext
(
int n
);
//******************************************************************************************
// Long ASCII file export description.
//
const TCHAR* LongDesc
(
);
//******************************************************************************************
// Short ASCII file export description.
//
const TCHAR* ShortDesc
(
);
//******************************************************************************************
// ASCII Author name.
//
const TCHAR* AuthorName
(
);
//******************************************************************************************
// ASCII Copyright message.
//
const TCHAR* CopyrightMessage
(
);
//******************************************************************************************
// Other message #1.
//
const TCHAR* OtherMessage1
(
)
{
return _T("");
}
//******************************************************************************************
// Other message #2.
//
const TCHAR* OtherMessage2
(
)
{
return _T("");
}
//******************************************************************************************
// Version number * 100 (i.e. v3.01 = 301).
//
unsigned int Version
(
);
//******************************************************************************************
// Export the object into a file.
//
void ShowAbout
(
HWND hWnd
);
//******************************************************************************************
// Export the object into a file.
//
int DoExport
(
const TCHAR* tchr_export_name, // File name and path to export to.
ExpInterface* pei_export_interface, // Class for enumerating the nodes in the scene.
Interface* pip_interface // Interface pointer for calling MAX API's.
);
};
//*********************************************************************************************
//
class CClassDesc: public ClassDesc
//
// Prefix: cldlg
//
// This class implements the virtual functions which describe the features and capabilities of
// the export plugin to 3D Studio Max.
//
//
//*********************************************************************************************
{
public:
2018-01-01 22:07:24 +00:00
//******************************************************************************************
//
int IsPublic
(
)
{
return true;
}
//******************************************************************************************
//
void* Create
(
BOOL loading = false
2018-01-01 22:07:24 +00:00
)
{
return new JP2Export;
}
//******************************************************************************************
//
const TCHAR* ClassName
(
)
{
return guiInterface.strGetString(IDS_JP2_CLASSNAME);
}
//******************************************************************************************
//
SClass_ID SuperClassID
(
)
{
return SCENE_EXPORT_CLASS_ID;
}
//******************************************************************************************
//
Class_ID ClassID
(
)
{
return Class_ID(0x297455F, 0x17C9693D);
}
//******************************************************************************************
//
const TCHAR* Category
(
)
{
return guiInterface.strGetString(IDS_JP2_EXPORTER);
}
};
static CClassDesc cld_jp2_desc;
//*********************************************************************************************
//
class CObjectEntry
//
// Prefix: obe
//
// This class keeps track of the objects which are deemed to be 'exportable' to the outside
// world. In the simplest case, this would include objects which can be converted to a trimesh
// object.
//
// Example:
//
//*********************************************************************************************
{
public:
TSTR tstrName; // Node's object name.
INode* pinINode; // INode of the object.
Object* pobjObject; // Object.
int iType; // OBTYPE_MESH, OBTYPE_BONE
CObjectEntry* pobeNext; // Next scene entry node in the list.
public:
//******************************************************************************************
//
CObjectEntry
(
INode* pin_node,
Object* pobj_object,
int i_type
);
};
//**********************************************************************************************
//
CObjectEntry::CObjectEntry
(
INode* pin_node,
Object* pobj_object,
int i_type
)
{
pinINode = pin_node; // Setup a pointer to the INode.
pobjObject = pobj_object; // Setup a pointer to the object.
iType = i_type; // The object type (i.e. tri-mesh).
pobeNext = 0; // Terminate the next node pointer.
}
//**********************************************************************************************
//
class CSceneEnumProc : public ITreeEnumProc
//
// Prefix: sep
//
// This class is dreived from the base class iTreeEnumProc, which passes each of the INodes in
// the scene to the exporter through the 'callback' procedure. The callback then determines
// which objects can be converted to a tri-mesh object, and can then be exported.
//
// Example:
//
//**********************************************************************************************
{
private:
uint uNodeCount; // The number of nodes in the list.
public:
TimeValue tvTime; // The actual time when the export occurred.
IScene* theScene; // A pointe
Interface* pipInterface; // Pointer to the interface structure.
CObjectEntry* pobeHead; // Pointer to the first object entry in the list.
CObjectEntry* pobeTail; // Pointer to the last object entry in the list.
//*****************************************************************************************
// Constructors.
//
CSceneEnumProc
(
IScene* pis_scene,
TimeValue tv_time,
Interface* pip_interface
);
//*****************************************************************************************
// Destructors.
//
~CSceneEnumProc
(
);
//*****************************************************************************************
// This function is serves as the callback function which determines which objects in
// the scene are passed to the exporter. It is this procedure which builds the list of
// of objects which the exporter eventually exports.
//
// Note: It is not clear to me at this point why this call is necessary. It seems to be
// unnecessary since selection of the objects which are the objects could
//
int callback
(
INode* pin_inode
);
//*****************************************************************************************
//
void Append
(
INode* pin_inode,
Object* pobj_object,
int i_type
);
//*****************************************************************************************
//
CObjectEntry* pobeLookup
(
INode* pin_inode
);
//*****************************************************************************************
//
uint uCount
(
)
{
return uNodeCount;
};
//*****************************************************************************************
//
Box3 bx3Bound
(
);
//*****************************************************************************************
//
void BuildNames
(
);
//******************************************************************************************
//
CObjectEntry* operator[]
(
uint u_index
);
};
CSceneEnumProc* psep_the_scene_enum = 0;
//**********************************************************************************************
//
CSceneEnumProc::CSceneEnumProc(IScene* pis_scene, TimeValue tv_time, Interface* pip_interface)
{
tvTime = tv_time;
theScene = pis_scene;
uNodeCount = 0;
pobeHead = 0;
pobeTail = 0;
pipInterface = pip_interface;
// Display the scene enumeration initiation banner.
slLogfile.Printf(guiInterface.strGetString(IDS_SCENEENUM_START));
//
// Call the EnumTree function, from class, IScene which will cause our call back to be
// be invoked for each INode which exists in the scene.
//
pis_scene->EnumTree(this);
// Display the scene enumeration completion banner.
slLogfile.Printf(guiInterface.strGetString(IDS_SCENEENUM_END));
}
//**********************************************************************************************
//
CSceneEnumProc::~CSceneEnumProc()
{
CObjectEntry* pobe_next;
// Destroy the scene entry list one node at a time.
while (pobeHead) {
// Setup a pointer to the next node.
pobe_next = pobeHead->pobeNext;
// Delete this node.
delete pobeHead;
// Setup head to point to the saved node.
pobeHead = pobe_next;
}
// Terminate the head and tail list pointers.
pobeHead = 0;
pobeTail = 0;
// Set the scene entry count to 0.
uNodeCount = 0;
}
#define TRIMESH_OBJECT 10
//**********************************************************************************************
//
int CSceneEnumProc::callback(INode* pin_inode)
{
// Setup a pointer to the object in the scene
Object* pobj_object = pin_inode->EvalWorldState(tvTime).obj;
// Log the inode, name and conversion type of this object.
slLogfile.Printf(guiInterface.strGetString(IDS_SCENEENUM_INODE), pin_inode, pin_inode->GetName());
slLogfile.Printf(guiInterface.strGetString(IDS_CONV_TO_TRIMESH));
// Can this object be converted to a TRI-MESH object?
if (pobj_object->CanConvertToType(triObjectClassID))
{
// Log the fact that a Tri-mesh was located.
slLogfile.Printf(guiInterface.strGetString(IDS_YES));
// Yes! Then add it to the Scene list for later exporting
Append(pin_inode, pobj_object, TRIMESH_OBJECT);
}
else
{
// This object is not convertable to a tri-mesh object. Add check here for a 'bones' object.
slLogfile.Printf(guiInterface.strGetString(IDS_NO));
}
// Process the next object
return TREE_CONTINUE;
}
//**********************************************************************************************
//
void CSceneEnumProc::Append(INode* pin_inode, Object* pobj_object, int i_type)
{
CObjectEntry* pobe_entry = new CObjectEntry(pin_inode, pobj_object, i_type);
// Does the list contain more than one scene entry already?
if (pobeTail)
{
// Yes! Then add this object to the list.
pobeTail->pobeNext = pobe_entry;
}
// Since this node is at the end of the list, the tail pointer should point at the new node.
pobeTail = pobe_entry;
// Is this node the first in the list?
if (!pobeHead)
{
// Yes! Then the head pointer should point at it.
pobeHead = pobe_entry;
}
// Increment the count of the total number of objects in the list.
uNodeCount++;
}
//**********************************************************************************************
//
Box3 CSceneEnumProc::bx3Bound()
{
Box3 bx3_scene_box;
ViewExp* pve_viewport = pipInterface->GetViewport(0);
CObjectEntry* pobe_entry = pobeHead;
// Initialize the bounding box parameters.
bx3_scene_box.Init();
// While there are still objects in the list to see.
while (pobe_entry)
{
Box3 bx3_object_box;
// Get the world bounding box.
pobe_entry->pobjObject->GetWorldBoundBox(tvTime, pobe_entry->pinINode, pve_viewport, bx3_object_box);
// Make sure this new object falls into the bounding box.
bx3_scene_box += bx3_object_box;
// Move to the next node in the list.
pobe_entry = pobe_entry->pobeNext;
}
// Return the boundiung box.
return bx3_scene_box;
}
//**********************************************************************************************
//
CObjectEntry* CSceneEnumProc::pobeLookup(INode* pin_inode)
{
CObjectEntry* pobe_object = pobeHead;
// While there are object nodes in the list.
while (pobe_object)
{
// Is this the INode we are looking for?
if (pobe_object->pinINode == pin_inode)
{
// Yes! Then return it.
return pobe_object;
}
// No! Then advance to the next object in the list.
pobe_object = pobe_object->pobeNext;
}
// Uh oh! The node was not found in the list, so return null.
return false;
}
//**********************************************************************************************
//
CObjectEntry* CSceneEnumProc::operator[](uint u_index)
{
CObjectEntry* pobe_entry = pobeHead;
// Is the index in range?
if (u_index > uNodeCount)
{
// Yes! Return null.
return 0;
}
// While there are still object entries in the list.
while (pobe_entry)
{
// Is this the index we are looking for?
if (u_index-- == 0)
{
// Yes! Then return this node.
return pobe_entry;
}
// No! Advance to the next node in the list.
pobe_entry = pobe_entry->pobeNext;
}
// Uh oh! This means that the list has fewer nodes than the uCount field believes should be in the
// object netry list, so return null to the user.
return 0;
}
//*********************************************************************************************
//
class CObjectListNode
//
// Prefix: oln
//
// This class is dreived from the base class iTreeEnumProc, which passes each of the INodes in
// the scene to the exporter through the 'callback' procedure. The callback then determines
// which objects can be converted to a tri-mesh object, and can then be exported.
//
// Example:
//
//*********************************************************************************************
{
public:
CObjectEntry* pobeEntry;
CObjectListNode* polnNext;
CObjectListNode
(
CObjectEntry* pobe_entry
)
{
pobeEntry = pobe_entry; polnNext = 0;
}
};
//*********************************************************************************************
//
class CObjectList
//
// Prefix: ol
//
// This class is derived from the base class iTreeEnumProc, which passes each of the INodes in
// the scene to the exporter through the 'callback' procedure. The callback then determines
// which objects can be converted to a tri-mesh object, and can then be exported.
//
// Example:
//
//*********************************************************************************************
{
private:
uint uObjectCount;
public:
CObjectListNode* polnHead;
CObjectListNode* polnTail;
//******************************************************************************************
//
CObjectList
(
CSceneEnumProc& scene
);
//******************************************************************************************
//
~CObjectList
(
);
//******************************************************************************************
//
void Append
(
CObjectEntry* pobe_object
);
//******************************************************************************************
//
uint uCount
(
)
{
return uObjectCount;
}
//******************************************************************************************
//
int operator[]
(
Object* pobj_object
);
//******************************************************************************************
//
int operator[]
(
INode* pin_inode
);
//******************************************************************************************
//
CObjectListNode* operator[]
(
uint u_index
);
};
//**********************************************************************************************
//
CObjectList::CObjectList(CSceneEnumProc& sep_scene)
{
polnHead = 0;
polnTail = 0;
uObjectCount = 0;
uint u_object_count = sep_scene.uCount();
//
// Add each of the object entries to the object list. Note: this seems redundant since
// the user should be able to operate on the object entries in the scene enum proc list
// rather than copying them to the object list. Will need to look into this later in
// more datail to determine why this is occurring.
//
for (uint u_i = 0; u_i < u_object_count; u_i++)
{
// Add the object entry to the object list.
Append(sep_scene[u_i]);
}
}
//**********************************************************************************************
//
CObjectList::~CObjectList()
{
// While there are object entry nodes in the list.
while (polnHead)
{
// Setup a pointer to the next object entry node.
CObjectListNode *poln_next = polnHead->polnNext;
// Delete the object list node at the front of the list.
delete polnHead;
// Advance the head pointer to the next node in the list.
polnHead = poln_next;
}
// The list is now empty so terminate the list pointer and zero the count.
polnHead = 0;
polnTail = 0;
uObjectCount = 0;
}
//**********************************************************************************************
//
void CObjectList::Append(CObjectEntry* pobe_object)
{
CObjectListNode* poln_node = new CObjectListNode(pobe_object);
// Is there already a node in the list?
if (polnTail)
{
// Yes! Then add this node to the end of the list.
polnTail->polnNext = poln_node;
}
// Setup the tail pointer to point to the last node in the list.
polnTail = poln_node;
// Was the list previously empty?
if (polnHead == 0)
{
// Yes! Then setup the head list pointer to point to this node.
polnHead = poln_node;
}
// Increment the list counter.
uObjectCount++;
}
//**********************************************************************************************
//
CObjectListNode* CObjectList::operator[](uint u_index)
{
CObjectListNode* poln_node = polnHead;
// Is the index in range?
if (u_index > uObjectCount)
{
// No! Return a null pointer.
return 0;
}
// While there are still nodes in the list.
while (poln_node)
{
// Is this the node we are looking for?
if (u_index-- == 0)
{
// Yes! Return a pointer to this node.
return poln_node;
}
// Advance to the next node in the list.
poln_node = poln_node->polnNext;
}
// Uh oh! This means that the node count and the node list length do not match. Return null.
return false;
}
//**********************************************************************************************
//
int CObjectList::operator[](Object* pobj_object)
{
int i_index = 0;
CObjectListNode* poln_node = polnHead;
// While there are still nodes in the list to process.
while (poln_node)
{
// Is this the node we are looking for?
if (poln_node->pobeEntry->pobjObject == pobj_object)
{
// Return the index to this node.
return i_index;
}
// Advance to the next node in the object list.
poln_node = poln_node->polnNext;
// Advance in index pointer.
i_index++;
}
// The node was not located in the list so return an error.
return -1;
}
//**********************************************************************************************
//
int CObjectList::operator[](INode* pin_inode)
{
int i_index = 0;
CObjectListNode* poln_node = polnHead;
// While there are still nodes in the list.
while (poln_node)
{
// Is this the node we are looking for?
if (poln_node->pobeEntry->pinINode == pin_inode)
{
// Yes! Then return the index to this node to the user.
return i_index;
}
// Advance to the next node in the list.
poln_node = poln_node->polnNext;
// Increment the index node pointer.
i_index++;
}
// The node was not located in the list so return an error.
return -1;
}
//*********************************************************************************************
//
class CObjectName
//
// Prefix: on
//
// Example:
//
//*********************************************************************************************
{
public:
TSTR tstrName;
CObjectName* ponNext;
//******************************************************************************************
//
CObjectName
(
TSTR tstr_object_name
)
{
tstrName = tstr_object_name;
ponNext = 0;
}
};
//*********************************************************************************************
//
class CObjectNameList
//
// Prefix: onl
//
// This class is derived from the base class iTreeEnumProc, which passes each of the INodes in
// the scene to the exporter through the 'callback' procedure. The callback then determines
// which objects can be converted to a tri-mesh object, and can then be exported.
//
// Example:
//
//*********************************************************************************************
{
uint uObjectCount;
public:
CObjectName* ponHead;
CObjectName* ponTail;
//******************************************************************************************
//
CObjectNameList
(
)
{
ponHead = 0;
ponTail = 0;
uObjectCount = 0;
}
//******************************************************************************************
//
~CObjectNameList
(
);
//******************************************************************************************
//
void Append
(
TSTR& tstr_object_name
);
//******************************************************************************************
//
int iLookup
(
TSTR& tstr_object_name
);
//******************************************************************************************
//
uint uCount
(
)
{
return uObjectCount;
}
//******************************************************************************************
//
void MakeUnique
(
TSTR& tstr_object_name
);
//******************************************************************************************
//
int operator[]
(
TSTR& tstr_object_name
);
};
//**********************************************************************************************
//
CObjectNameList::~CObjectNameList()
{
// While there are nodes in the list.
while (ponHead)
{
// Advance the pointer to the next node in the list.
CObjectName* pon_node = ponHead->ponNext;
// Remove the node from the list.
delete ponHead;
// Advance the head pointer to the next node.
ponHead = pon_node;
}
// Set the head, tail node pointers and count to null.
ponHead = 0;
ponTail = 0;
uObjectCount = 0;
}
//**********************************************************************************************
//
void CObjectNameList::Append(TSTR& tstr_object_name)
{
CObjectName* pon_node = new CObjectName(tstr_object_name);
// Does the list have any nodes in it?
if (ponTail)
{
// Yes! Add this node to the list.
ponTail->ponNext = pon_node;
}
// Setup the tail pointer to point to the end of the list.
ponTail = pon_node;
// Was the list previously empty?
if (ponHead == 0)
{
// Yes! Then the new node is the only node in the list.
ponHead = pon_node;
}
// Increment the node counter.
uObjectCount++;
}
//**********************************************************************************************
//
void CObjectNameList::MakeUnique(TSTR& tstr_object_name)
{
// Is this name already in the list?
if (iLookup(tstr_object_name) == -1)
{
// No! Then add it to the list.
Append(tstr_object_name);
}
else
{
// Yes! Then attempt to build a unique name.
for (int i = 0; i < 10000000; ++i)
{
char buf[12];
// Setup a counter in strings.
sprintf(buf,":%d",i);
TSTR tstr_num(buf);
TSTR tstr_work = tstr_object_name;
// Concatenate the numeric text string onto the end of this string.
tstr_work = tstr_work + tstr_num;
// Is the new name now unique?
if (iLookup(tstr_work) == -1)
{
// Add the new name to the object name list.
Append(tstr_work);
// Return the new object name to the caller.
tstr_object_name = tstr_work;
break;
}
}
}
}
//**********************************************************************************************
//
int CObjectNameList::iLookup(TSTR& tstr_object_name)
{
int i_index = 0;
CObjectName* pon_node = ponHead;
// While there are still nodes in the list.
while (pon_node)
{
// Is this the node we are looking for?
if (pon_node->tstrName == tstr_object_name)
{
// Return the index to this node.
return i_index;
}
// Adavance to the next node in the list.
pon_node = pon_node->ponNext;
// Advance in the index counter.
i_index++;
}
// The node was not found so return an invalid index.
return -1;
}
CObjectNameList on_the_object_names;
//**********************************************************************************************
//
void CSceneEnumProc::BuildNames()
{
CObjectNameList onl_name_list;
CObjectEntry* pobe_node = pobeHead;
// While there are still objects in the list.
while (pobe_node)
{
// Get the objects actual name.
pobe_node->tstrName = pobe_node->pinINode->GetName();
// Make sure the objects name is unique.
onl_name_list.MakeUnique(pobe_node->tstrName);
// Advance to the next node in the list.
pobe_node = pobe_node->pobeNext;
}
}
//**********************************************************************************************
// Define the DLL's interface information.
//
bool WINAPI DllMain(HINSTANCE hDLLInst, DWORD fdwReason, LPVOID lpvReserved)
{
// Why was the DLL's main called?
switch (fdwReason)
{
// Is a new process attaching to this DLL?
case DLL_PROCESS_ATTACH:
// Is there already a process attached to this DLL?
if (guiInterface.GetInstance() != 0)
{
// Yes! Since this code is not multi-threaded, return an error.
// were unsuccessful.
return(false);
}
// Get the DLL's instance handle and set it in the interface class.
guiInterface.SetInstance(hDLLInst);
break;
// Is an existing process attempting to detach from this DLL?
case DLL_PROCESS_DETACH:
// Delete the instance handle of this process from the interface class.
guiInterface.SetInstance(0);
break;
// A thread want to attach to the DLL, and this is allowed.
case DLL_THREAD_ATTACH:
break;
// A thread want to dettach to the DLL, and this is allowed.
case DLL_THREAD_DETACH:
break;
}
// Let the caller know that we were successful.
return true;
}
//**********************************************************************************************
// Function which returns a description of the DLL.
//
__declspec(dllexport) const TCHAR* LibDescription()
{
// Return an ASCII string from the string table.
return _T(guiInterface.strGetString(IDS_JP2_COPYRIGHT));
}
//**********************************************************************************************
// Function which returns the number of classes in this library.
//
__declspec(dllexport) int LibNumberClasses()
{
// Currently there is just one class in this library.
return 1;
}
//**********************************************************************************************
// Function which returns a pointer to a class based upon an index.
//
__declspec(dllexport) ClassDesc *LibClassDesc(int i)
{
// Which class is being referenced?
switch(i) {
// Class 1 in this DLL.
case 0:
// Return a pointer to it.
return &cld_jp2_desc;
break;
// Otherwise, return 0 as the requested class was not found.
default:
return 0;
break;
}
}
//**********************************************************************************************
// Function which returns the version of the DLL.
//
__declspec(dllexport) ULONG LibVersion()
{
// Return the current version number from the version table.
return(EXPORTER_VERSION_NUMBER);
}
//**********************************************************************************************
// Routines for processing the bitmaps associated with the objects
//
int Materials;
CObjectDef* podCurrent;
CObjectDefList theList;
//**********************************************************************************************
// Global static variables for keeping session default values around until the Max application
// is exited.
// Change the default checkbox settings in the development environment.
#ifndef _DEBUG
static bool b_quantize_bmp = true;
static bool b_gen_groff = true;
static bool b_gen_logfiles = false;
#else
static bool b_quantize_bmp = false;
static bool b_gen_groff = true;
static bool b_gen_logfiles = true;
#endif
//**********************************************************************************************
//
static BOOL CALLBACK ExportDlgProc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
{
// Now process the message.
switch(msg)
{
case WM_INITDIALOG:
// Center the window on the screen.
CenterWindow(hdlg, GetParent(hdlg));
// Setup the defaults for the check buttons.
CheckDlgButton(hdlg, IDC_QUANTIZE_BMP, b_quantize_bmp);
CheckDlgButton(hdlg, IDC_GEN_GROFF, b_gen_groff);
CheckDlgButton(hdlg, IDC_GEN_LOGFILES, b_gen_logfiles);
// Indicate that we processed a message.
return true;
case WM_COMMAND:
// Process the windows command.
switch(LOWORD(wparam))
{
// Did the user press the cancel button, implying he want to bail out?
case IDCANCEL:
// Yes! Remove the dialog box and return false to the creator of the dialog.
EndDialog(hdlg, false);
break;
// Does the user want to perform the export now?
case IDOK:
// Yes! Then get the button selection options.
b_quantize_bmp = IsDlgButtonChecked(hdlg, IDC_QUANTIZE_BMP);
b_gen_groff = IsDlgButtonChecked(hdlg, IDC_GEN_GROFF);
b_gen_logfiles = IsDlgButtonChecked(hdlg, IDC_GEN_LOGFILES);
// Remove the dialog box and return true to the caller.
EndDialog(hdlg, true);
break;
}
break;
}
// Return a failure result.
return false;
}
//**********************************************************************************************
//
void Convert(SColor24* ac24_dst, BMM_Color_48* ac48_src, uint u_count)
{
for (uint u_i = 0; u_i < u_count; u_i++)
{
ac24_dst[u_i].u1Red = uint8 (ac48_src[u_i].r >> 8);
ac24_dst[u_i].u1Green = uint8 (ac48_src[u_i].g >> 8);
ac24_dst[u_i].u1Blue = uint8 (ac48_src[u_i].b >> 8);
}
}
//**********************************************************************************************
//
void MaterialDefaults(StdMat* psmtl_material)
{
slLogfile.Printf(guiInterface.strGetString(IDS_MATERIAL_CONFIG));
// Do we have a valid material?
if (psmtl_material == 0)
{
// No! Return
return;
}
// Is face mapping enabled?
if (psmtl_material->GetFaceMap())
{
slLogfile.Printf(guiInterface.strGetString(IDS_FACE_MAP_ENABLED));
}
else
{
slLogfile.Printf(guiInterface.strGetString(IDS_FACE_MAP_DISABLED));
}
// Are two sided polygons in use?
if (psmtl_material->GetTwoSided())
{
slLogfile.Printf(guiInterface.strGetString(IDS_FACE_MODE_DOUBLE));
}
else
{
slLogfile.Printf(guiInterface.strGetString(IDS_FACE_MODE_SINGLE));
}
// Get the shininess value.
slLogfile.Printf(guiInterface.strGetString(IDS_SHININESS), psmtl_material->GetShininess(0));
// Get the shininess strength value.
slLogfile.Printf(guiInterface.strGetString(IDS_SHININESS_STRENGTH), psmtl_material->GetShinStr(0));
// Get the self-illumination
slLogfile.Printf(guiInterface.strGetString(IDS_SELF_ILLUMINATION), psmtl_material->GetSelfIllum(0));
// Look through all the materials and determine the maps in use and report them.
for (uint u_i = ID_AM; u_i < ID_RR; u_i++)
{
// Is the map enabled?
if (psmtl_material->MapEnabled(u_i))
{
// Get the strength field.
float f_strength = psmtl_material->GetTexmapAmt(u_i, 0);
// Yes! Report the map type and name.
switch(u_i)
{
case ID_AM:
slLogfile.Printf(guiInterface.strGetString(IDS_AMBIENT_MAP), f_strength);
break;
case ID_DI:
slLogfile.Printf(guiInterface.strGetString(IDS_DIFFUSE_MAP), f_strength);
break;
case ID_SP:
slLogfile.Printf(guiInterface.strGetString(IDS_SPECULAR_MAP), f_strength);
break;
case ID_SH:
slLogfile.Printf(guiInterface.strGetString(IDS_SHININESS_MAP), f_strength);
break;
case ID_SS:
slLogfile.Printf(guiInterface.strGetString(IDS_SHININESS_STR_MAP), f_strength);
break;
case ID_SI:
slLogfile.Printf(guiInterface.strGetString(IDS_SELF_ILLUM_MAP), f_strength);
break;
case ID_OP:
slLogfile.Printf(guiInterface.strGetString(IDS_OPACITY_MAP), f_strength);
break;
case ID_FI:
slLogfile.Printf(guiInterface.strGetString(IDS_FILTER_MAP), f_strength);
break;
case ID_BU:
slLogfile.Printf(guiInterface.strGetString(IDS_BUMP_MAP), f_strength);
break;
case ID_RL:
slLogfile.Printf(guiInterface.strGetString(IDS_REFLECTION_MAP), f_strength);
break;
case ID_RR:
slLogfile.Printf(guiInterface.strGetString(IDS_REFRACTION_MAP), f_strength);
break;
}
}
}
}
//**********************************************************************************************
//
bool QuantizeBitmap(Quantizer* pq_quantizer, TSTR& Diffuse)
{
bool b_success = true;
TSTR tstr_progress_title;
// Build the progress meter title.
tstr_progress_title.printf(guiInterface.strGetString(IDS_QUANTIZE_BM), Diffuse.data());
// Notify the user of what is going on.
guiInterface.InitProgressMeter((char *) tstr_progress_title.data());
// Setup a bitmap info structure
BitmapInfo bi_bitmap;
// Setup the name of the bitmap
bi_bitmap.SetName(Diffuse.data());
// Load the bitmap. Use Max's bitmap manager to the bitmap since it could be an unsupported type.
Bitmap* pbm_bitmap = TheManager->Load(&bi_bitmap);
// Were we successful?
if (!pbm_bitmap)
{
// Report error to the user.
guiInterface.bErrorPrintf(IDS_QB_CANT_LOAD_DIF_BMP, Diffuse.data());
// Return an error.
return false;
}
// Again attempt to determine what kind of bitmap we are looking at. Is it paletted?
if (bi_bitmap.Type() != BMM_TRUE_24)
{
// Report the error to the user.
guiInterface.bErrorPrintf(IDS_QB_TEX_BMP_NOT_TRUECOLOR, Diffuse.data());
// Return an error result.
return false;
}
else
{
//
// We now know we have a 24 bit bitmap and that it has been loaded. We now need
// to feed the bitmap
//
// Allocate a buffer for conversion of the bitmap.
PixelBuf pxb_line(pbm_bitmap->Width());
// Were we successful?
if (!pxb_line.Ptr())
{
// No! Notify the user.
guiInterface.bErrorMsg(IDS_PB_CANT_ALLOC_PXL_BUFFER);
// Close the bitmap structure
pbm_bitmap->Close(&bi_bitmap);
return false;
}
// Convert the image from 24 bit to 8 bit.
for (int i_row = 0; i_row < pbm_bitmap->Height(); i_row++)
{
// Update the progress bar. And determine if the user wants to abort.
if (guiInterface.bUpdateProgressMeter((101 * i_row)/pbm_bitmap->Height()))
{
// Destroy the progress meter.
guiInterface.DestroyProgressMeter();
// Yes! The user is requesting to abort this process.
return false;
}
// Attempt to get a row of pixels. Were we successful?
if (!pbm_bitmap->GetPixels(0, i_row, pbm_bitmap->Width(), pxb_line.Ptr()))
{
// No! Something went wrong.
guiInterface.bErrorMsg(IDS_PXL_LOOP_READ_ERR);
break;
}
else
{
// Add these colors to the histogram.
pq_quantizer->AddToHistogram(pxb_line.Ptr(), pbm_bitmap->Width());
}
}
}
// Destroy the progress meter.
guiInterface.DestroyProgressMeter();
// Return a successful result.
return true;
}
//**********************************************************************************************
//
bool FileExists(TSTR tstr_filename)
{
HANDLE hFile;
// Attempt to open the file.
hFile = CreateFile(tstr_filename.data(), GENERIC_READ, FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES) NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE) NULL);
// Does the file exist?
if (hFile != INVALID_HANDLE_VALUE)
{
// Yes! The file exists so close the file and return TRUE.
CloseHandle(hFile);
return true;
}
// No! Return false.
return false;
}
//**********************************************************************************************
//
void Convert_Path(TSTR& tstr_map_name)
{
TSTR tstr_path;
TSTR tstr_file;
// Construct the texture file name for the progress meter.
SplitPathFile(tstr_map_name, &tstr_path, &tstr_file);
// Build the absolute path for the target of the bitmap.
tstr_path.printf("%s%s", guiInterface.strGetBitmapDirName(), tstr_file.data());
// Assign the new path name to the file.
tstr_map_name = tstr_path;
}
//**********************************************************************************************
//
bool ProcessBitmap(
TSTR& tstr_diffuse, // The name of the source diffuse bitmap.
TSTR& tstr_opacity, // The name of the source opacity bitmap.
TSTR& tstr_bump, // The name of the source bump bitmap.
BMM_Color_48* bmm_palette, // The quantized 48 bit palette for conversion.
SColor24* ac24_palette, // The target palette for the bitmap.
const uint u_palette_entries // The number of entries in the target palette.
)
{
bool b_success = true;
TSTR tstr_diffuse_path;
TSTR tstr_diffuse_file;
// Construct the texture file name for the progress meter.
TSTR tstr_progress_title;
SplitPathFile(tstr_diffuse, &tstr_diffuse_path, &tstr_diffuse_file);
tstr_progress_title.printf(guiInterface.strGetString(IDS_BITMAP_FMT), tstr_diffuse_file.data());
// Setup a bitmap info structure
BitmapInfo bi_bitmap;
// Setup the name of the source bitmap
bi_bitmap.SetName(tstr_diffuse.data());
// Load the bitmap.
Bitmap* pbm_bitmap = TheManager->Load(&bi_bitmap);
// Were we successful?
if (!pbm_bitmap)
{
// Report error to the user.
guiInterface.bErrorPrintf(IDS_PB_CANT_LOAD_DIF_BMP, tstr_diffuse.data());
return false;
}
// Log a bunch of information about the logfile.
slLogfile.Printf(guiInterface.strGetString(IDS_BMP_TITLE), (char *) tstr_diffuse.data());
slLogfile.Printf(guiInterface.strGetString(IDS_BMP_WIDTH_FMT), bi_bitmap.Width());
slLogfile.Printf(guiInterface.strGetString(IDS_BMP_HEIGHT_FMT), bi_bitmap.Height());
slLogfile.Printf(guiInterface.strGetString(IDS_BMP_FLAGS_FMT), bi_bitmap.Flags());
slLogfile.Printf(guiInterface.strGetString(IDS_BMP_MAX_RGB_LVL_FMT), pbm_bitmap->MaxRGBLevel());
// Again attempt to determine what kind of bitmap we are looking at. Is it paletted?
if (bi_bitmap.Type() == BMM_PALETTED)
{
// Close the bitmap structure
pbm_bitmap->Close(&bi_bitmap);
// No! Report the error and return a failure result.
guiInterface.bErrorPrintf(IDS_PB_DIF_BMP_NOT_TRUECOLOR, tstr_diffuse.data());
return false;
}
// This had better be a true color, 24 bit bitmap.
else if (bi_bitmap.Type() == BMM_TRUE_24)
{
// The bitmap is true color.
slLogfile.Printf(guiInterface.strGetString(IDS_PB_DIF_BMP_TRUECOLOR));
//
// We now know we have a 24 bit bitmap and that it has been loaded. We now need
// to create an 8 bit bitmap and place it into the export directory.
//
// Convert the bitmap path to the destination.
Convert_Path(tstr_diffuse);
// Configure the bitmap.
CBitmapInfo bi_bitmap_info;
bi_bitmap_info.Name(tstr_diffuse.data());
bi_bitmap_info.Width(bi_bitmap.Width());
bi_bitmap_info.Height(bi_bitmap.Height());
bi_bitmap_info.BitmapFormat(EFMT_BMP);
bi_bitmap_info.Depth(8);
// Attempt to create the bitmap.
CBitmapImage bmi_bitmap;
// Attempt to create the bitmap. Were we successful?
if (!bmi_bitmap.bCreate(bi_bitmap_info, true))
{
// No! Close the bitmap structure.
pbm_bitmap->Close(&bi_bitmap);
// Report the error and return a failure result.
guiInterface.bErrorPrintf(IDS_PB_CANT_CREATE_DST_TXT_BMP, tstr_diffuse.data());
return false;
}
// Allocate a buffer for conversion of the bitmap.
PixelBuf pxb_line(pbm_bitmap->Width());
// Were we successful?
if (!pxb_line.Ptr())
{
// No! Notify the user.
pbm_bitmap->Close(&bi_bitmap);
// Report the error and return a failure result.
guiInterface.bErrorMsg(IDS_PB_CANT_ALLOC_PXL_BUFFER);
return false;
}
// Attempt to save the palette in the new bitmap. Were we successful?
if (bmi_bitmap.uSetPaletteEntries(0, u_palette_entries+1, ac24_palette) != u_palette_entries+1)
{
// No! Report an error and return.
pbm_bitmap->Close(&bi_bitmap);
// Report the error and return a failure result.
guiInterface.bErrorMsg(IDS_PB_CANT_CFG_NEW_IMG_PAL);
return false;
}
// Setup a progress meter since pixel conversion is a very slow operation.
guiInterface.InitProgressMeter((char *) tstr_progress_title.data());
ColorPacker* pcp_color_packer = BMMNewColorPacker(pbm_bitmap->Width(), &bmm_palette[1], u_palette_entries);
uint8 u1_scanline[MAX_BITMAP_WIDTH];
// Convert the image from 24 bit to 8 bit.
for (int i_row = 0; i_row < pbm_bitmap->Height(); i_row++)
{
// Attempt to get a row of pixels. Were we successful?
if (!pbm_bitmap->GetPixels(0, i_row, pbm_bitmap->Width(), pxb_line.Ptr()))
{
// No! Something went wrong.
guiInterface.bErrorMsg(IDS_PXL_LOOP_READ_ERR);
// Deallocate the color packer stuff.
pcp_color_packer->DeleteThis();
// Destroy the progress meter.
guiInterface.DestroyProgressMeter();
// Close the bitmap structure
pbm_bitmap->Close(&bi_bitmap);
return false;
}
else
{
// Update the progress meter. Does the user wish to abort?
if (guiInterface.bUpdateProgressMeter((101 * i_row) / pbm_bitmap->Height()))
{
//
// Yes! Clean things up here and abort.
//
// Deallocate the color packer stuff.
pcp_color_packer->DeleteThis();
// Close the bitmap structure
pbm_bitmap->Close(&bi_bitmap);
// Destroy the progress meter.
guiInterface.DestroyProgressMeter();
// Return a failure result.
return false;
}
// Pack these colors into a single scan line.
pcp_color_packer->PackLine(pxb_line.Ptr(), &u1_scanline[0], pbm_bitmap->Width());
//
// Increment all of the pixel indices since the palette to which the 24 bit was quantized artificially
// contained a transparency in the zero index. This means that each pixel index must be incremented.
// This is less efficient, but it eliminates the possibility of some color being mapped to the
// transparency pixel.
//
for (int i_col = 0; i_col < pbm_bitmap->Width(); i_col++)
{
// Increment the pixel value.
u1_scanline[i_col]++;
}
// Place them in the bitmap.
if (bmi_bitmap.uSetPalettedPixels(0, (uint) i_row, pbm_bitmap->Width(), &u1_scanline[0]) != (uint) pbm_bitmap->Width())
{
// No! Report the error and return.
guiInterface.bErrorMsg(IDS_PB_CANT_WR_PPXL_TO_BMP);
// Deallocate the color packer stuff.
pcp_color_packer->DeleteThis();
// Destroy the progress meter.
guiInterface.DestroyProgressMeter();
// Close the bitmap structure
pbm_bitmap->Close(&bi_bitmap);
// Return a failure result.
return false;
}
}
}
// Destroy the progress meter.
guiInterface.DestroyProgressMeter();
// Deallocate the color packer stuff.
pcp_color_packer->DeleteThis();
// Close the bitmap structure
pbm_bitmap->Close(&bi_bitmap);
// Was a transparency map supplied?
if (tstr_opacity.length() > 0)
{
// Attempt to load the bitmap.
CBitmapImage bmi_opacity;
CBitmapIO bio_opacity;
// Does this bitmap exist?
if (!bio_opacity.bLoad((char *) tstr_opacity.data(), bmi_opacity))
{
// No! Report the error.
guiInterface.bErrorPrintf(IDS_PB_CANT_LOAD_OP_BMP, tstr_opacity.data());
// Return a failure result.
return false;
}
// There will NEVER be an opacity map in the destination directory, so delete the reference to it.
tstr_opacity.printf("");
//
// Perform a number of reality checks on the data: Dimensions must be equal, Opacity map must be 2 color.
//
CBitmapInfo bi_opacity;
bi_opacity = bmi_opacity.biBitmapInfo();
// Are the dimensions equal?
if (bi_bitmap_info.uWidth() != bi_opacity.uWidth() || bi_bitmap_info.uHeight() != bi_opacity.uHeight())
{
// No! Report the error.
if (guiInterface.bErrorPrintf(IDS_PB_BMP_DIMS_INCOMPAT, bi_bitmap_info.strName(), bi_bitmap_info.uWidth(),
bi_bitmap_info.uHeight(), bi_opacity.strName(), bi_opacity.uWidth(), bi_opacity.uHeight()))
{
// Yes! The user wants to quit so let him.
return false;
}
}
// Is the opacity map paletted?
else if (!bmi_opacity.bIsPaletted())
{
// Does the user want to quit?
if (guiInterface.bErrorPrintf(IDS_PB_OP_BMP_NOT_PAL, bi_opacity.strName()))
{
// Yes! The user wants to quit so let him.
return false;
}
}
else
{
//
// We now have the opacity map loaded and it is known to be valid. Modify the texture
// map to incorporate transparent pixels.
//
// Determine which index value represents transparent.
SColor24 ac24_tmp_palette[256];
if (bmi_opacity.uGetPaletteEntries(0, bi_opacity.uPaletteEntries(), &ac24_tmp_palette[0]) != bi_opacity.uPaletteEntries())
{
// Does the user want to quit?
if (guiInterface.bErrorPrintf(IDS_PB_CANT_RD_OP_BMP_PAL, bi_opacity.strName()))
{
// Yes! The user wants to quit so let him.
return false;
}
}
else
{
uint u_xparent_index = 256;
// Locate the transparency value which is defined to be the RGB triple with values (0,0,0).
for (uint8 u1_i = 0; u1_i < bi_opacity.uPaletteEntries(); u1_i++)
{
// Is this the value we are looking for?
if (ac24_tmp_palette[u1_i].u1Red == 0 && ac24_tmp_palette[u1_i].u1Green == 0 && ac24_tmp_palette[u1_i].u1Blue == 0)
{
// Yes! Record this index value and exit the loop.
u_xparent_index = u1_i;
break;
}
}
// Were we successful?
if (u_xparent_index == 256)
{
// Does the user want to quit?
if (guiInterface.bErrorPrintf(IDS_PB_CANT_FIND_XPAR_PXL, bi_opacity.strName()))
{
// Yes! The user wants to quit so let him.
return false;
}
}
else
{
// Keep track of the number of transparent pixels in this map.
uint u_transparent_pixels = 0;
// Process the texture map one row at a time.
for (uint u_row = 0; u_row < bi_opacity.uHeight(); u_row++)
{
// Attempt to read the scanline.
uint8 u1_opacity_scanline[MAX_BITMAP_WIDTH];
if (bmi_opacity.uGetPalettedPixels(0, (bi_opacity.uHeight()-1)-u_row, bi_opacity.uWidth(), &u1_opacity_scanline[0]) != bi_opacity.uWidth())
{
// Does the user want to quit?
if (guiInterface.bErrorPrintf(IDS_PB_CANT_RD_OP_BMP_SCANLINE, bi_opacity.strName()))
{
// Yes! The user wants to quit so let him.
return false;
}
break;
}
// Read the texture map scanline.
if (bmi_bitmap.uGetPalettedPixels(0, u_row, bi_opacity.uWidth(), &u1_scanline[0]) != bi_opacity.uWidth())
{
// Does the user want to quit?
if (guiInterface.bErrorPrintf(IDS_PB_CANT_RD_DIF_BMP_SCANLINE, bi_bitmap_info.strName()))
{
// Yes! The user wants to quit so let him.
return false;
}
break;
}
// Loop through the scanline and process all of the pixels.
for (uint u_col = 0; u_col < bi_opacity.uWidth(); u_col++)
{
// Is this pixel supposed to be transparent?
if (u1_opacity_scanline[u_col] == u_xparent_index)
{
// Make this pixel transparent.
u1_scanline[u_col] = 0;
// Increment the transparent pixel count.
u_transparent_pixels++;
}
}
// Attempt to write this bitmap back to the texture map.
if (bmi_bitmap.uSetPalettedPixels(0, u_row, bi_opacity.uWidth(), &u1_scanline[0]) != bi_opacity.uWidth())
{
// Does the user want to quit?
if (guiInterface.bErrorPrintf(IDS_PB_CANT_WR_SCANLINE_2_DIF_BMP, bi_bitmap_info.strName()))
{
// Yes! The user wants to quit so let him.
return false;
}
break;
}
}
// Log the transparent pixel ratio to the logfile for the artists.
slLogfile.Printf(guiInterface.strGetString(IDS_PB_PXL_PRCS_STATS), bi_opacity.uWidth()*bi_opacity.uHeight(),
u_transparent_pixels,((float) u_transparent_pixels*100.0)/((float) (bi_opacity.uWidth()*bi_opacity.uHeight())));
}
}
}
}
// Was a bump map file supplied?
if (tstr_bump.length() > 0)
{
CBitmapIO bio_bump;
CBitmapImage bmi_bump;
// Attempt to load the bumpmap.
if (!bio_bump.bLoad((char *) tstr_bump.data(), bmi_bump))
{
// Does the user want to quit?
if (guiInterface.bErrorPrintf(IDS_PB_CANT_LOAD_BU_BMP, tstr_bump.data()))
{
// Yes! The user wants to quit so let him.
return false;
}
}
CBitmapInfo bi_bump = bmi_bump.biBitmapInfo();
// Are the dimensions equal?
if (bi_bitmap_info.uWidth() != bi_bump.uWidth() || bi_bitmap_info.uHeight() != bi_bump.uHeight())
{
// Does the user want to quit?
if (guiInterface.bErrorPrintf(IDS_PB_BMP_DIMS_INCOMPAT, bi_bitmap_info.strName(), bi_bitmap_info.uWidth(),
bi_bitmap_info.uHeight(), bi_bump.strName(), bi_bump.uWidth(), bi_bump.uHeight()))
{
// Yes! The user wants to quit so let him.
return false;
}
}
// Is the opacity map paletted?
else if (!bmi_bump.bIsPaletted())
{
// Does the user want to quit?
if (guiInterface.bErrorPrintf(IDS_PB_BU_BMP_NOT_PAL, bi_bump.strName()))
{
// Yes! The user wants to quit so let him.
return false;
}
}
else
{
// Get the info on the bumpmap.
CBitmapInfo bi_bump = bmi_bump.biBitmapInfo();
// Convert the bitmap path to the destination.
Convert_Path(tstr_bump);
// Change the name of the bump map to correspond to the new bump map.
bi_bump.Name(tstr_bump.data());
// Attempt to update the name in the bitmap image.
if (!bmi_bump.bBitmapInfo(bi_bump))
{
// Does the user want to quit?
if (guiInterface.bErrorPrintf(IDS_PB_CANT_UPDATE_DST_BU_NAME, bi_bump.strName()))
{
// Yes! The user wants to quit so let him.
return false;
}
}
// Invert the bump map vertically.
for (uint u_row = 0; u_row < bi_bump.uHeight() / 2; u_row++)
{
// Attempt to read the scanline.
uint8 u1_bump_scanline[2][MAX_BITMAP_WIDTH];
// Get a scanline from the top of the bitmap.
if (bmi_bump.uGetPalettedPixels(0, (bi_bump.uHeight()-1)-u_row, bi_bump.uWidth(), &u1_bump_scanline[0][0]) != bi_bump.uWidth())
{
// Does the user want to quit?
if (guiInterface.bErrorPrintf(IDS_PB_CANT_RD_BU_BMP_SCANLINE, bi_bump.strName()))
{
// Yes! The user wants to quit so let him.
return false;
}
break;
}
// Get a scanline from the bottom of the bitmap.
if (bmi_bump.uGetPalettedPixels(0, u_row, bi_bump.uWidth(), &u1_bump_scanline[1][0]) != bi_bump.uWidth())
{
// Does the user want to quit?
if (guiInterface.bErrorPrintf(IDS_PB_CANT_RD_BU_BMP_SCANLINE, bi_bump.strName()))
{
// Yes! The user wants to quit so let him.
return false;
}
break;
}
// Attempt to write the scanlines to the bitmaps.
if (bmi_bump.uSetPalettedPixels(0, (bi_bump.uHeight()-1)-u_row, bi_bump.uWidth(), &u1_bump_scanline[1][0]) != bi_bump.uWidth())
{
// Display the Error message to the user.
guiInterface.bErrorPrintf(IDS_PB_CANT_WR_SCANLINE_2_BU_BMP, bi_bump.strName());
break;
}
if (bmi_bump.uSetPalettedPixels(0, u_row, bi_bump.uWidth(), &u1_bump_scanline[0][0]) != bi_bump.uWidth())
{
// Something went wrong in here, so report the error and exit the loop.
guiInterface.bErrorPrintf(IDS_PB_CANT_WR_SCANLINE_2_BU_BMP, bi_bump.strName());
break;
}
}
// Attempt to save the bumpmap to disk.
if (!bio_bump.bSave(bmi_bump))
{
// Something went wrong in here, so report the error and exit the loop.
guiInterface.bErrorPrintf(IDS_PB_CANT_WR_BU_BMP_2_DSK, bi_bump.strName());
// Return a failure result to the user.
return false;
}
}
}
// Finally attempt to write the bitmap to disk.
CBitmapIO bio_bitmap;
// Were we sucessful?
if (!bio_bitmap.bSave(bmi_bitmap))
{
// No! Return a failure result.
return false;
}
}
// Uh oh! We are seeing an unrecognized bitmap format.
else
{
// Generate an error message and report it to the user.
guiInterface.bErrorPrintf(IDS_PB_UNKNOWN_BMP_TYPE, bi_bitmap.Type());
// Close the bitmap structure
pbm_bitmap->Close(&bi_bitmap);
// Return a failure result.
return false;
}
// Return a successful result
return true;
}
//**********************************************************************************************
//
bool ProcessObjectBitmaps(CObjectDefList* pod_object_list, bool b_quantize_bitmaps, bool b_gen_groff)
{
uint u_object = 0;
bool b_result = true;
CSymTab st_texture_bitmaps;
SColor24 ac24_palette[256];
BMM_Color_48 bmm_palette[256];
uint u_palette_entries;
// Do we have a valid object list?
if (pod_object_list->podHead == 0)
{
// No! Return an error.
return false;
}
// Setup a pointer to first node in the object list.
CObjectDef* pod_node = pod_object_list->podHead;
// Does the user want to quanitize the bitmaps?
if (b_quantize_bitmaps)
{
// Allocate a quantizer.
Quantizer* pq_quantizer = BMMNewQuantizer();
// Were we successful?
if (pq_quantizer == 0)
{
// No! Report the error and return an error.
return guiInterface.bErrorMsg(guiInterface.strGetString(IDS_POB_CANT_ALLOC_QUANT));
}
// Attempt to allocate the quantizer histogram. Were we successful?
if (!pq_quantizer->AllocHistogram())
{
// No! Report the error, aeallocate the quantizer and return an error.
guiInterface.bErrorMsg(guiInterface.strGetString(IDS_POB_CANT_ALLOC_HIST));
// Delete the quantizer.
pq_quantizer->DeleteThis();
return false;
}
//
// Loop through the list and observe all the pixels in each of the bitmaps so that similar
// kinds of bitmaps can eventually be quantized to a common palette.
//
// Throw up a progress meter indicating the progress through building the quantization of the objects.
guiInterface.InitProgressMeter(guiInterface.strGetString(IDS_QUANTIZING));
// Loop through all the objects in the scene.
while (pod_node != 0)
{
// Update the progress indicator.
if (guiInterface.bUpdateProgressMeter((int) (u_object*101)/pod_object_list->uObjectCount()))
{
// Remove the progress indicator.
guiInterface.DestroyProgressMeter();
return false;
}
TSTR tstr_texture_name;
//
// First start out by making two lists which contains the texture map names and
// the export map names.
//
// Loop through the material list for this object.
for (uint u_i=0; u_i < pod_node->uMaterialCount; u_i++)
{
// Get the diffuse, opacity and bump bitmap names.
tstr_texture_name.printf("%s", pod_node->astrTextureMap[u_i]);
// We have not seen this bitmap before so add it to the bitmap list.
if (!st_texture_bitmaps.shLookup((char *) tstr_texture_name.data()))
{
// We have not seen this bitmap before so add it to the bitmap list.
st_texture_bitmaps.shInsert((char *) tstr_texture_name.data());
// Pass the bitmaps into the quantizer for observation. Were we successful?
if (!QuantizeBitmap(pq_quantizer, tstr_texture_name))
{
// Set the error result flag to indicate something went wrong.
b_result = false;
// Exit the loop.
break;
}
}
// Increment the progress counter.
u_object++;
}
// Advance to the next node.
pod_node = pod_node->podNext;
}
// Destroy the progress meter.
guiInterface.DestroyProgressMeter();
// Were we successful at quantizing the bitmaps?
if (!b_result)
{
// No! Deallocate the quantizer and return an error.
pq_quantizer->DeleteThis();
return false;
}
//
// Partition the histogram into a palette.
//
// Set palette entry 0 to contain the color definition of 100% blue to designate which pixels
// are transparent which viewed in a bitmap viewer.
bmm_palette[0].r = 0;
bmm_palette[0].g = 0;
bmm_palette[0].b = 65535;
u_palette_entries = pq_quantizer->Partition(&bmm_palette[1], 255, 0);
//
// The color at index 0 needs to be relocated to another index in the palette since index
// 0 has been reserved as the transparency index, when transparency is in use. This should
// always be possible because the maximum number of palette colors is 255. This therefore
// leaves 1 palette entry which can be used as a transparent pixel index.
//
// Since the quantizer has no knowledge of transparent pixels, and our implementation which
// uses index 0 for the transparent pixel index, all pixels which are currently using pixel
// index 0, must be relocated to some other index, otherwise they will appear transparent.
// This is accomplished by locating the first free pixel index in the palette and replacing
// all pixels with an index of 0 with the new index value. For example, if the number of
// palette entries returned from the partition request is 253, then all pixels with the
// index value of 0 will be replaced with the value 253 and the palette entry at index 253
// will contain the pixel definition from palette entry 0. Palette entry 0 will then be
// given the value which corresponds to (RGB) (0.0, 0.0, 1.0), which is full blue. This is
// done so that bitmaps which have been encoded with transparency information, allow tools
// such as photoshop, to display all the transparent regions with a color which is unlikely
// to appear in the bitmaps itself.
//
// Convert the palette entries from Max format 48bit to our internal format 24bit.
Convert(&ac24_palette[0], &bmm_palette[0], u_palette_entries+1);
// Deallocate the quantizer, since it is no longer needed.
pq_quantizer->DeleteThis();
}
// Flush the symbol table.
CSymTab st_export_bitmaps;
// Prepare to loop through the list again and start processing bitmaps.
pod_node = pod_object_list->podHead;
// Reset the object counter to 0
u_object = 0;
// Loop through all the objects in the scene.
while(pod_node)
{
// Loop through the material list for this object.
for (uint u_i=0; u_i < pod_node->uMaterialCount; u_i++)
{
TSTR tstr_texture_name;
TSTR tstr_opacity_name;
TSTR tstr_bump_name;
// Get the diffuse, opacity and bump bitmap names if they are present.
if (pod_node->astrTextureMap[u_i])
{
tstr_texture_name.printf("%s", pod_node->astrTextureMap[u_i]);
}
if (pod_node->astrOpacityMap[u_i])
{
tstr_opacity_name.printf("%s", pod_node->astrOpacityMap[u_i]);
}
if (pod_node->astrBumpMap[u_i])
{
tstr_bump_name.printf("%s", pod_node->astrBumpMap[u_i]);
}
// We have not seen this bitmap before so add it to the bitmap list.
if (!st_export_bitmaps.shLookup(pod_node->astrTextureMap[u_i]))
{
// We have not seen this bitmap before so add it to the bitmap list.
st_export_bitmaps.shInsert((char *) tstr_texture_name.data());
// Does the user want to quantize the bitmaps?
if (b_quantize_bitmaps)
{
// Process the bitmap. Were we successful?
if (!ProcessBitmap(tstr_texture_name, tstr_opacity_name, tstr_bump_name, bmm_palette, ac24_palette, u_palette_entries))
{
// Return an error.
b_result = false;
}
}
else
{
//
// No! Then make sure all the required bitmaps exist, otherwise a generated GROFF
// file will not be able to load successfully.
//
TSTR tstr_error_msg;
TSTR tstr_path;
TSTR tstr_file;
// Did the user supply a texture map?
if (tstr_texture_name.length() > 0 )
{
// Convert the bitmap to it's new name.
Convert_Path(tstr_texture_name);
// Does a bitmap exist in the map directory?
if (b_gen_groff && !FileExists(tstr_texture_name.data()))
{
//
// No! Then this is an error, but treat it as a warning because the user may
// know what he is doing. He has been warned.
//
SplitPathFile(tstr_texture_name, &tstr_path, &tstr_file);
tstr_path.printf("%s%s", guiInterface.strGetExportPath(), guiInterface.strGetBitmapDirName());
tstr_error_msg.printf(guiInterface.strGetString(IDS_POB_MISSING_QUANTIZED_BMP),
pod_node->estrObjectName.strData(), tstr_file.data(), tstr_path.data());
// Report the message to the user.
guiInterface.bWarningMsg(tstr_error_msg.data());
}
}
// Did the user supply an opacity map?
if (tstr_opacity_name.length() > 0)
{
Convert_Path(tstr_opacity_name);
}
// Did the user supply a bump map?
if (tstr_bump_name.length() > 0)
{
Convert_Path(tstr_bump_name);
// Does a bitmap exist in the map directory?
if (b_gen_groff && !FileExists(tstr_bump_name.data()))
{
//
// No! Then this is an error, but treat it as a warning because the user may
// know what he is doing. He has been warned.
//
SplitPathFile(tstr_bump_name, &tstr_path, &tstr_file);
tstr_path.printf("%s%s", guiInterface.strGetExportPath(), guiInterface.strGetBitmapDirName());
tstr_error_msg.printf(guiInterface.strGetString(IDS_POB_MISSING_BU_BMP),
pod_node->estrObjectName.strData(), tstr_file.data(), tstr_path.data());
// Report the message to the user.
guiInterface.bWarningMsg(tstr_error_msg.data());
}
}
}
}
else
{
//
// Major hack for now. Since the map has been seen, we must build the converted map names
// for the textures manually.
//
if (tstr_texture_name.length() > 0 )
{
Convert_Path(tstr_texture_name);
}
if (tstr_opacity_name.length() > 0)
{
Convert_Path(tstr_opacity_name);
}
if (tstr_bump_name.length() > 0)
{
Convert_Path(tstr_bump_name);
}
}
// Update all the bitmap names since they have changed.
pod_node->TextureName(u_i, tstr_texture_name.data());
pod_node->OpacityName(u_i, tstr_opacity_name.data());
pod_node->BumpmapName(u_i, tstr_bump_name.data());
}
// Increment the object counter.
u_object++;
// Advance to the next object in the list.
pod_node = pod_node->podNext;
}
// Return a successful result.
return b_result;
}
//**********************************************************************************************
//
int SingleMaterial(INode* pin_inode, CMathematicsUtil& mutil_utils)
{
Mtl* pmtl_material = pin_inode->GetMtl();
Class_ID cid_class_id;
TSTR tstr_export_name;
// Do we have a valid material?
if (pmtl_material == false)
{
// Report the error to the user.
mutil_utils.guiInterface.bErrorMsg(IDS_SM_MISSING_MTL);
// Return 0 indicating a material definition was not successfully processed.
return 0;
}
else
{
mutil_utils.slLogfile.Printf(guiInterface.strGetString(IDS_SINGLE_MTL));
}
// Make sure we are only handling standard materials.
cid_class_id = pmtl_material->ClassID();
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_MTL_CLASS_ID), cid_class_id.PartA(), cid_class_id.PartB());
// Is this material something other than a default material?
if (cid_class_id != Class_ID(DMTL_CLASS_ID, 0))
{
// Yes! We cannot do anything about this now so return an error.
mutil_utils.guiInterface.bErrorMsg(IDS_SM_MUST_USE_SM);
// Return 0 indicating a material definition was not successfully processed.
return 0;
}
//
// We now have identified this material as a default material. Setup a pointer to the
// standard material and determine the material's properties.
//
StdMat* psmtl_material = (StdMat *) pmtl_material;
// Get all the material default parameters.
MaterialDefaults(psmtl_material);
// Check the diffuse channel for a bitmap.
TSTR tstr_diffuse_name;
Texmap* ptm_diffuse_map = (BitmapTex *) psmtl_material->GetSubTexmap(ID_DI);
// Does this material have a map on the diffuse channel?
if (ptm_diffuse_map == false)
{
// No! Since a diffuse bitmap is required, report the error.
mutil_utils.guiInterface.bErrorMsg(IDS_SM_DIF_BMP_MISSING);
// Return 0 indicating a material definition was not successfully processed.
return 0;
}
// Determine if the diffuse texture map is a bitmap.
cid_class_id = ptm_diffuse_map->ClassID();
mutil_utils.slLogfile.Printf(guiInterface.strGetString(IDS_SM_DIF_BMP_ID), cid_class_id.PartA(), cid_class_id.PartB());
// Is this a bitmap texture?
if (cid_class_id != Class_ID(BMTEX_CLASS_ID, 0))
{
// No! This is not a bitmap so return an error.
mutil_utils.guiInterface.bErrorMsg(IDS_SM_DIF_MTL_INVALID_BMP);
// Return 0 indicating a material definition was not successfully processed.
return 0;
}
// Get the bitmap information.
BitmapTex* pbm_diffuse = (BitmapTex *) ptm_diffuse_map;
// Get the name of the bitmap.
tstr_diffuse_name = pbm_diffuse->GetMapName();
// Does a name exist with this bitmap?
if (tstr_diffuse_name.data() == 0)
{
// No! This should never happen as it indicates an internal MAX error.
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_BMP_MISSING_NAME));
// Return 0 indicating a material definition was not successfully processed.
return 0;
}
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_DIF_BMP_NAME), tstr_diffuse_name.data());
//
// Does this material have a map on the opacity channel?
//
TSTR tstr_opacity_name;
Texmap* ptm_opacity_map = (BitmapTex *) psmtl_material->GetSubTexmap(ID_OP);
if (ptm_opacity_map)
{
// Determine if the texture map is a Now make sure the texture map is a bitmap.
cid_class_id = ptm_opacity_map->ClassID();
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_SM_OP_BMP_ID), cid_class_id.PartA(), cid_class_id.PartB());
// Is this a bitmap texture?
if (cid_class_id != Class_ID(BMTEX_CLASS_ID, 0))
{
mutil_utils.guiInterface.bErrorMsg(IDS_SM_OP_MTL_INVALID_BMP);
// Return 0 indicating a material definition was not successfully processed.
return 0;
}
// Get the bitmap information.
BitmapTex* pbm_opacity = (BitmapTex *) ptm_opacity_map;
// Get the name of the bitmap.
tstr_opacity_name = pbm_opacity->GetMapName();
// Sanity check to make sure the name exists
if (tstr_opacity_name.data() == 0)
{
mutil_utils.guiInterface.bErrorMsg(IDS_BMP_MISSING_NAME);
// Return 0 indicating a material definition was not successfully processed.
return 0;
}
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_OP_BMP_NAME), tstr_opacity_name.data());
}
//
// Does this material have a map on the bump channel?
//
TSTR tstr_bump_name;
Texmap* ptm_bump_map = (BitmapTex *) psmtl_material->GetSubTexmap(ID_BU);
if (ptm_bump_map)
{
// Determine if the texture map is a Now make sure the texture map is a bitmap.
cid_class_id = ptm_bump_map->ClassID();
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_SM_BU_BMP_ID), cid_class_id.PartA(), cid_class_id.PartB());
// Is this a bitmap texture?
if (cid_class_id != Class_ID(BMTEX_CLASS_ID, 0))
{
mutil_utils.guiInterface.bErrorMsg(IDS_SM_BU_MTL_INVALID_BMP);
// Return 0 indicating a material definition was not successfully processed.
return 0;
}
// Get the bitmap information.
BitmapTex* pbm_bump = (BitmapTex *) ptm_bump_map;
// Get the name of the bitmap.
tstr_bump_name = pbm_bump->GetMapName();
// Sanity check to make sure the name exists
if (tstr_bump_name.data() == 0)
{
mutil_utils.guiInterface.bErrorMsg(IDS_BMP_MISSING_NAME);
// Return 0 indicating a material definition was not successfully processed.
return 0;
}
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_BU_BMP_NAME), tstr_bump_name.data());
// Get a copy of the texture output structure to determine texture strength.
TextureOutput* pto_texture_out = pbm_bump->GetTexout();
// Were we successful?
if (pto_texture_out != 0)
{
// Yes! Attempt to get the amount value for the bump map.
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_BU_STRENGTH), pto_texture_out->GetOutputLevel(0));
}
}
// We are using a single object material.
podCurrent->MaterialCount(1);
// Record the name of the diffuse bitmap.
if (tstr_diffuse_name.length() > 0)
{
podCurrent->TextureName(0, tstr_diffuse_name.data());
}
// Record the name of the opacity bitmap.
if (tstr_opacity_name.length() > 0)
{
podCurrent->OpacityName(0, tstr_opacity_name.data());
}
// Record the name of the bump bitmap.
if (tstr_bump_name.length() > 0)
{
podCurrent->BumpmapName(0, tstr_bump_name.data());
}
// Return 1 indicating the number of material definitions successfuly processed.
return 1;
}
//**********************************************************************************************
//
int MultiMaterial(INode* inode, CMathematicsUtil& mutil_utils)
{
Mtl* mtl = inode->GetMtl();
Class_ID CL_ID;
CSymTab st_symtab;
// Make sure we are only handling multi materials.
CL_ID = mtl->ClassID();
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_MULTI_MTL_DEF));
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_MTL_CLASS_ID), CL_ID.PartA(), CL_ID.PartB());
// Only multi-materials types are supports.
if (CL_ID != Class_ID(MULTI_CLASS_ID, 0))
{
// Report the error.
mutil_utils.guiInterface.bErrorMsg(IDS_MM_MUST_USE_MM);
// Return an error result.
return false;
}
// Are there any submaterials? There should be.
int i;
int SubMtls = mtl->NumSubMtls();
Mtl* sub;
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_SUB_MTL_COUNT), SubMtls);
// We must be looking at a multi-sub object material. We now know how many textures are
// associated with this material, so record it.
podCurrent->MaterialCount(SubMtls);
// Loop through all the materials and identify the bitmapped ones.
for (i = 0; i < SubMtls; i++)
{
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_SUB_MTL_NUM), i);
// Get each submaterial and make sure it is valid.
sub = mtl->GetSubMtl(i);
// Is this clot in use?
if (sub == 0)
{
// Continue on to next material
continue;
}
// Setup a pointer to the standard material.
StdMat* sm = (StdMat *) sub;
// Get the default material mapping, selection, values.
MaterialDefaults(sm);
// Is there a texture map on the diffuse channel?
Texmap* tm = (BitmapTex *) sm->GetSubTexmap(ID_DI);
if (!tm)
{
// No! report the error and move onto the next channel.
mutil_utils.guiInterface.bErrorPrintf(IDS_MM_DIF_BMP_MISSING, podCurrent->estrObjectName.strData(), i+1);
continue;
}
// Make sure this is a bitmap texture since we cannot process anything else
CL_ID = tm->ClassID();
if (CL_ID != Class_ID(BMTEX_CLASS_ID, 0))
{
mutil_utils.guiInterface.bErrorPrintf(IDS_MM_DIF_MTL_INVALID_BMP, i);
}
BitmapTex* bm = (BitmapTex *) tm;
TSTR tstr_diffuse_name;
TSTR tstr_export_name;
TSTR tstr_file;
TSTR tstr_path;
tstr_diffuse_name = bm->GetMapName();
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_EXP_FILENAME), tstr_export_name.data());
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_MM_DIF_BMP_ID), i, CL_ID.PartA(), CL_ID.PartB());
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_DIF_BMP_NAME), tstr_diffuse_name.data());
// Is there a bitmap map on the opacity channel?
TSTR tstr_opacity_name;
tstr_opacity_name.printf("");
// Get te texture associated with the opacity channel.
tm = (BitmapTex *) sm->GetSubTexmap(ID_OP);
if (tm)
{
// Make sure this is a bitmap texture since we don't support anything else.
CL_ID = tm->ClassID();
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_MM_OP_BMP_ID), i, CL_ID.PartA(), CL_ID.PartB());
// Make sure this texture is a bitmap. Is it?
if (CL_ID == Class_ID(BMTEX_CLASS_ID, 0))
{
bm = (BitmapTex *) tm;
// Get the opacity map name.
tstr_opacity_name = bm->GetMapName();
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_OP_BMP_NAME), tstr_opacity_name.data());
}
else
{
mutil_utils.guiInterface.bErrorPrintf(IDS_MM_OP_MTL_INVALID_BMP, i);
}
}
// Is there a texture map on the bump channel?
TSTR tstr_bump_name;
tstr_bump_name.printf("");
tm = (BitmapTex *) sm->GetSubTexmap(ID_BU);
if (tm)
{
// Make sure this is a bitmap texture since we don't support anything else.
CL_ID = tm->ClassID();
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_MM_BU_BMP_ID), i, CL_ID.PartA(), CL_ID.PartB());
// Make sure this texture is a bitmap. Is it?
if (CL_ID == Class_ID(BMTEX_CLASS_ID, 0))
{
bm = (BitmapTex *) tm;
// Get the opacity map name.
tstr_bump_name = bm->GetMapName();
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_BU_BMP_NAME), (char *) tstr_bump_name.data());
}
else
{
mutil_utils.guiInterface.bErrorPrintf(IDS_MM_BU_MTL_INVALID_BMP, i);
}
}
// Record the name of the diffuse bitmap.
if (tstr_diffuse_name.length() > 0)
{
podCurrent->TextureName(i, tstr_diffuse_name.data());
}
// Record the name of the opacity bitmap.
if (tstr_opacity_name.length() > 0)
{
podCurrent->OpacityName(i, tstr_opacity_name.data());
}
// Record the name of the bump bitmap.
if (tstr_bump_name.length() > 0)
{
podCurrent->BumpmapName(i, tstr_bump_name.data());
}
}
// Return the bitmap texture structure to the caller.
return SubMtls;
}
//**********************************************************************************************
//
uint uExtractFaces(Mesh& mesh, CMathematicsUtil& mutil_utils)
{
// Build the rendering normals.
mesh.buildRenderNormals();
// Setup constants for the face and vertex counts.
const uint u_faces = mesh.getNumFaces();
const uint u_vertices = mesh.getNumVerts();
// Display the title banner for the faces.
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_FACES_TITLE), u_faces);
// Register the polygon faces and the normals
podCurrent->FaceCount(u_faces);
podCurrent->FaceNormalCount(u_faces);
podCurrent->VertexNormalCount(u_faces);
// Loop through all the faces in the list and get the face vertex indices.
for (uint u_face = 0; u_face < u_faces; u_face++)
{
// Get the face vertex indices.
Face& face = mesh.faces[u_face];
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_FACE_DEFS), u_face,
face.v[0], face.v[1], face.v[2]);
}
// Display the title banner for the face normals.
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_FACE_NORMAL_TITLE), u_faces);
// Loop through all the faces in the list and get the face normals.
for (uint u_face = 0; u_face < u_faces; u_face++)
2018-01-01 22:07:24 +00:00
{
// Get the face normal.
Point3& pt3_normal = mesh.getFaceNormal(u_face);
mutil_utils.slLogfile.Printf(guiInterface.strGetString(IDS_FACE_NORMAL_DEFS), u_face,
pt3_normal.x, pt3_normal.y, pt3_normal.z);
// Record the face normal.
podCurrent->FaceNormal(u_face, pt3_normal[0], pt3_normal[1], pt3_normal[2]);
}
// Display the title banner for the vertex normals.
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_VERTEX_NORMAL_TITLE), u_faces);
// Now get the vertex normal list.
for (uint u_face = 0; u_face < u_faces; u_face++)
2018-01-01 22:07:24 +00:00
{
// Get the face vertex indices.
Face& face = mesh.faces[u_face];
// Register each of the vertex indices.
podCurrent->Face(u_face, (uint) face.v[0], (uint) face.v[1], (uint) face.v[2]);
// Get the smoothing group for this face.
uint u_smoothing_group = mesh.faces[u_face].getSmGroup();
// Loop through the vertex list.
for (uint u_vertex = 0; u_vertex < 3; u_vertex++)
{
int cv = mesh.faces[u_face].v[u_vertex];
// Get the rendering vertex.
RVertex* prv_render_vertex = mesh.getRVertPtr(cv);
Point3 pt3_normal;
if (prv_render_vertex->rFlags & SPECIFIED_NORMAL)
{
// Get the rendering normal (Circumstances???)
pt3_normal = prv_render_vertex->rn.getNormal();
}
else {
// Get the normal count for this face.
uint u_normal_count = (uint) (prv_render_vertex->rFlags & NORCT_MASK);
// If there are normals and the smoothing group is > 0 (i.e. not flat shaded).
if (u_normal_count && u_smoothing_group)
{
// Are the normals stored in the rendering information?
if (u_normal_count == 1)
{
// Yes! Then the normal is stored in in rn.
pt3_normal = prv_render_vertex->rn.getNormal();
}
else
{
// No! They are in the corrent place.
for (uint u_index = 0; u_index < u_normal_count; u_index++)
{
// Get the list of normals???
pt3_normal = prv_render_vertex->ern[u_index].getNormal();
}
}
}
else
{
//
// Either the smoothing group is zero or the normal count is zero. For
// now just use the face normal.
//
pt3_normal = mesh.getFaceNormal(u_face);
}
}
// Write the vertex normal out to the list.
podCurrent->VertexNormal(u_face, u_vertex, (float) pt3_normal.x, (float) pt3_normal.y,
(float) pt3_normal.z);
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_VERTEX_NORMAL_DEFS), u_face, u_vertex,
pt3_normal.x, pt3_normal.y, pt3_normal.z);
}
}
// Display the title banner for the face-material definitions.
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_FACE_MTL_TITLE), u_faces);
// Do we need to dump a material index as well?
if (Materials > 0)
{
// Yes! So inform the object manager that there are materials associated
// with this object.
podCurrent->TextureFaceCount((int) u_faces);
// For each of the faces, dump the material index.
for (uint u_face = 0; u_face < u_faces; u_face++)
{
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_FACE_MTL_DEFS), u_face,
mesh.faces[u_face].getMatID());
// Record the material index for this face.
podCurrent->FaceMaterialIndex(u_face, mesh.faces[u_face].getMatID());
}
}
// Return the face count.
return u_faces;
}
//**********************************************************************************************
//
uint uExtractTextureVertices(Mesh& mesh, CMathematicsUtil& mutil_utils)
{
// Determine the number of texture vertices to process.
const int i_tvert_count = mesh.getNumTVerts();
podCurrent->TextureVertexCount(i_tvert_count);
// Log the texture vertext count to the log file.
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_TVERT_TITLE), i_tvert_count);
// Extract the texture vertex list.
for (int i_i = 0; i_i < i_tvert_count; i_i++)
{
// Dump the texture vertex definition into the logfile.
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_TVERT_DEFS), i_i,
mesh.tVerts[i_i].x, mesh.tVerts[i_i].y);
// Record the texture vertex definition.
podCurrent->TextureVertex(i_i, mesh.tVerts[i_i].x, mesh.tVerts[i_i].y);
}
// Setup a count to the number of faces.
const int i_face_count = mesh.getNumFaces();
// Log the texture face title and count into the log file.
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_TFACE_TITLE), i_face_count);
// Process the texture face list
for (int i_i = 0; i_i < i_face_count; i_i++)
2018-01-01 22:07:24 +00:00
{
// Dump the texture face definition into the logfile.
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_TFACE_DEFS), i_i,
mesh.tvFace[i_i].t[0], mesh.tvFace[i_i].t[1], mesh.tvFace[i_i].t[2]);
// Record the texture face definition.
podCurrent->TextureFace(i_i, mesh.tvFace[i_i].t[0], mesh.tvFace[i_i].t[1], mesh.tvFace[i_i].t[2]);
}
// Return the texture vertex count.
return i_tvert_count;
}
//**********************************************************************************************
//
uint uExtractVertices(Mesh& mesh, CMathematicsUtil& mutil_utils)
{
//
uint u_count = mesh.getNumVerts();
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_VERTEX_TITLE), u_count);
// Register the number of vertices into the object
podCurrent->VertexCount((int) u_count);
// Loop through the vertex list and record each one.
Point3 p3_vertex;
for (uint u_i = 0; u_i < u_count; u_i++)
{
// Get a vertex.
p3_vertex = mesh.verts[u_i];
// Register the vertex in the logfile.
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_VERTEX_DEFS),
u_i, p3_vertex[0], p3_vertex[1], p3_vertex[2]);
// Record the vertex.
podCurrent->Vertex(u_i, p3_vertex[0], p3_vertex[1], p3_vertex[2]);
}
// Return the number of vertices in the list.
return u_count;
}
//**********************************************************************************************
//
bool bExtractMesh(CObjectListNode& oln_node, CMathematicsUtil& mutil_utils)
{
bool b_error = false;
// Add an object the object definition list
podCurrent = theList.podAddObject(oln_node.pobeEntry->tstrName.data());
//
// Display the banner for this object and the classification of the node.
//
mutil_utils.DisplayNewline();
mutil_utils.DisplayPrompt(guiInterface.strGetString(IDS_EQ_SEPARATOR));
// Get the INode of the object
INode* pin_inode = oln_node.pobeEntry->pinINode;
// Evaluate the world state at a specific point in time.
pin_inode->EvalWorldState(psep_the_scene_enum->tvTime).obj;
//
// Process the hierarchy of this object.
//
// Is this object a parent object a child?
if (pin_inode->IsRootNode())
{
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_ROOT_OBJECT), oln_node.pobeEntry->tstrName.data(),
pin_inode->NumberOfChildren());
}
else
{
// Is this object a child node, with children or a leaf?
int i_children = pin_inode->NumberOfChildren();
if (i_children)
{
// This is a child object so display the number of children.
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_CHILD_OBJECT), oln_node.pobeEntry->tstrName.data(),
pin_inode->NumberOfChildren());
}
else
{
// This is a leaf object with no children.
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_LEAF_OBJECT), oln_node.pobeEntry->tstrName.data(),
pin_inode->NumberOfChildren());
}
}
// Complete the banner.
mutil_utils.DisplayPrompt(guiInterface.strGetString(IDS_EQ_SEPARATOR));
//
// Process the Object attribute information.
//
//
// Display the OAL attribute source if it exists.
//
TSTR tstr_property_buffer;
pin_inode->GetUserPropBuffer(tstr_property_buffer);
// Is there any source associated with this object?
if (tstr_property_buffer.length() > 0)
{
// Yes! Then place it into the log file.
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_OAL_SOURCE), tstr_property_buffer.data());
}
//
// Construct a tri-mesg object for geometry processing.
//
// Setup a pointer to the scene object record then convert the object to a Tri-object.
Object* pobj_object = oln_node.pobeEntry->pobjObject;
TriObject* ptri_tri_object = (TriObject *) pobj_object->ConvertToType(psep_the_scene_enum->pipInterface->GetTime(),
triObjectClassID);
// Setup a reference to the mesh.
Mesh& mesh = ptri_tri_object->mesh;
//
// Extract all of the placement information.
//
// Get the object TM before WSM.
Matrix3 m3_tm_before_wsm = pin_inode->GetObjTMBeforeWSM(psep_the_scene_enum->tvTime);
mutil_utils.DisplayMatrix(mutil_utils.guiInterface.strGetString(IDS_TMBeforeWSM), m3_tm_before_wsm);
// Record it.
podCurrent->TMBeforeWSM(m3_tm_before_wsm);
// Get the object TM after WSM.
Matrix3 m3_tm_after_wsm = pin_inode->GetObjTMAfterWSM(psep_the_scene_enum->tvTime);
mutil_utils.DisplayMatrix(mutil_utils.guiInterface.strGetString(IDS_TMAfterWSM), m3_tm_after_wsm);
// Record it.
podCurrent->TMAfterWSM(m3_tm_after_wsm);
// Get the object TM.
Matrix3 m3_object_tm = pin_inode->GetObjectTM(psep_the_scene_enum->tvTime);
mutil_utils.DisplayMatrix(mutil_utils.guiInterface.strGetString(IDS_ObjectTM), m3_object_tm);
// Record it.
podCurrent->ObjectTM(m3_object_tm);
// Get the parent TM.
Matrix3 m3_parent_tm = pin_inode->GetParentTM(psep_the_scene_enum->tvTime);
mutil_utils.DisplayMatrix(mutil_utils.guiInterface.strGetString(IDS_ParentTM), m3_parent_tm);
// Record it.
podCurrent->ParentTM(m3_parent_tm);
// Get the node TM and display it.
Matrix3 m3_node_tm = pin_inode->GetNodeTM(psep_the_scene_enum->tvTime);
mutil_utils.DisplayMatrix(mutil_utils.guiInterface.strGetString(IDS_NodeTM), m3_node_tm);
// Record it.
podCurrent->NodeTM(m3_node_tm);
// Calculate the relative TM between the node and the parent.
Matrix3 m3_relative_tm = m3_node_tm * Inverse(m3_parent_tm);
mutil_utils.DisplayMatrix(mutil_utils.guiInterface.strGetString(IDS_RelativeTM), m3_relative_tm);
// Record it.
podCurrent->RelativeTM(m3_relative_tm);
// Display the objects positional information.
mutil_utils.DisplayPrompt(mutil_utils.guiInterface.strGetString(IDS_OBJ_OFF_TITLE1));
// Get the pivot offset information.
Point3 p3_offset_pos = pin_inode->GetObjOffsetPos();
mutil_utils.DisplayPrompt(mutil_utils.guiInterface.strGetString(IDS_PIVOT_OFF));
mutil_utils.DisplayVector(p3_offset_pos, 1);
// Record it.
podCurrent->PivotOffset(p3_offset_pos);
// Get the pivot orientation information.
Quat q_offset_rot = pin_inode->GetObjOffsetRot();
mutil_utils.DisplayQuat(mutil_utils.guiInterface.strGetString(IDS_PIVOT_ROT), q_offset_rot);
// Record it.
podCurrent->PivotRotation(q_offset_rot);
// For now setup the scaling values assuming uniform scaling.
podCurrent->Scale(1.0f);
// Get the object position.
Point3 p3_position = m3_tm_after_wsm.GetRow(3);
mutil_utils.DisplayPrompt(mutil_utils.guiInterface.strGetString(IDS_OBJ_POS));
mutil_utils.DisplayVector(p3_position);
// Record it.
podCurrent->Position(p3_position);
//
// Convert the rotation matrix to a quaternion. First, make sure that we are starting
// with an ortho-normal matrix since the constructor blindly assumes the matrix is
// orthogonal. The result being that a matrix with a non-unity (skewed) determinant
// will cause an invalid quaternion to be created which results in invalid placement
// of the object in the world. This effect is introduced by non-uniformly scaling an
// object, then collapsing it's stack.
//
m3_tm_after_wsm.Orthogonalize();
Quat q_orient(m3_tm_after_wsm);
mutil_utils.DisplayQuat(mutil_utils.guiInterface.strGetString(IDS_OBJ_ROT_QUAT), q_orient);
// Record it.
podCurrent->Rotation(q_orient);
// Get the Euler form of the rotation.
Point3 p3_rotation;
p3_rotation = podCurrent->p3GetRotation();
// Display the orientation angles angles as Convert the Euler angles to degrees.
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_F3_EULER), p3_rotation[0] * 180.0/3.1415926,
p3_rotation[1] * 180.0/3.1415926, p3_rotation[2] * 180.0/3.1415926);
//
// Get the bounding box of the mesh.
//
mesh.buildBoundingBox();
Box3 bx3_bounding_box = mesh.getBoundingBox();
mutil_utils.DisplayBox(mutil_utils.guiInterface.strGetString(IDS_OBJ_BBOX), bx3_bounding_box);
// Record it.
podCurrent->BoundingBox(bx3_bounding_box);
//
// Process the materials which are assigned to the object.
//
Mtl* mtl = pin_inode->GetMtl();
//
// Counter to keep track of the number of materials mapped on a surface,
// which is important because we must dump a material index for each of the
// textured faces within an object.
//
Materials = 0;
// Does this object have an associated amterial?
if (mtl != 0)
{
mutil_utils.DisplayPrompt(mutil_utils.guiInterface.strGetString(IDS_MTL_TITLE));
// Is this a single or multi-material?
if (mtl->IsMultiMtl())
{
// This is a multi-material object, so process it as such.
Materials = MultiMaterial(pin_inode, mutil_utils);
// Log the number of materials located for this object.
mutil_utils.slLogfile.Msg(mutil_utils.guiInterface.strGetString(IDS_MULTI_MTL), Materials);
}
else
{
// This is a single material object, so process it as such.
Materials = SingleMaterial(pin_inode, mutil_utils);
// Log the fact that this is a single material object.
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_SINGLE_MTL));
}
}
else
{
//
// In the future allow the user the ability for the user to export this object
// with a "flat shaded" material option so it can continue to work.
//
mutil_utils.guiInterface.bErrorPrintf(mutil_utils.guiInterface.strGetString(IDS_ERR_NO_MTLS), oln_node.pobeEntry->tstrName.data());
// Set the global error flag to true.
b_error = true;
// Set the material counter to 0.
Materials = 0;
}
//
// Does the mesh contain any vertices?
if (mesh.getNumVerts())
{
// Attempt to dump the point array. Were we successful?
if (uExtractVertices(mesh, mutil_utils) == 0)
{
// No! If the object was not already a tri_mesh, then delete the temporary copy.
if (pobj_object != (Object *) ptri_tri_object)
{
// Delete the mesh.
ptri_tri_object->DeleteThis();
}
// Return an error.
return false;
}
// Display a title banner for the world space vertex coordinates.
mutil_utils.DisplayPrompt(mutil_utils.guiInterface.strGetString(IDS_WORLD_SPACE_TITLE));
// Calculate the world space coordinate locations of the object.
Point3 p3_tmp;
for (int u_ii = 0; u_ii < mesh.getNumVerts(); u_ii++)
{
// Get a vertex from the file.
p3_tmp[0] = podCurrent->afv3Vertex[u_ii].X;
p3_tmp[1] = podCurrent->afv3Vertex[u_ii].Y;
p3_tmp[2] = podCurrent->afv3Vertex[u_ii].Z;
// Transform the objects vertices into world space.
p3_tmp = m3_tm_after_wsm * p3_tmp;
// Log the world vertex coordinate.
mutil_utils.slLogfile.Printf(mutil_utils.guiInterface.strGetString(IDS_WORLD_VERTEX_FMT), u_ii, p3_tmp[0], p3_tmp[1], p3_tmp[2]);
}
// Does this mesh have any faces?
if (mesh.getNumFaces())
{
// Process the face array.
if (uExtractFaces(mesh, mutil_utils) == 0)
{
// No! If the object was not already a tri_mesh, then delete the temporary copy.
if (pobj_object != (Object *) ptri_tri_object)
{
// Delete the mesh.
ptri_tri_object->DeleteThis();
}
// Return an error.
return false;
}
}
// Are there any texture vertices?
if (mesh.getNumTVerts())
{
// Process the texture vertices.
if (uExtractTextureVertices(mesh, mutil_utils) == 0)
{
// No! If the object was not already a tri_mesh, then delete the temporary copy.
if (pobj_object != (Object *) ptri_tri_object)
{
// Delete the mesh.
ptri_tri_object->DeleteThis();
}
// Return an error.
return false;
}
}
}
else
{
// No! Report the error, then exit.
mutil_utils.guiInterface.bErrorPrintf(mutil_utils.guiInterface.strGetString(IDS_ERR_NO_GEOMETRY),
oln_node.pobeEntry->tstrName.data());
// Set the global error flag to true.
b_error = true;
// Return an error.
return false;
}
// Make sure that we delete any meshes that were created during scene enumeration. Is this a candidate?
if (pobj_object != (Object *) ptri_tri_object)
{
// Yes! Delete it.
ptri_tri_object->DeleteThis();
}
// Return an error.
return false;
}
//**********************************************************************************************
//
uint uExtractNodes(CObjectList& ol_object_list, CMathematicsUtil& mutil_utils)
{
// Loop through all the objects in the scene.
for (uint u_i = 0; u_i < ol_object_list.uCount(); u_i++)
{
// Setup a pointer to a node in the list.
CObjectListNode* poln_node = ol_object_list[u_i];
// Determine what type of object we are looking at.
if (poln_node->pobeEntry->iType == TRIMESH_OBJECT)
{
// Yes! Were we able to succesfully extract the object information?
if (!bExtractMesh(*poln_node, mutil_utils))
{
// No! Return 0 as the number of nodes successfully extracted.
return 0;
}
}
else
{
// This is an unrecognized object type so report the error and return an error.
mutil_utils.guiInterface.bErrorMsg(IDS_INVALID_EXP_OBJ_TYPE);
}
}
// Return the number of objects successfully processed.
return ol_object_list.uCount();
}
//**********************************************************************************************
//
const TCHAR* JP2Export::Ext(int n)
{
// Since there is only one extension, just return it.
return guiInterface.strGetString(IDS_JP2_EXTENSION);
}
//**********************************************************************************************
//
const TCHAR* JP2Export::LongDesc()
{
// Return the long description.
return guiInterface.strGetString(IDS_JP2_LONGDESC);
}
//**********************************************************************************************
//
const TCHAR* JP2Export::ShortDesc()
{
// Return the short description.
return guiInterface.strGetString(IDS_JP2_SHORTDESC);
}
//**********************************************************************************************
//
const TCHAR* JP2Export::AuthorName()
{
// Return the author's name.
return guiInterface.strGetString(IDS_JP2_AUTHOR);
}
//**********************************************************************************************
//
const TCHAR* JP2Export::CopyrightMessage()
{
// Return the copyright message.
return guiInterface.strGetString(IDS_JP2_COPYRIGHT);
}
//**********************************************************************************************
//
unsigned int JP2Export::Version()
{
// Return the current exporter version number.
return EXPORTER_VERSION_NUMBER;
}
//**********************************************************************************************
//
void JP2Export::ShowAbout(HWND hWnd)
{
// Display an informational about box.
MessageBox(hWnd, guiInterface.strGetString(IDS_JP2_ABOUT_BOX),
guiInterface.strGetString(IDS_JP2_ABOUT_TITLE), MB_ICONINFORMATION | MB_OK);
}
//**********************************************************************************************
//
int JP2Export::DoExport(const TCHAR* tchr_export_filename, ExpInterface* pei_export_interface, Interface* pip_interface)
{
// Setup a local copy of the export filename.
CEasyString estr_export_filename(tchr_export_filename);
// Setup the parameter dialog.
if (!DialogBoxParam(guiInterface.GetInstance(), MAKEINTRESOURCE(IDD_EXPORT_OPTIONS), GetActiveWindow(),
ExportDlgProc, (LPARAM) this))
{
// Return an error.
return true;
}
// This type of export should generate a log file.
guiInterface.GenerateLogfiles(b_gen_logfiles);
// Attempt to build the Groff export file hierarchy. Were we successful?
if (!guiInterface.bBuildExportHierarchy(tchr_export_filename))
{
// No! Report the error then return.
guiInterface.bErrorMsg(guiInterface.strGetString(IDS_ERR_CONST_EXP_HIER));
// Return an error.
return true;
}
// Setup the GUI interface pointer in the GUI interface class.
guiInterface.SetInterface(pip_interface);
// Construct the complete file path.
char str_logfile[256];
guiInterface.BuildPath(str_logfile, guiInterface.strGetLogfileDirPath(), guiInterface.strGetString(IDS_FILENAME_EXPORT));
// Does the user want logfiles generated?
if (guiInterface.bGenerateLogfiles())
{
slLogfile.Open(str_logfile);
slLogfile.Enable();
}
else
{
// Disable a potentially open logfile.
slLogfile.Disable();
}
// Start out by enumerating all the nodes in the scene which we are interested in.
CSceneEnumProc sep_the_scene(pei_export_interface->theScene, pip_interface->GetTime(), pip_interface);
// Were any nodes located?
if (sep_the_scene.uCount() == 0)
{
// No! No inodes were located so notify the user and return.
guiInterface.bWarningMsg(IDS_NO_ENUMERATED_INODES);
// No! Display an error message.
guiInterface.bErrorMsg(guiInterface.strGetString(IDS_NO_GROFF_GEN));
// Free all the memory used by the code generator
theList.DeleteObjects();
// Return a successful result.
return true;
}
// Process all of the object names to make sure there are no duplicates.
sep_the_scene.BuildNames();
// Construct and object list.
CObjectList ol_the_objects(sep_the_scene);
// Setup global pointers to the object list and the scene enumeration list.
psep_the_scene_enum = &sep_the_scene;
// Setup the math utility structure.
CMathematicsUtil mutil_utility(guiInterface, slLogfile);
// Attempt to process the objects. Were we successful?
if (uExtractNodes(ol_the_objects, mutil_utility) == false)
{
// No! Display an error message.
guiInterface.bErrorMsg(guiInterface.strGetString(IDS_NO_GROFF_GEN));
// Free all the memory used by the code generator
theList.DeleteObjects();
// Return a successful result.
return true;
}
// Dump the list into a logfile.
theList.Dump();
// Check the geometry and make sure it's OK before processing the bitmaps.
CGeometry geo_geometry;
bool b_result = geo_geometry.bCheckScene(&theList, estr_export_filename);
// Close the logfile if it was open.
slLogfile.Close();
// Were we successful?
if (b_result)
{
// Process all the bitmaps.
if (ProcessObjectBitmaps(&theList, b_quantize_bmp, b_gen_groff))
{
CGroffExport ge;
// Does the user want a groff file to be generated?
if (b_gen_groff)
{
// Generate a GROFF file.
ge.bSaveScene(&theList, tchr_export_filename);
// Let the user know he has a GROFF file.
guiInterface.InfoMsg(guiInterface.strGetString(IDS_GROFF_GEN));
}
else
{
// Did the user request logfile creation only?
if (b_quantize_bmp && b_gen_logfiles)
{
// Yes! Then notify the user the logfile creation os complete.
guiInterface.InfoMsg(guiInterface.strGetString(IDS_QUANT_AND_GEN_LOGS));
}
// Did the user request logfile creation only?
else if (!b_quantize_bmp && b_gen_logfiles)
{
// Yes! Then notify the user the logfile creation os complete.
guiInterface.InfoMsg(guiInterface.strGetString(IDS_GEN_LOGFILES));
}
// Did the user request quantization only
else if (b_quantize_bmp && !b_gen_logfiles)
{
// Yes! Then notify the user the bitmaps were successfully quantized.
guiInterface.InfoMsg(guiInterface.strGetString(IDS_QUANTIZE_BMPS));
}
}
}
}
else
{
// No! Display an error message.
guiInterface.bErrorMsg(guiInterface.strGetString(IDS_NO_GROFF_GEN));
}
// Free all the memory used by the code generator
theList.DeleteObjects();
// Set the GUI interface pointer to null.
return true;
}
//Global variables and functions declared elsewhere as extern
//needed by the libraries
bool bIsTrespasser = false;
bool bUseReplayFile = false;
bool bInvertMouse = false;
bool bUseOutputFiles = false;
unsigned int g_u4NotifyParam = 0;
unsigned int u4LookupResourceString(int, char*, unsigned int) { return 0; }
void LineColour(int, int, int) {}
void* hwndGetMainHwnd() { return nullptr; }
HINSTANCE hinstGetMainHInstance() { return nullptr; }
void ResetAppData() {}
PFNWORLDLOADNOTIFY g_pfnWorldLoadNotify = nullptr;