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