Panda3D
 All Classes Functions Variables Enumerations
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 }
bool is_valid() const
Returns true if the header represents a valid and recognized Lightwave header, false otherwise...
Definition: lwoHeader.I:23
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
const string & get_name() const
Returns the name of the surface.
Definition: cLwoSurface.I:23
Describes the shading attributes of a surface.
Definition: lwoSurface.h:28
int get_index() const
Returns the index number of this clip.
Definition: cLwoClip.I:24
virtual string get_extension() const
Returns the common extension of the file type this converter supports.
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
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:63
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
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...
An array of tag strings that will be referenced by later chunks.
Definition: lwoTags.h:35
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 &quot;IFF&quot; file, which the LightWave object file is based on...
Definition: iffChunk.h:32
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.
int get_number() const
Returns the index number associated with this particular layer.
Definition: cLwoLayer.I:36
Signals the start of a new layer.
Definition: lwoLayer.h:32
virtual string get_name() const
Returns the English name of the file type this converter supports.
bool had_error() const
Returns true if an error was detected during the conversion process (unless _allow_errors is true)...
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.
A specialization of IffInputFile to handle reading a Lightwave Object file.
Definition: lwoInputFile.h:29
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...
This class is a wrapper around LwoPoints and stores additional information useful during the conversi...
Definition: cLwoPoints.h:36
virtual bool supports_compressed() const
Returns true if this file type can transparently load compressed files (with a .pz extension)...
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...
void connect_egg()
Connects all the egg structures together.
Definition: cLwoLayer.cxx:46
An array of polygons that will be referenced by later chunks.
Definition: lwoPolygons.h:32
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.