panda3d/pandatool/src/lwoegg/lwoToEggConverter.cxx
2001-08-07 16:29:28 +00:00

498 lines
16 KiB
C++

// Filename: lwoToEggConverter.cxx
// Created by: drose (25Apr01)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "lwoToEggConverter.h"
#include "cLwoLayer.h"
#include "cLwoClip.h"
#include "cLwoPoints.h"
#include "cLwoPolygons.h"
#include "cLwoSurface.h"
#include "eggData.h"
#include "lwoHeader.h"
#include "lwoLayer.h"
#include "lwoClip.h"
#include "lwoPoints.h"
#include "lwoPolygons.h"
#include "lwoVertexMap.h"
#include "lwoDiscontinuousVertexMap.h"
#include "lwoTags.h"
#include "lwoPolygonTags.h"
#include "lwoInputFile.h"
#include "dcast.h"
////////////////////////////////////////////////////////////////////
// Function: LwoToEggConverter::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
LwoToEggConverter::
LwoToEggConverter() {
_generic_layer = (CLwoLayer *)NULL;
_make_materials = true;
}
////////////////////////////////////////////////////////////////////
// Function: LwoToEggConverter::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
LwoToEggConverter::
LwoToEggConverter(const LwoToEggConverter &copy) :
SomethingToEggConverter(copy)
{
}
////////////////////////////////////////////////////////////////////
// Function: LwoToEggConverter::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
LwoToEggConverter::
~LwoToEggConverter() {
cleanup();
}
////////////////////////////////////////////////////////////////////
// Function: LwoToEggConverter::make_copy
// Access: Public, Virtual
// Description: Allocates and returns a new copy of the converter.
////////////////////////////////////////////////////////////////////
SomethingToEggConverter *LwoToEggConverter::
make_copy() {
return new LwoToEggConverter(*this);
}
////////////////////////////////////////////////////////////////////
// Function: LwoToEggConverter::get_name
// Access: Public, Virtual
// Description: Returns the English name of the file type this
// converter supports.
////////////////////////////////////////////////////////////////////
string LwoToEggConverter::
get_name() const {
return "Lightwave";
}
////////////////////////////////////////////////////////////////////
// Function: LwoToEggConverter::get_extension
// Access: Public, Virtual
// Description: Returns the common extension of the file type this
// converter supports.
////////////////////////////////////////////////////////////////////
string LwoToEggConverter::
get_extension() const {
return "lwo";
}
////////////////////////////////////////////////////////////////////
// Function: LwoToEggConverter::convert_file
// Access: Public, Virtual
// Description: Handles the reading of the input file and converting
// it to egg. Returns true if successful, false
// otherwise.
//
// This is designed to be as generic as possible,
// generally in support of run-time loading.
// Command-line converters may choose to use
// convert_lwo() instead, as it provides more control.
////////////////////////////////////////////////////////////////////
bool LwoToEggConverter::
convert_file(const Filename &filename) {
LwoInputFile in;
nout << "Reading " << filename << "\n";
if (!in.open_read(filename)) {
nout << "Unable to open " << filename << "\n";
return false;
}
PT(IffChunk) chunk = in.get_chunk();
if (chunk == (IffChunk *)NULL) {
nout << "Unable to read " << filename << "\n";
return false;
}
if (!chunk->is_of_type(LwoHeader::get_class_type())) {
nout << "File " << filename << " is not a Lightwave Object file.\n";
return false;
}
LwoHeader *header = DCAST(LwoHeader, chunk);
if (!header->is_valid()) {
nout << "File " << filename
<< " is not recognized as a Lightwave Object file. "
<< "Perhaps the version is too recent.\n";
return false;
}
return convert_lwo(header);
}
////////////////////////////////////////////////////////////////////
// Function: LwoToEggConverter::convert_lwo
// Access: Public
// Description: Fills up the egg_data structure according to the
// indicated lwo structure.
////////////////////////////////////////////////////////////////////
bool LwoToEggConverter::
convert_lwo(const LwoHeader *lwo_header) {
if (_egg_data->get_coordinate_system() == CS_default) {
_egg_data->set_coordinate_system(CS_yup_left);
}
_error = false;
_lwo_header = lwo_header;
collect_lwo();
make_egg();
connect_egg();
_egg_data->remove_unused_vertices();
cleanup();
return !_error;
}
////////////////////////////////////////////////////////////////////
// Function: LwoToEggConverter::get_layer
// Access: Public
// Description: Returns a pointer to the layer with the given index
// number, or NULL if there is no such layer.
////////////////////////////////////////////////////////////////////
CLwoLayer *LwoToEggConverter::
get_layer(int number) const {
if (number >= 0 && number < (int)_layers.size()) {
return _layers[number];
}
return (CLwoLayer *)NULL;
}
////////////////////////////////////////////////////////////////////
// Function: LwoToEggConverter::get_clip
// Access: Public
// Description: Returns a pointer to the clip with the given index
// number, or NULL if there is no such clip.
////////////////////////////////////////////////////////////////////
CLwoClip *LwoToEggConverter::
get_clip(int number) const {
if (number >= 0 && number < (int)_clips.size()) {
return _clips[number];
}
return (CLwoClip *)NULL;
}
////////////////////////////////////////////////////////////////////
// Function: LwoToEggConverter::get_surface
// Access: Public
// Description: Returns a pointer to the surface definition with the
// given name, or NULL if there is no such surface.
////////////////////////////////////////////////////////////////////
CLwoSurface *LwoToEggConverter::
get_surface(const string &name) const {
Surfaces::const_iterator si;
si = _surfaces.find(name);
if (si != _surfaces.end()) {
return (*si).second;
}
return (CLwoSurface *)NULL;
}
////////////////////////////////////////////////////////////////////
// Function: LwoToEggConverter::cleanup
// Access: Private
// Description: Frees all the internal data structures after we're
// done converting, and resets the converter to its
// initial state.
////////////////////////////////////////////////////////////////////
void LwoToEggConverter::
cleanup() {
_lwo_header.clear();
if (_generic_layer != (CLwoLayer *)NULL) {
delete _generic_layer;
_generic_layer = (CLwoLayer *)NULL;
}
Layers::iterator li;
for (li = _layers.begin(); li != _layers.end(); ++li) {
CLwoLayer *layer = (*li);
if (layer != (CLwoLayer *)NULL) {
delete layer;
}
}
_layers.clear();
Clips::iterator ci;
for (ci = _clips.begin(); ci != _clips.end(); ++ci) {
CLwoClip *clip = (*ci);
if (clip != (CLwoClip *)NULL) {
delete clip;
}
}
_clips.clear();
Points::iterator pi;
for (pi = _points.begin(); pi != _points.end(); ++pi) {
CLwoPoints *points = (*pi);
delete points;
}
_points.clear();
Polygons::iterator gi;
for (gi = _polygons.begin(); gi != _polygons.end(); ++gi) {
CLwoPolygons *polygons = (*gi);
delete polygons;
}
_polygons.clear();
Surfaces::iterator si;
for (si = _surfaces.begin(); si != _surfaces.end(); ++si) {
CLwoSurface *surface = (*si).second;
delete surface;
}
_surfaces.clear();
}
////////////////////////////////////////////////////////////////////
// Function: LwoToEggConverter::collect_lwo
// Access: Private
// Description: Walks through the chunks in the Lightwave data and
// creates wrapper objects for each relevant piece.
////////////////////////////////////////////////////////////////////
void LwoToEggConverter::
collect_lwo() {
CLwoLayer *last_layer = (CLwoLayer *)NULL;
CLwoPoints *last_points = (CLwoPoints *)NULL;
CLwoPolygons *last_polygons = (CLwoPolygons *)NULL;
const LwoTags *tags = (const LwoTags *)NULL;
int num_chunks = _lwo_header->get_num_chunks();
for (int i = 0; i < num_chunks; i++) {
const IffChunk *chunk = _lwo_header->get_chunk(i);
if (chunk->is_of_type(LwoLayer::get_class_type())) {
const LwoLayer *lwo_layer = DCAST(LwoLayer, chunk);
CLwoLayer *layer = new CLwoLayer(this, lwo_layer);
int number = layer->get_number();
slot_layer(number);
if (_layers[number] != (CLwoLayer *)NULL) {
nout << "Warning: multiple layers with number " << number << "\n";
}
_layers[number] = layer;
last_layer = layer;
last_points = (CLwoPoints *)NULL;
last_polygons = (CLwoPolygons *)NULL;
} else if (chunk->is_of_type(LwoClip::get_class_type())) {
const LwoClip *lwo_clip = DCAST(LwoClip, chunk);
CLwoClip *clip = new CLwoClip(this, lwo_clip);
int index = clip->get_index();
slot_clip(index);
if (_clips[index] != (CLwoClip *)NULL) {
nout << "Warning: multiple clips with index " << index << "\n";
}
_clips[index] = clip;
} else if (chunk->is_of_type(LwoPoints::get_class_type())) {
if (last_layer == (CLwoLayer *)NULL) {
last_layer = make_generic_layer();
}
const LwoPoints *lwo_points = DCAST(LwoPoints, chunk);
CLwoPoints *points = new CLwoPoints(this, lwo_points, last_layer);
_points.push_back(points);
last_points = points;
} else if (chunk->is_of_type(LwoVertexMap::get_class_type())) {
if (last_points == (CLwoPoints *)NULL) {
nout << "Vertex map chunk encountered without a preceding points chunk.\n";
} else {
const LwoVertexMap *lwo_vmap = DCAST(LwoVertexMap, chunk);
last_points->add_vmap(lwo_vmap);
}
} else if (chunk->is_of_type(LwoDiscontinuousVertexMap::get_class_type())) {
if (last_polygons == (CLwoPolygons *)NULL) {
nout << "Discontinous vertex map chunk encountered without a preceding polygons chunk.\n";
} else {
const LwoDiscontinuousVertexMap *lwo_vmad = DCAST(LwoDiscontinuousVertexMap, chunk);
last_polygons->add_vmad(lwo_vmad);
}
} else if (chunk->is_of_type(LwoTags::get_class_type())) {
tags = DCAST(LwoTags, chunk);
} else if (chunk->is_of_type(LwoPolygons::get_class_type())) {
if (last_points == (CLwoPoints *)NULL) {
nout << "Polygon chunk encountered without a preceding points chunk.\n";
} else {
const LwoPolygons *lwo_polygons = DCAST(LwoPolygons, chunk);
CLwoPolygons *polygons =
new CLwoPolygons(this, lwo_polygons, last_points);
_polygons.push_back(polygons);
last_polygons = polygons;
}
} else if (chunk->is_of_type(LwoPolygonTags::get_class_type())) {
if (last_polygons == (CLwoPolygons *)NULL) {
nout << "Polygon tags chunk encountered without a preceding polygons chunk.\n";
} else if (tags == (LwoTags *)NULL) {
nout << "Polygon tags chunk encountered without a preceding tags chunk.\n";
} else {
const LwoPolygonTags *lwo_ptags = DCAST(LwoPolygonTags, chunk);
last_polygons->add_ptags(lwo_ptags, tags);
}
} else if (chunk->is_of_type(LwoSurface::get_class_type())) {
if (last_layer == (CLwoLayer *)NULL) {
last_layer = make_generic_layer();
}
const LwoSurface *lwo_surface = DCAST(LwoSurface, chunk);
CLwoSurface *surface = new CLwoSurface(this, lwo_surface);
bool inserted = _surfaces.insert(Surfaces::value_type(surface->get_name(), surface)).second;
if (!inserted) {
nout << "Multiple surface definitions named " << surface->get_name() << "\n";
delete surface;
}
}
}
}
////////////////////////////////////////////////////////////////////
// Function: LwoToEggConverter::make_egg
// Access: Private
// Description: Makes egg structures for all of the conversion
// wrapper objects.
////////////////////////////////////////////////////////////////////
void LwoToEggConverter::
make_egg() {
if (_generic_layer != (CLwoLayer *)NULL) {
_generic_layer->make_egg();
}
Layers::iterator li;
for (li = _layers.begin(); li != _layers.end(); ++li) {
CLwoLayer *layer = (*li);
if (layer != (CLwoLayer *)NULL) {
layer->make_egg();
}
}
Points::iterator pi;
for (pi = _points.begin(); pi != _points.end(); ++pi) {
CLwoPoints *points = (*pi);
points->make_egg();
}
Polygons::iterator gi;
for (gi = _polygons.begin(); gi != _polygons.end(); ++gi) {
CLwoPolygons *polygons = (*gi);
polygons->make_egg();
}
}
////////////////////////////////////////////////////////////////////
// Function: LwoToEggConverter::connect_egg
// Access: Private
// Description: Connects together all of the egg structures.
////////////////////////////////////////////////////////////////////
void LwoToEggConverter::
connect_egg() {
if (_generic_layer != (CLwoLayer *)NULL) {
_generic_layer->connect_egg();
}
Layers::iterator li;
for (li = _layers.begin(); li != _layers.end(); ++li) {
CLwoLayer *layer = (*li);
if (layer != (CLwoLayer *)NULL) {
layer->connect_egg();
}
}
Points::iterator pi;
for (pi = _points.begin(); pi != _points.end(); ++pi) {
CLwoPoints *points = (*pi);
points->connect_egg();
}
Polygons::iterator gi;
for (gi = _polygons.begin(); gi != _polygons.end(); ++gi) {
CLwoPolygons *polygons = (*gi);
polygons->connect_egg();
}
}
////////////////////////////////////////////////////////////////////
// Function: LwoToEggConverter::slot_layer
// Access: Private
// Description: Ensures that there is space in the _layers array to
// store an element at position number.
////////////////////////////////////////////////////////////////////
void LwoToEggConverter::
slot_layer(int number) {
nassertv(number - (int)_layers.size() < 1000);
while (number >= (int)_layers.size()) {
_layers.push_back((CLwoLayer *)NULL);
}
nassertv(number >= 0 && number < (int)_layers.size());
}
////////////////////////////////////////////////////////////////////
// Function: LwoToEggConverter::slot_clip
// Access: Private
// Description: Ensures that there is space in the _clips array to
// store an element at position number.
////////////////////////////////////////////////////////////////////
void LwoToEggConverter::
slot_clip(int number) {
nassertv(number - (int)_clips.size() < 1000);
while (number >= (int)_clips.size()) {
_clips.push_back((CLwoClip *)NULL);
}
nassertv(number >= 0 && number < (int)_clips.size());
}
////////////////////////////////////////////////////////////////////
// Function: LwoToEggConverter::make_generic_layer
// Access: Private
// Description: If a geometry definition is encountered in the
// Lightwave file before a layer definition, we should
// make a generic layer to hold the geometry. This
// makes and returns a single layer for this purpose.
// It should not be called twice.
////////////////////////////////////////////////////////////////////
CLwoLayer *LwoToEggConverter::
make_generic_layer() {
nassertr(_generic_layer == (CLwoLayer *)NULL, _generic_layer);
PT(LwoLayer) layer = new LwoLayer;
layer->make_generic();
_generic_layer = new CLwoLayer(this, layer);
return _generic_layer;
}