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  */
65 make_copy() {
66  return new LwoToEggConverter(*this);
67 }
68 
69 /**
70  * Returns the English name of the file type this converter supports.
71  */
73 get_name() const {
74  return "Lightwave";
75 }
76 
77 /**
78  * Returns the common extension of the file type this converter supports.
79  */
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  */
90 supports_compressed() const {
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 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class is a wrapper around LwoClip and stores additional information useful during the conversion...
Definition: cLwoClip.h:29
int get_index() const
Returns the index number of this clip.
Definition: cLwoClip.I:19
This class is a wrapper around LwoLayer and stores additional information useful during the conversio...
Definition: cLwoLayer.h:29
void make_egg()
Creates the egg structures associated with this Lightwave object.
Definition: cLwoLayer.cxx:24
int get_number() const
Returns the index number associated with this particular layer.
Definition: cLwoLayer.I:29
void connect_egg()
Connects all the egg structures together.
Definition: cLwoLayer.cxx:39
This class is a wrapper around LwoPoints and stores additional information useful during the conversi...
Definition: cLwoPoints.h:33
void make_egg()
Creates the egg structures associated with this Lightwave object.
Definition: cLwoPoints.cxx:82
void add_vmap(const LwoVertexMap *lwo_vmap)
Associates the indicated VertexMap with the points set.
Definition: cLwoPoints.cxx:27
void connect_egg()
Connects all the egg structures together.
Definition: cLwoPoints.cxx:93
This class is a wrapper around LwoPolygons and stores additional information useful during the conver...
Definition: cLwoPolygons.h:36
void make_egg()
Creates the egg structures associated with this Lightwave object.
void connect_egg()
Connects all the egg structures together.
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.
This class is a wrapper around LwoSurface and stores additional information useful during the convers...
Definition: cLwoSurface.h:39
const std::string & get_name() const
Returns the name of the surface.
Definition: cLwoSurface.I:19
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
The basic kind of record in an EA "IFF" file, which the LightWave object file is based on.
Definition: iffChunk.h:30
bool open_read(Filename filename)
Attempts to open the indicated filename for reading.
A single image file, or a numbered sequence of images (e.g.
Definition: lwoClip.h:25
A mapping of floating-point values per integer index.
The first chunk in a Lightwave Object file.
Definition: lwoHeader.h:24
bool is_valid() const
Returns true if the header represents a valid and recognized Lightwave header, false otherwise.
Definition: lwoHeader.I:19
A specialization of IffInputFile to handle reading a Lightwave Object file.
Definition: lwoInputFile.h:26
Signals the start of a new layer.
Definition: lwoLayer.h:28
An array of points that will be referenced by later chunks.
Definition: lwoPoints.h:26
An association of polygons defined in the most recent LwoPolygons chunk to tag ids defined in the mos...
An array of polygons that will be referenced by later chunks.
Definition: lwoPolygons.h:29
Describes the shading attributes of a surface.
Definition: lwoSurface.h:25
An array of tag strings that will be referenced by later chunks.
Definition: lwoTags.h:31
This class supervises the construction of an EggData structure from the data represented by the LwoHe...
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.
virtual bool supports_compressed() const
Returns true if this file type can transparently load compressed files (with a .pz extension),...
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.
virtual std::string get_name() const
Returns the English name of the file type this converter supports.
virtual SomethingToEggConverter * make_copy()
Allocates and returns a new copy of the converter.
virtual std::string get_extension() const
Returns the common extension 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.
virtual bool convert_file(const Filename &filename)
Handles the reading of the input file and converting it to egg.
bool convert_lwo(const LwoHeader *lwo_header)
Fills up the egg_data structure according to the indicated lwo structure.
A mapping of floating-point values per integer index.
Definition: lwoVertexMap.h:27
This is a base class for a family of converter classes that manage a conversion from some file type t...
bool had_error() const
Returns true if an error was detected during the conversion process (unless _allow_errors is true),...
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.