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"
|
2020-04-04 12:01:50 +00:00
|
|
|
#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:
|
|
|
|
|
2020-04-04 12:01:50 +00:00
|
|
|
|
2018-01-01 22:07:24 +00:00
|
|
|
//******************************************************************************************
|
|
|
|
//
|
|
|
|
int IsPublic
|
|
|
|
(
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//******************************************************************************************
|
|
|
|
//
|
|
|
|
void* Create
|
|
|
|
(
|
2020-04-04 12:01:50 +00:00
|
|
|
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.
|
2020-04-04 12:01:50 +00:00
|
|
|
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.
|
2020-04-04 12:01:50 +00:00
|
|
|
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
|
2020-04-04 12:01:50 +00:00
|
|
|
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;
|
2020-04-09 17:28:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//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;
|