Panda3D
lwoToEggConverter.cxx
1 // Filename: lwoToEggConverter.cxx
2 // Created by: drose (25Apr01)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "lwoToEggConverter.h"
16 #include "cLwoLayer.h"
17 #include "cLwoClip.h"
18 #include "cLwoPoints.h"
19 #include "cLwoPolygons.h"
20 #include "cLwoSurface.h"
21 
22 #include "eggData.h"
23 #include "lwoHeader.h"
24 #include "lwoLayer.h"
25 #include "lwoClip.h"
26 #include "lwoPoints.h"
27 #include "lwoPolygons.h"
28 #include "lwoVertexMap.h"
29 #include "lwoDiscontinuousVertexMap.h"
30 #include "lwoTags.h"
31 #include "lwoPolygonTags.h"
32 #include "lwoInputFile.h"
33 #include "dcast.h"
34 
35 
36 ////////////////////////////////////////////////////////////////////
37 // Function: LwoToEggConverter::Constructor
38 // Access: Public
39 // Description:
40 ////////////////////////////////////////////////////////////////////
41 LwoToEggConverter::
42 LwoToEggConverter() {
43  _generic_layer = (CLwoLayer *)NULL;
44  _make_materials = true;
45 }
46 
47 ////////////////////////////////////////////////////////////////////
48 // Function: LwoToEggConverter::Copy Constructor
49 // Access: Public
50 // Description:
51 ////////////////////////////////////////////////////////////////////
52 LwoToEggConverter::
53 LwoToEggConverter(const LwoToEggConverter &copy) :
55 {
56 }
57 
58 ////////////////////////////////////////////////////////////////////
59 // Function: LwoToEggConverter::Destructor
60 // Access: Public, Virtual
61 // Description:
62 ////////////////////////////////////////////////////////////////////
63 LwoToEggConverter::
64 ~LwoToEggConverter() {
65  cleanup();
66 }
67 
68 ////////////////////////////////////////////////////////////////////
69 // Function: LwoToEggConverter::make_copy
70 // Access: Public, Virtual
71 // Description: Allocates and returns a new copy of the converter.
72 ////////////////////////////////////////////////////////////////////
75  return new LwoToEggConverter(*this);
76 }
77 
78 ////////////////////////////////////////////////////////////////////
79 // Function: LwoToEggConverter::get_name
80 // Access: Public, Virtual
81 // Description: Returns the English name of the file type this
82 // converter supports.
83 ////////////////////////////////////////////////////////////////////
85 get_name() const {
86  return "Lightwave";
87 }
88 
89 ////////////////////////////////////////////////////////////////////
90 // Function: LwoToEggConverter::get_extension
91 // Access: Public, Virtual
92 // Description: Returns the common extension of the file type this
93 // converter supports.
94 ////////////////////////////////////////////////////////////////////
96 get_extension() const {
97  return "lwo";
98 }
99 
100 ////////////////////////////////////////////////////////////////////
101 // Function: LwoToEggConverter::supports_compressed
102 // Access: Published, Virtual
103 // Description: Returns true if this file type can transparently load
104 // compressed files (with a .pz extension), false
105 // otherwise.
106 ////////////////////////////////////////////////////////////////////
109  return true;
110 }
111 
112 ////////////////////////////////////////////////////////////////////
113 // Function: LwoToEggConverter::convert_file
114 // Access: Public, Virtual
115 // Description: Handles the reading of the input file and converting
116 // it to egg. Returns true if successful, false
117 // otherwise.
118 //
119 // This is designed to be as generic as possible,
120 // generally in support of run-time loading.
121 // Command-line converters may choose to use
122 // convert_lwo() instead, as it provides more control.
123 ////////////////////////////////////////////////////////////////////
125 convert_file(const Filename &filename) {
126  LwoInputFile in;
127 
128  nout << "Reading " << filename << "\n";
129  if (!in.open_read(filename)) {
130  nout << "Unable to open " << filename << "\n";
131  return false;
132  }
133 
134  PT(IffChunk) chunk = in.get_chunk();
135  if (chunk == (IffChunk *)NULL) {
136  nout << "Unable to read " << filename << "\n";
137  return false;
138  }
139 
140  if (!chunk->is_of_type(LwoHeader::get_class_type())) {
141  nout << "File " << filename << " is not a Lightwave Object file.\n";
142  return false;
143  }
144 
145  LwoHeader *header = DCAST(LwoHeader, chunk);
146  if (!header->is_valid()) {
147  nout << "File " << filename
148  << " is not recognized as a Lightwave Object file. "
149  << "Perhaps the version is too recent.\n";
150  return false;
151  }
152 
153  return convert_lwo(header);
154 }
155 
156 ////////////////////////////////////////////////////////////////////
157 // Function: LwoToEggConverter::convert_lwo
158 // Access: Public
159 // Description: Fills up the egg_data structure according to the
160 // indicated lwo structure.
161 ////////////////////////////////////////////////////////////////////
163 convert_lwo(const LwoHeader *lwo_header) {
164  if (_egg_data->get_coordinate_system() == CS_default) {
165  _egg_data->set_coordinate_system(CS_yup_left);
166  }
167 
168  _error = false;
169  _lwo_header = lwo_header;
170 
171  collect_lwo();
172  make_egg();
173  connect_egg();
174 
175  _egg_data->remove_unused_vertices(true);
176  cleanup();
177 
178  return !had_error();
179 }
180 
181 ////////////////////////////////////////////////////////////////////
182 // Function: LwoToEggConverter::get_layer
183 // Access: Public
184 // Description: Returns a pointer to the layer with the given index
185 // number, or NULL if there is no such layer.
186 ////////////////////////////////////////////////////////////////////
188 get_layer(int number) const {
189  if (number >= 0 && number < (int)_layers.size()) {
190  return _layers[number];
191  }
192  return (CLwoLayer *)NULL;
193 }
194 
195 ////////////////////////////////////////////////////////////////////
196 // Function: LwoToEggConverter::get_clip
197 // Access: Public
198 // Description: Returns a pointer to the clip with the given index
199 // number, or NULL if there is no such clip.
200 ////////////////////////////////////////////////////////////////////
202 get_clip(int number) const {
203  if (number >= 0 && number < (int)_clips.size()) {
204  return _clips[number];
205  }
206  return (CLwoClip *)NULL;
207 }
208 
209 ////////////////////////////////////////////////////////////////////
210 // Function: LwoToEggConverter::get_surface
211 // Access: Public
212 // Description: Returns a pointer to the surface definition with the
213 // given name, or NULL if there is no such surface.
214 ////////////////////////////////////////////////////////////////////
216 get_surface(const string &name) const {
217  Surfaces::const_iterator si;
218  si = _surfaces.find(name);
219  if (si != _surfaces.end()) {
220  return (*si).second;
221  }
222  return (CLwoSurface *)NULL;
223 }
224 
225 ////////////////////////////////////////////////////////////////////
226 // Function: LwoToEggConverter::cleanup
227 // Access: Private
228 // Description: Frees all the internal data structures after we're
229 // done converting, and resets the converter to its
230 // initial state.
231 ////////////////////////////////////////////////////////////////////
232 void LwoToEggConverter::
233 cleanup() {
234  _lwo_header.clear();
235 
236  if (_generic_layer != (CLwoLayer *)NULL) {
237  delete _generic_layer;
238  _generic_layer = (CLwoLayer *)NULL;
239  }
240 
241  Layers::iterator li;
242  for (li = _layers.begin(); li != _layers.end(); ++li) {
243  CLwoLayer *layer = (*li);
244  if (layer != (CLwoLayer *)NULL) {
245  delete layer;
246  }
247  }
248  _layers.clear();
249 
250  Clips::iterator ci;
251  for (ci = _clips.begin(); ci != _clips.end(); ++ci) {
252  CLwoClip *clip = (*ci);
253  if (clip != (CLwoClip *)NULL) {
254  delete clip;
255  }
256  }
257  _clips.clear();
258 
259  Points::iterator pi;
260  for (pi = _points.begin(); pi != _points.end(); ++pi) {
261  CLwoPoints *points = (*pi);
262  delete points;
263  }
264  _points.clear();
265 
266  Polygons::iterator gi;
267  for (gi = _polygons.begin(); gi != _polygons.end(); ++gi) {
268  CLwoPolygons *polygons = (*gi);
269  delete polygons;
270  }
271  _polygons.clear();
272 
273  Surfaces::iterator si;
274  for (si = _surfaces.begin(); si != _surfaces.end(); ++si) {
275  CLwoSurface *surface = (*si).second;
276  delete surface;
277  }
278  _surfaces.clear();
279 }
280 
281 ////////////////////////////////////////////////////////////////////
282 // Function: LwoToEggConverter::collect_lwo
283 // Access: Private
284 // Description: Walks through the chunks in the Lightwave data and
285 // creates wrapper objects for each relevant piece.
286 ////////////////////////////////////////////////////////////////////
287 void LwoToEggConverter::
288 collect_lwo() {
289  CLwoLayer *last_layer = (CLwoLayer *)NULL;
290  CLwoPoints *last_points = (CLwoPoints *)NULL;
291  CLwoPolygons *last_polygons = (CLwoPolygons *)NULL;
292 
293  const LwoTags *tags = (const LwoTags *)NULL;
294 
295  int num_chunks = _lwo_header->get_num_chunks();
296  for (int i = 0; i < num_chunks; i++) {
297  const IffChunk *chunk = _lwo_header->get_chunk(i);
298 
299  if (chunk->is_of_type(LwoLayer::get_class_type())) {
300  const LwoLayer *lwo_layer = DCAST(LwoLayer, chunk);
301  CLwoLayer *layer = new CLwoLayer(this, lwo_layer);
302  int number = layer->get_number();
303  slot_layer(number);
304 
305  if (_layers[number] != (CLwoLayer *)NULL) {
306  nout << "Warning: multiple layers with number " << number << "\n";
307  }
308  _layers[number] = layer;
309  last_layer = layer;
310  last_points = (CLwoPoints *)NULL;
311  last_polygons = (CLwoPolygons *)NULL;
312 
313  } else if (chunk->is_of_type(LwoClip::get_class_type())) {
314  const LwoClip *lwo_clip = DCAST(LwoClip, chunk);
315  CLwoClip *clip = new CLwoClip(this, lwo_clip);
316 
317  int index = clip->get_index();
318  slot_clip(index);
319 
320  if (_clips[index] != (CLwoClip *)NULL) {
321  nout << "Warning: multiple clips with index " << index << "\n";
322  }
323  _clips[index] = clip;
324 
325  } else if (chunk->is_of_type(LwoPoints::get_class_type())) {
326  if (last_layer == (CLwoLayer *)NULL) {
327  last_layer = make_generic_layer();
328  }
329 
330  const LwoPoints *lwo_points = DCAST(LwoPoints, chunk);
331  CLwoPoints *points = new CLwoPoints(this, lwo_points, last_layer);
332  _points.push_back(points);
333  last_points = points;
334 
335  } else if (chunk->is_of_type(LwoVertexMap::get_class_type())) {
336  if (last_points == (CLwoPoints *)NULL) {
337  nout << "Vertex map chunk encountered without a preceding points chunk.\n";
338  } else {
339  const LwoVertexMap *lwo_vmap = DCAST(LwoVertexMap, chunk);
340  last_points->add_vmap(lwo_vmap);
341  }
342 
343  } else if (chunk->is_of_type(LwoDiscontinuousVertexMap::get_class_type())) {
344  if (last_polygons == (CLwoPolygons *)NULL) {
345  nout << "Discontinous vertex map chunk encountered without a preceding polygons chunk.\n";
346  } else {
347  const LwoDiscontinuousVertexMap *lwo_vmad = DCAST(LwoDiscontinuousVertexMap, chunk);
348  last_polygons->add_vmad(lwo_vmad);
349  }
350 
351  } else if (chunk->is_of_type(LwoTags::get_class_type())) {
352  tags = DCAST(LwoTags, chunk);
353 
354  } else if (chunk->is_of_type(LwoPolygons::get_class_type())) {
355  if (last_points == (CLwoPoints *)NULL) {
356  nout << "Polygon chunk encountered without a preceding points chunk.\n";
357  } else {
358  const LwoPolygons *lwo_polygons = DCAST(LwoPolygons, chunk);
359  CLwoPolygons *polygons =
360  new CLwoPolygons(this, lwo_polygons, last_points);
361  _polygons.push_back(polygons);
362  last_polygons = polygons;
363  }
364 
365  } else if (chunk->is_of_type(LwoPolygonTags::get_class_type())) {
366  if (last_polygons == (CLwoPolygons *)NULL) {
367  nout << "Polygon tags chunk encountered without a preceding polygons chunk.\n";
368  } else if (tags == (LwoTags *)NULL) {
369  nout << "Polygon tags chunk encountered without a preceding tags chunk.\n";
370  } else {
371  const LwoPolygonTags *lwo_ptags = DCAST(LwoPolygonTags, chunk);
372  last_polygons->add_ptags(lwo_ptags, tags);
373  }
374 
375  } else if (chunk->is_of_type(LwoSurface::get_class_type())) {
376  if (last_layer == (CLwoLayer *)NULL) {
377  last_layer = make_generic_layer();
378  }
379 
380  const LwoSurface *lwo_surface = DCAST(LwoSurface, chunk);
381  CLwoSurface *surface = new CLwoSurface(this, lwo_surface);
382 
383  bool inserted = _surfaces.insert(Surfaces::value_type(surface->get_name(), surface)).second;
384  if (!inserted) {
385  nout << "Multiple surface definitions named " << surface->get_name() << "\n";
386  delete surface;
387  }
388  }
389  }
390 }
391 
392 ////////////////////////////////////////////////////////////////////
393 // Function: LwoToEggConverter::make_egg
394 // Access: Private
395 // Description: Makes egg structures for all of the conversion
396 // wrapper objects.
397 ////////////////////////////////////////////////////////////////////
398 void LwoToEggConverter::
399 make_egg() {
400  if (_generic_layer != (CLwoLayer *)NULL) {
401  _generic_layer->make_egg();
402  }
403 
404  Layers::iterator li;
405  for (li = _layers.begin(); li != _layers.end(); ++li) {
406  CLwoLayer *layer = (*li);
407  if (layer != (CLwoLayer *)NULL) {
408  layer->make_egg();
409  }
410  }
411 
412  Points::iterator pi;
413  for (pi = _points.begin(); pi != _points.end(); ++pi) {
414  CLwoPoints *points = (*pi);
415  points->make_egg();
416  }
417 
418  Polygons::iterator gi;
419  for (gi = _polygons.begin(); gi != _polygons.end(); ++gi) {
420  CLwoPolygons *polygons = (*gi);
421  polygons->make_egg();
422  }
423 }
424 
425 ////////////////////////////////////////////////////////////////////
426 // Function: LwoToEggConverter::connect_egg
427 // Access: Private
428 // Description: Connects together all of the egg structures.
429 ////////////////////////////////////////////////////////////////////
430 void LwoToEggConverter::
431 connect_egg() {
432  if (_generic_layer != (CLwoLayer *)NULL) {
433  _generic_layer->connect_egg();
434  }
435 
436  Layers::iterator li;
437  for (li = _layers.begin(); li != _layers.end(); ++li) {
438  CLwoLayer *layer = (*li);
439  if (layer != (CLwoLayer *)NULL) {
440  layer->connect_egg();
441  }
442  }
443 
444  Points::iterator pi;
445  for (pi = _points.begin(); pi != _points.end(); ++pi) {
446  CLwoPoints *points = (*pi);
447  points->connect_egg();
448  }
449 
450  Polygons::iterator gi;
451  for (gi = _polygons.begin(); gi != _polygons.end(); ++gi) {
452  CLwoPolygons *polygons = (*gi);
453  polygons->connect_egg();
454  }
455 }
456 
457 ////////////////////////////////////////////////////////////////////
458 // Function: LwoToEggConverter::slot_layer
459 // Access: Private
460 // Description: Ensures that there is space in the _layers array to
461 // store an element at position number.
462 ////////////////////////////////////////////////////////////////////
463 void LwoToEggConverter::
464 slot_layer(int number) {
465  nassertv(number - (int)_layers.size() < 1000);
466  while (number >= (int)_layers.size()) {
467  _layers.push_back((CLwoLayer *)NULL);
468  }
469  nassertv(number >= 0 && number < (int)_layers.size());
470 }
471 
472 ////////////////////////////////////////////////////////////////////
473 // Function: LwoToEggConverter::slot_clip
474 // Access: Private
475 // Description: Ensures that there is space in the _clips array to
476 // store an element at position number.
477 ////////////////////////////////////////////////////////////////////
478 void LwoToEggConverter::
479 slot_clip(int number) {
480  nassertv(number - (int)_clips.size() < 1000);
481  while (number >= (int)_clips.size()) {
482  _clips.push_back((CLwoClip *)NULL);
483  }
484  nassertv(number >= 0 && number < (int)_clips.size());
485 }
486 
487 ////////////////////////////////////////////////////////////////////
488 // Function: LwoToEggConverter::make_generic_layer
489 // Access: Private
490 // Description: If a geometry definition is encountered in the
491 // Lightwave file before a layer definition, we should
492 // make a generic layer to hold the geometry. This
493 // makes and returns a single layer for this purpose.
494 // It should not be called twice.
495 ////////////////////////////////////////////////////////////////////
496 CLwoLayer *LwoToEggConverter::
497 make_generic_layer() {
498  nassertr(_generic_layer == (CLwoLayer *)NULL, _generic_layer);
499 
500  PT(LwoLayer) layer = new LwoLayer;
501  layer->make_generic();
502 
503  _generic_layer = new CLwoLayer(this, layer);
504  return _generic_layer;
505 }
CLwoSurface * get_surface(const string &name) const
Returns a pointer to the surface definition with the given name, or NULL if there is no such surface...
virtual string get_name() const
Returns the English name of the file type this converter supports.
int get_number() const
Returns the index number associated with this particular layer.
Definition: cLwoLayer.I:36
void add_vmad(const LwoDiscontinuousVertexMap *lwo_vmad)
Associates the indicated DiscontinousVertexMap with the polygons.
void add_ptags(const LwoPolygonTags *lwo_ptags, const LwoTags *tags)
Associates the indicated PolygonTags and Tags with the polygons in this chunk.
void make_egg()
Creates the egg structures associated with this Lightwave object.
Definition: cLwoPoints.cxx:92
bool had_error() const
Returns true if an error was detected during the conversion process (unless _allow_errors is true)...
Describes the shading attributes of a surface.
Definition: lwoSurface.h:28
An association of polygons defined in the most recent LwoPolygons chunk to tag ids defined in the mos...
void add_vmap(const LwoVertexMap *lwo_vmap)
Associates the indicated VertexMap with the points set.
Definition: cLwoPoints.cxx:31
This class is a wrapper around LwoPolygons and stores additional information useful during the conver...
Definition: cLwoPolygons.h:39
The first chunk in a Lightwave Object file.
Definition: lwoHeader.h:26
void make_egg()
Creates the egg structures associated with this Lightwave object.
Definition: cLwoLayer.cxx:28
A single image file, or a numbered sequence of images (e.g.
Definition: lwoClip.h:27
virtual string get_extension() const
Returns the common extension of the file type this converter supports.
An array of tag strings that will be referenced by later chunks.
Definition: lwoTags.h:35
const string & get_name() const
Returns the name of the surface.
Definition: cLwoSurface.I:23
bool open_read(Filename filename)
Attempts to open the indicated filename for reading.
void make_egg()
Creates the egg structures associated with this Lightwave object.
This class is a wrapper around LwoClip and stores additional information useful during the conversion...
Definition: cLwoClip.h:32
This class is a wrapper around LwoSurface and stores additional information useful during the convers...
Definition: cLwoSurface.h:42
The basic kind of record in an EA "IFF" file, which the LightWave object file is based on...
Definition: iffChunk.h:32
int get_index() const
Returns the index number of this clip.
Definition: cLwoClip.I:24
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
This class is a wrapper around LwoLayer and stores additional information useful during the conversio...
Definition: cLwoLayer.h:32
bool convert_lwo(const LwoHeader *lwo_header)
Fills up the egg_data structure according to the indicated lwo structure.
CLwoLayer * get_layer(int number) const
Returns a pointer to the layer with the given index number, or NULL if there is no such layer...
Signals the start of a new layer.
Definition: lwoLayer.h:32
A mapping of floating-point values per integer index.
Definition: lwoVertexMap.h:30
void connect_egg()
Connects all the egg structures together.
Definition: cLwoPoints.cxx:105
This class supervises the construction of an EggData structure from the data represented by the LwoHe...
virtual SomethingToEggConverter * make_copy()
Allocates and returns a new copy of the converter.
bool is_valid() const
Returns true if the header represents a valid and recognized Lightwave header, false otherwise...
Definition: lwoHeader.I:23
CLwoClip * get_clip(int number) const
Returns a pointer to the clip with the given index number, or NULL if there is no such clip...
A specialization of IffInputFile to handle reading a Lightwave Object file.
Definition: lwoInputFile.h:29
This class is a wrapper around LwoPoints and stores additional information useful during the conversi...
Definition: cLwoPoints.h:36
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:63
void connect_egg()
Connects all the egg structures together.
Definition: cLwoLayer.cxx:46
virtual bool supports_compressed() const
Returns true if this file type can transparently load compressed files (with a .pz extension)...
An array of polygons that will be referenced by later chunks.
Definition: lwoPolygons.h:32
void make_generic()
Resets the layer&#39;s parameters to initial defaults for a generic layer created implicitly.
Definition: lwoLayer.cxx:30
void connect_egg()
Connects all the egg structures together.
A mapping of floating-point values per integer index.
This is a base class for a family of converter classes that manage a conversion from some file type t...
An array of points that will be referenced by later chunks.
Definition: lwoPoints.h:29
virtual bool convert_file(const Filename &filename)
Handles the reading of the input file and converting it to egg.