mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 18:31:55 -04:00
498 lines
16 KiB
C++
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 ©) :
|
|
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;
|
|
}
|