Panda3D
fltToEggConverter.cxx
1 // Filename: fltToEggConverter.cxx
2 // Created by: drose (17Apr01)
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 "fltToEggConverter.h"
16 
17 #include "fltRecord.h"
18 #include "fltLOD.h"
19 #include "fltGroup.h"
20 #include "fltObject.h"
21 #include "fltBeadID.h"
22 #include "fltBead.h"
23 #include "fltFace.h"
24 #include "fltVertex.h"
25 #include "fltVertexList.h"
26 #include "fltExternalReference.h"
27 #include "dcast.h"
28 #include "eggData.h"
29 #include "eggGroup.h"
30 #include "eggSwitchCondition.h"
31 #include "eggPrimitive.h"
32 #include "eggPolygon.h"
33 #include "eggPoint.h"
34 #include "eggVertex.h"
35 #include "eggVertexPool.h"
36 #include "eggExternalReference.h"
37 #include "string_utils.h"
38 
39 
40 ////////////////////////////////////////////////////////////////////
41 // Function: FltToEggConverter::Constructor
42 // Access: Public
43 // Description:
44 ////////////////////////////////////////////////////////////////////
45 FltToEggConverter::
46 FltToEggConverter() {
47  _compose_transforms = false;
48  _flt_units = DU_invalid;
49 }
50 
51 ////////////////////////////////////////////////////////////////////
52 // Function: FltToEggConverter::Copy Constructor
53 // Access: Public
54 // Description:
55 ////////////////////////////////////////////////////////////////////
56 FltToEggConverter::
57 FltToEggConverter(const FltToEggConverter &copy) :
59  _compose_transforms(copy._compose_transforms)
60 {
61 }
62 
63 ////////////////////////////////////////////////////////////////////
64 // Function: FltToEggConverter::Destructor
65 // Access: Public
66 // Description:
67 ////////////////////////////////////////////////////////////////////
68 FltToEggConverter::
69 ~FltToEggConverter() {
70  cleanup();
71 }
72 
73 ////////////////////////////////////////////////////////////////////
74 // Function: FltToEggConverter::make_copy
75 // Access: Public, Virtual
76 // Description: Allocates and returns a new copy of the converter.
77 ////////////////////////////////////////////////////////////////////
80  return new FltToEggConverter(*this);
81 }
82 
83 
84 ////////////////////////////////////////////////////////////////////
85 // Function: FltToEggConverter::get_name
86 // Access: Public, Virtual
87 // Description: Returns the English name of the file type this
88 // converter supports.
89 ////////////////////////////////////////////////////////////////////
91 get_name() const {
92  return "MultiGen";
93 }
94 
95 ////////////////////////////////////////////////////////////////////
96 // Function: FltToEggConverter::get_extension
97 // Access: Public, Virtual
98 // Description: Returns the common extension of the file type this
99 // converter supports.
100 ////////////////////////////////////////////////////////////////////
101 string FltToEggConverter::
102 get_extension() const {
103  return "flt";
104 }
105 
106 ////////////////////////////////////////////////////////////////////
107 // Function: FltToEggConverter::supports_compressed
108 // Access: Published, Virtual
109 // Description: Returns true if this file type can transparently load
110 // compressed files (with a .pz extension), false
111 // otherwise.
112 ////////////////////////////////////////////////////////////////////
115  return true;
116 }
117 
118 ////////////////////////////////////////////////////////////////////
119 // Function: FltToEggConverter::convert_file
120 // Access: Public, Virtual
121 // Description: Handles the reading of the input file and converting
122 // it to egg. Returns true if successful, false
123 // otherwise.
124 //
125 // This is designed to be as generic as possible,
126 // generally in support of run-time loading.
127 // Command-line converters may choose to use
128 // convert_flt() instead, as it provides more control.
129 ////////////////////////////////////////////////////////////////////
131 convert_file(const Filename &filename) {
132  PT(FltHeader) header = new FltHeader(_path_replace);
133 
134  nout << "Reading " << filename << "\n";
135  FltError result = header->read_flt(filename);
136  if (result != FE_ok) {
137  nout << "Unable to read: " << result << "\n";
138  return false;
139  }
140 
141  header->check_version();
142 
143  _flt_units = header->get_units();
144 
145  return convert_flt(header);
146 }
147 
148 ////////////////////////////////////////////////////////////////////
149 // Function: FltToEggConverter::get_input_units
150 // Access: Public, Virtual
151 // Description: This may be called after convert_file() has been
152 // called and returned true, indicating a successful
153 // conversion. It will return the distance units
154 // represented by the converted egg file, if known, or
155 // DU_invalid if not known.
156 ////////////////////////////////////////////////////////////////////
157 DistanceUnit FltToEggConverter::
159  return _flt_units;
160 }
161 
162 ////////////////////////////////////////////////////////////////////
163 // Function: FltToEggConverter::convert_flt
164 // Access: Public
165 // Description: Fills up the egg_data structure according to the
166 // indicated lwo structure.
167 ////////////////////////////////////////////////////////////////////
169 convert_flt(const FltHeader *flt_header) {
170  if (_egg_data->get_coordinate_system() == CS_default) {
171  _egg_data->set_coordinate_system(CS_zup_right);
172  }
173 
174  clear_error();
175  _flt_header = flt_header;
176 
177  // Generate a default vertex pool.
178  _main_egg_vpool = new EggVertexPool("vpool");
179  _egg_data->add_child(_main_egg_vpool.p());
180 
181  // We could populate the vertex pool right away, but it's better to
182  // defer each vertex until we encounter it, since some of the
183  // vertices may need to be adjusted to match the particular polygon
184  // they're assigned to (for instance, to apply a transparency or
185  // something).
186 
187  FltToEggLevelState state(this);
188  state._egg_parent = _egg_data;
189  convert_record(_flt_header, state);
190 
191  if (_main_egg_vpool->empty()) {
192  // If we didn't get any global vertices, remove the vertex pool
193  // just for cleanliness.
194  _egg_data->remove_child(_main_egg_vpool.p());
195  }
196 
197  cleanup();
198 
199  return !had_error();
200 }
201 
202 ////////////////////////////////////////////////////////////////////
203 // Function: FltToEggConverter::cleanup
204 // Access: Private
205 // Description: Frees all the internal data structures after we're
206 // done converting, and resets the converter to its
207 // initial state.
208 ////////////////////////////////////////////////////////////////////
209 void FltToEggConverter::
210 cleanup() {
211  _flt_header.clear();
212  _main_egg_vpool.clear();
213  _textures.clear();
214 }
215 
216 ////////////////////////////////////////////////////////////////////
217 // Function: FltToEggConverter::convert_record
218 // Access: Private
219 // Description: Converts the record and all of its children.
220 ////////////////////////////////////////////////////////////////////
221 void FltToEggConverter::
222 convert_record(const FltRecord *flt_record, FltToEggLevelState &state) {
223  int num_children = flt_record->get_num_children();
224 
225  for (int i = 0; i < num_children; i++) {
226  const FltRecord *child = flt_record->get_child(i);
227  dispatch_record(child, state);
228  }
229 }
230 
231 ////////////////////////////////////////////////////////////////////
232 // Function: FltToEggConverter::dispatch_record
233 // Access: Private
234 // Description: Determines what kind of record this is and calls the
235 // appropriate convert function.
236 ////////////////////////////////////////////////////////////////////
237 void FltToEggConverter::
238 dispatch_record(const FltRecord *flt_record, FltToEggLevelState &state) {
239  if (flt_record->is_of_type(FltLOD::get_class_type())) {
240  convert_lod(DCAST(FltLOD, flt_record), state);
241 
242  } else if (flt_record->is_of_type(FltGroup::get_class_type())) {
243  convert_group(DCAST(FltGroup, flt_record), state);
244 
245  } else if (flt_record->is_of_type(FltObject::get_class_type())) {
246  convert_object(DCAST(FltObject, flt_record), state);
247 
248  } else if (flt_record->is_of_type(FltFace::get_class_type())) {
249  convert_face(DCAST(FltFace, flt_record), state);
250 
251  } else if (flt_record->is_of_type(FltExternalReference::get_class_type())) {
252  convert_ext_ref(DCAST(FltExternalReference, flt_record), state);
253 
254  // Fallbacks.
255  } else if (flt_record->is_of_type(FltBeadID::get_class_type())) {
256  convert_bead_id(DCAST(FltBeadID, flt_record), state);
257 
258  } else if (flt_record->is_of_type(FltBead::get_class_type())) {
259  convert_bead(DCAST(FltBead, flt_record), state);
260 
261  } else {
262  convert_record(flt_record, state);
263  }
264 }
265 
266 ////////////////////////////////////////////////////////////////////
267 // Function: FltToEggConverter::convert_lod
268 // Access: Private
269 // Description: Converts the LOD bead and all of its children.
270 ////////////////////////////////////////////////////////////////////
271 void FltToEggConverter::
272 convert_lod(const FltLOD *flt_lod, FltToEggLevelState &state) {
273  EggGroup *egg_group = new EggGroup(flt_lod->get_id());
274  state._egg_parent->add_child(egg_group);
275 
277  (flt_lod->_switch_in, flt_lod->_switch_out,
278  LPoint3d(flt_lod->_center_x, flt_lod->_center_y, flt_lod->_center_z),
279  flt_lod->_transition_range);
280  egg_group->set_lod(lod);
281 
282  state.set_transform(flt_lod, egg_group);
283  parse_comment(flt_lod, egg_group);
284 
285  FltToEggLevelState next_state(state);
286  next_state._egg_parent = egg_group;
287  convert_record(flt_lod, next_state);
288 }
289 
290 ////////////////////////////////////////////////////////////////////
291 // Function: FltToEggConverter::convert_group
292 // Access: Private
293 // Description: Converts the group and all of its children.
294 ////////////////////////////////////////////////////////////////////
295 void FltToEggConverter::
296 convert_group(const FltGroup *flt_group, FltToEggLevelState &state) {
297  EggGroup *egg_group = new EggGroup(flt_group->get_id());
298  state._egg_parent->add_child(egg_group);
299 
300  if ((flt_group->_flags & FltGroup::F_forward_animation) != 0) {
301  // It's a sequence animation.
302  egg_group->set_switch_flag(true);
303  egg_group->set_switch_fps(24.0);
304  }
305 
306  state.set_transform(flt_group, egg_group);
307  parse_comment(flt_group, egg_group);
308 
309  ///*** replicate count.
310 
311  FltToEggLevelState next_state(state);
312  next_state._egg_parent = egg_group;
313  convert_record(flt_group, next_state);
314 }
315 
316 ////////////////////////////////////////////////////////////////////
317 // Function: FltToEggConverter::convert_object
318 // Access: Private
319 // Description: Converts the object and all of its children.
320 ////////////////////////////////////////////////////////////////////
321 void FltToEggConverter::
322 convert_object(const FltObject *flt_object, FltToEggLevelState &state) {
323  EggGroup *egg_group = new EggGroup(flt_object->get_id());
324  state._egg_parent->add_child(egg_group);
325 
326  state.set_transform(flt_object, egg_group);
327  parse_comment(flt_object, egg_group);
328 
329  FltToEggLevelState next_state(state);
330  next_state._flt_object = flt_object;
331  next_state._egg_parent = egg_group;
332  convert_record(flt_object, next_state);
333 }
334 
335 ////////////////////////////////////////////////////////////////////
336 // Function: FltToEggConverter::convert_bead_id
337 // Access: Private
338 // Description: Converts the generic bead (with ID) and all of its
339 // children.
340 ////////////////////////////////////////////////////////////////////
341 void FltToEggConverter::
342 convert_bead_id(const FltBeadID *flt_bead, FltToEggLevelState &state) {
343  nout << "Don't know how to convert beads of type " << flt_bead->get_type()
344  << "\n";
345  EggGroup *egg_group = new EggGroup(flt_bead->get_id());
346  state._egg_parent->add_child(egg_group);
347 
348  state.set_transform(flt_bead, egg_group);
349  parse_comment(flt_bead, egg_group);
350 
351  FltToEggLevelState next_state(state);
352  next_state._egg_parent = egg_group;
353  convert_record(flt_bead, next_state);
354 }
355 
356 ////////////////////////////////////////////////////////////////////
357 // Function: FltToEggConverter::convert_bead
358 // Access: Private
359 // Description: Converts the generic bead (without ID) and all of its
360 // children.
361 ////////////////////////////////////////////////////////////////////
362 void FltToEggConverter::
363 convert_bead(const FltBead *flt_bead, FltToEggLevelState &state) {
364  nout << "Don't know how to convert beads of type " << flt_bead->get_type()
365  << "\n";
366  EggGroup *egg_group = new EggGroup;
367  state._egg_parent->add_child(egg_group);
368 
369  state.set_transform(flt_bead, egg_group);
370  parse_comment(flt_bead, egg_group);
371 
372  FltToEggLevelState next_state(state);
373  next_state._egg_parent = egg_group;
374  convert_record(flt_bead, next_state);
375 }
376 
377 ////////////////////////////////////////////////////////////////////
378 // Function: FltToEggConverter::convert_face
379 // Access: Private
380 // Description: Converts the face and all of its children.
381 ////////////////////////////////////////////////////////////////////
382 void FltToEggConverter::
383 convert_face(const FltFace *flt_face, FltToEggLevelState &state) {
384  bool is_light;
385  switch (flt_face->_draw_type) {
386  case FltGeometry::DT_omni_light:
387  case FltGeometry::DT_uni_light:
388  case FltGeometry::DT_bi_light:
389  is_light = true;
390  break;
391 
392  default:
393  is_light = false;
394  }
395 
396  PT(EggPrimitive) egg_prim;
397  if (is_light) {
398  egg_prim = new EggPoint;
399  } else {
400  egg_prim = new EggPolygon;
401  }
402 
403  // Collect the vertices for this primitive.
404  pvector< PT_EggVertex > vertices;
405 
406  const FltVertexList *vlist = (FltVertexList *)NULL;
407  int num_children = flt_face->get_num_children();
408  for (int i = 0; i < num_children && vlist == (FltVertexList *)NULL; i++) {
409  const FltRecord *child = flt_face->get_child(i);
410  if (child->is_of_type(FltVertexList::get_class_type())) {
411  vlist = DCAST(FltVertexList, child);
412  }
413  }
414 
415  if (vlist != (FltVertexList *)NULL) {
416  int num_vertices = vlist->get_num_vertices();
417  for (int i = 0; i < num_vertices; i++) {
418  FltVertex *flt_vertex = vlist->get_vertex(i);
419  vertices.push_back(make_egg_vertex(flt_vertex));
420  }
421  }
422 
423  setup_geometry(flt_face, state, egg_prim, _main_egg_vpool, vertices);
424 }
425 
426 ////////////////////////////////////////////////////////////////////
427 // Function: FltToEggConverter::convert_ext_ref
428 // Access: Private
429 // Description: Converts the external reference node.
430 ////////////////////////////////////////////////////////////////////
431 void FltToEggConverter::
432 convert_ext_ref(const FltExternalReference *flt_ext, FltToEggLevelState &state) {
433  // Get a group node to put the reference into.
434  EggGroupNode *egg_parent =
435  state.get_synthetic_group("", flt_ext);
436 
437  handle_external_reference(egg_parent, flt_ext->get_ref_filename());
438 }
439 
440 ////////////////////////////////////////////////////////////////////
441 // Function: FltToEggConverter::setup_geometry
442 // Access: Private
443 // Description: Applies the state indicated in the FltGeometry record
444 // to the indicated EggPrimitive and all of its
445 // indicated vertices, and then officially adds the
446 // vertices to the vertex pool and to the primitive, and
447 // adds the primitive to its appropriate parent.
448 ////////////////////////////////////////////////////////////////////
449 void FltToEggConverter::
450 setup_geometry(const FltGeometry *flt_geom, FltToEggLevelState &state,
451  EggPrimitive *egg_prim, EggVertexPool *egg_vpool,
452  const FltToEggConverter::EggVertices &vertices) {
453 
454  // Determine what the appropriate parent will be.
455  EggGroupNode *egg_parent =
456  state.get_synthetic_group(flt_geom->get_id(), flt_geom,
457  flt_geom->_billboard_type);
458 
459  // Create a new state to reflect the new parent.
460  FltToEggLevelState next_state(state);
461  next_state._egg_parent = egg_parent;
462 
463  // Check for decals onto the primitive.
464  convert_subfaces(flt_geom, next_state);
465 
466  // Add the primitive to its new home.
467  next_state._egg_parent->add_child(egg_prim);
468 
469  // Now examine the vertices.
470  EggVertices::const_iterator vi;
471 
472  bool use_vertex_color = true;
473  bool keep_normals = true;
474  switch (flt_geom->_light_mode) {
475  case FltGeometry::LM_face_no_normal:
476  use_vertex_color = false;
477  keep_normals = false;
478  break;
479 
480  case FltGeometry::LM_vertex_no_normal:
481  use_vertex_color = true;
482  keep_normals = false;
483  break;
484 
485  case FltGeometry::LM_face_with_normal:
486  use_vertex_color = false;
487  keep_normals = true;
488  break;
489 
490  case FltGeometry::LM_vertex_with_normal:
491  use_vertex_color = true;
492  keep_normals = true;
493  break;
494  }
495 
496  LColor face_color = flt_geom->get_color();
497 
498  if (state._flt_object != (FltObject *)NULL) {
499  // If we have a FltObject above us, it might also specify a
500  // transparency. This combines with our existing transparency.
501  PN_stdfloat alpha = 1.0 - (state._flt_object->_transparency / 65535.0);
502  face_color[3] *= alpha;
503  }
504 
505  egg_prim->set_color(face_color);
506 
507  if (flt_geom->has_texture()) {
508  // If the geometry has a texture, apply it.
509  egg_prim->set_texture(make_egg_texture(flt_geom->get_texture()));
510 
511  if (flt_geom->_texwhite) {
512  // If the geometry should be colored white under the texture,
513  // then eliminate vertex colors.
514  use_vertex_color = false;
515  }
516  }
517 
518  if (use_vertex_color) {
519  // If we're to use vertex color instead of the face color, remove
520  // the face color to eliminate any ambiguity.
521  egg_prim->clear_color();
522 
523  // Also, make sure the transparency is set correctly across all
524  // vertices.
525  for (vi = vertices.begin(); vi != vertices.end(); ++vi) {
526  EggVertex *vertex = (*vi);
527  if (vertex->has_color()) {
528  LColor vertex_color = vertex->get_color();
529  vertex_color[3] = face_color[3];
530  vertex->set_color(vertex_color);
531  } else {
532  if (flt_geom->has_color()) {
533  // If a vertex doesn't have a color but the face does, set
534  // the vertex to use the face color.
535  vertex->set_color(face_color);
536  }
537  }
538  }
539 
540  } else {
541  // If we're to use face color instead of vertex color, remove the
542  // vertex color to eliminate any ambiguity.
543  for (vi = vertices.begin(); vi != vertices.end(); ++vi) {
544  (*vi)->clear_color();
545  }
546  }
547 
548  if (!keep_normals) {
549  // If we're not to use the normals, then eliminate them.
550  for (vi = vertices.begin(); vi != vertices.end(); ++vi) {
551  (*vi)->clear_normal();
552  }
553  }
554 
555  if (flt_geom->_draw_type == FltGeometry::DT_solid_no_cull) {
556  // A double-sided polygon.
557  egg_prim->set_bface_flag(true);
558  }
559 
560  for (vi = vertices.begin(); vi != vertices.end(); ++vi) {
561  EggVertex *egg_vertex = egg_vpool->create_unique_vertex(*(*vi));
562  egg_prim->add_vertex(egg_vertex);
563  }
564 
565  parse_comment(flt_geom, egg_prim);
566 }
567 
568 ////////////////////////////////////////////////////////////////////
569 // Function: FltToEggConverter::convert_subfaces
570 // Access: Public
571 // Description: Records all of the subfaces of the indicated group as
572 // coplanar polygons (i.e. decals) of the group.
573 //
574 // If coplanar polygons exist, the state is modified so
575 // that _egg_parent is the new group to which the base
576 // polygons should be added. Therefore, subfaces should
577 // be defined before the ordinary children are
578 // processed.
579 ////////////////////////////////////////////////////////////////////
580 void FltToEggConverter::
581 convert_subfaces(const FltRecord *flt_record, FltToEggLevelState &state) {
582  int num_subfaces = flt_record->get_num_subfaces();
583  if (num_subfaces == 0) {
584  // No subfaces.
585  return;
586  }
587 
588  // Create a new group to contain the base polygons.
589  EggGroup *egg_group = new EggGroup("decal_base");
590  state._egg_parent->add_child(egg_group);
591  state._egg_parent = egg_group;
592 
593  egg_group->set_decal_flag(true);
594 
595  // Now create a nested group to hold the decals.
596  EggGroup *decal_group = new EggGroup("decals");
597  egg_group->add_child(decal_group);
598  egg_group = decal_group;
599 
600  FltToEggLevelState next_state(state);
601  next_state._egg_parent = decal_group;
602 
603  for (int i = 0; i < num_subfaces; i++) {
604  const FltRecord *subface = flt_record->get_subface(i);
605  dispatch_record(subface, next_state);
606  }
607 }
608 
609 ////////////////////////////////////////////////////////////////////
610 // Function: FltToEggConverter::parse_comment
611 // Access: Private
612 // Description: Scans the comment on this record for "<egg> { ... }"
613 // and parses the enclosed string as if it appeared in
614 // the egg file. Returns true on success, false on
615 // syntax error (in which case _error is also set to
616 // true).
617 ////////////////////////////////////////////////////////////////////
618 bool FltToEggConverter::
619 parse_comment(const FltBeadID *flt_bead, EggNode *egg_node) {
620  return parse_comment(flt_bead->get_comment(), flt_bead->get_id(), egg_node);
621 }
622 
623 ////////////////////////////////////////////////////////////////////
624 // Function: FltToEggConverter::parse_comment
625 // Access: Private
626 // Description: Scans the comment on this record for "<egg> { ... }"
627 // and parses the enclosed string as if it appeared in
628 // the egg file. Returns true on success, false on
629 // syntax error (in which case _error is also set to
630 // true).
631 ////////////////////////////////////////////////////////////////////
632 bool FltToEggConverter::
633 parse_comment(const FltBead *flt_bead, EggNode *egg_node) {
634  return parse_comment(flt_bead->get_comment(), "anonymous", egg_node);
635 }
636 
637 ////////////////////////////////////////////////////////////////////
638 // Function: FltToEggConverter::parse_comment
639 // Access: Private
640 // Description: Scans the comment on this record for "<egg> { ... }"
641 // and parses the enclosed string as if it appeared in
642 // the egg file. Returns true on success, false on
643 // syntax error (in which case _error is also set to
644 // true).
645 ////////////////////////////////////////////////////////////////////
646 bool FltToEggConverter::
647 parse_comment(const FltTexture *flt_texture, EggNode *egg_node) {
648  return parse_comment(flt_texture->get_comment(),
649  flt_texture->get_texture_filename(), egg_node);
650 }
651 
652 ////////////////////////////////////////////////////////////////////
653 // Function: FltToEggConverter::parse_comment
654 // Access: Private
655 // Description: Scans the comment on this record for "<egg> { ... }"
656 // and parses the enclosed string as if it appeared in
657 // the egg file. Returns true on success, false on
658 // syntax error (in which case _error is also set to
659 // true).
660 ////////////////////////////////////////////////////////////////////
661 bool FltToEggConverter::
662 parse_comment(const string &comment, const string &name,
663  EggNode *egg_node) {
664  if (comment.empty()) {
665  // No comment.
666  return true;
667  }
668 
669  // Scan for <egg>.
670  static const string egg_str = "<egg>";
671 
672  size_t p;
673  p = 0;
674  while (p < comment.length() &&
675  cmp_nocase(comment.substr(p, 5), egg_str) != 0) {
676  p++;
677  }
678 
679  if (p >= comment.length()) {
680  // No "<egg>" in the comment.
681  return true;
682  }
683 
684  p += 5;
685  // Now scan past whitespace for the open curly brace.
686  while (p < comment.length() && isspace(comment[p])) {
687  ++p;
688  }
689  if (p >= comment.length() || comment[p] != '{') {
690  nout << "No opening brace in comment for "
691  << name << "\n\n";
692  _error = true;
693  return false;
694  }
695 
696  // Here's the beginning of the string after "<egg> {". Now lop off
697  // the closing brace at the end.
698  ++p;
699  size_t q = comment.length() - 1;
700  while (q > p && comment[q] != '}') {
701  --q;
702  }
703  if (q == p) {
704  nout << "No closing brace in comment for "
705  << name << "\n\n";
706  _error = true;
707  return false;
708  }
709 
710  string egg_syntax = comment.substr(p, q - p);
711 
712  if (!egg_node->parse_egg(egg_syntax)) {
713  nout << "Syntax error in comment for "
714  << name << "\n\n";
715  _error = true;
716  return false;
717  }
718 
719  // Correctly parsed!
720  return true;
721 }
722 
723 ////////////////////////////////////////////////////////////////////
724 // Function: FltToEggConverter::make_egg_vertex
725 // Access: Private
726 // Description: Makes a new EggVertex for the indicated FltVertex.
727 // The vertex is not automatically added to the vertex
728 // pool.
729 ////////////////////////////////////////////////////////////////////
730 PT_EggVertex FltToEggConverter::
731 make_egg_vertex(const FltVertex *flt_vertex) {
732  PT_EggVertex egg_vertex = new EggVertex;
733  egg_vertex->set_pos(flt_vertex->_pos);
734 
735  if (flt_vertex->_has_normal) {
736  egg_vertex->set_normal(LCAST(double, flt_vertex->_normal));
737  }
738 
739  if (flt_vertex->_has_uv) {
740  egg_vertex->set_uv(LCAST(double, flt_vertex->_uv));
741  }
742 
743  if (flt_vertex->has_color()) {
744  egg_vertex->set_color(flt_vertex->get_color());
745  }
746 
747  return egg_vertex;
748 }
749 
750 ////////////////////////////////////////////////////////////////////
751 // Function: FltToEggConverter::make_egg_texture
752 // Access: Private
753 // Description: Makes a new EggTexture for the indicated FltTexture,
754 // or returns a pointer to one previously made for the
755 // same FltTexture.
756 ////////////////////////////////////////////////////////////////////
757 PT_EggTexture FltToEggConverter::
758 make_egg_texture(const FltTexture *flt_texture) {
759  Textures::const_iterator ti;
760  ti = _textures.find(flt_texture);
761  if (ti != _textures.end()) {
762  // There's one previously created.
763  return (*ti).second;
764  }
765 
766  // Create a new one.
767  string tref_name = format_string(flt_texture->_pattern_index);
768  Filename filename = flt_texture->get_texture_filename();
769 
770  PT_EggTexture egg_texture = new EggTexture(tref_name, filename);
771 
772  _textures.insert(Textures::value_type(flt_texture, egg_texture));
773 
774  // Set up the texture properties.
775 
776  switch (flt_texture->_min_filter) {
777  case FltTexture::MN_point:
778  egg_texture->set_minfilter(EggTexture::FT_nearest);
779  break;
780 
781  case FltTexture::MN_bilinear:
782  egg_texture->set_minfilter(EggTexture::FT_linear);
783  break;
784 
785  case FltTexture::MN_mipmap_point:
786  egg_texture->set_minfilter(EggTexture::FT_nearest_mipmap_nearest);
787  break;
788 
789  case FltTexture::MN_mipmap_linear:
790  egg_texture->set_minfilter(EggTexture::FT_nearest_mipmap_linear);
791  break;
792 
793  case FltTexture::MN_mipmap_bilinear:
794  egg_texture->set_minfilter(EggTexture::FT_linear_mipmap_nearest);
795  break;
796 
797  case FltTexture::MN_mipmap_trilinear:
798  case FltTexture::MN_OB_mipmap:
799  egg_texture->set_minfilter(EggTexture::FT_linear_mipmap_linear);
800  break;
801 
802  case FltTexture::MN_bicubic:
803  case FltTexture::MN_bilinear_gequal:
804  case FltTexture::MN_bilinear_lequal:
805  case FltTexture::MN_bicubic_gequal:
806  case FltTexture::MN_bicubic_lequal:
807  // Not supported.
808  break;
809  }
810 
811  switch (flt_texture->_mag_filter) {
812  case FltTexture::MG_point:
813  egg_texture->set_magfilter(EggTexture::FT_nearest);
814  break;
815 
816  case FltTexture::MG_bilinear:
817  egg_texture->set_magfilter(EggTexture::FT_linear);
818  break;
819 
820  case FltTexture::MG_bicubic:
821  case FltTexture::MG_sharpen:
822  case FltTexture::MG_add_detail:
823  case FltTexture::MG_modulate_detail:
824  case FltTexture::MG_bilinear_gequal:
825  case FltTexture::MG_bilinear_lequal:
826  case FltTexture::MG_bicubic_gequal:
827  case FltTexture::MG_bicubic_lequal:
828  // Not supported.
829  break;
830  }
831 
832  switch (flt_texture->_repeat) {
833  case FltTexture::RT_repeat:
834  egg_texture->set_wrap_mode(EggTexture::WM_repeat);
835  break;
836 
837  case FltTexture::RT_clamp:
838  egg_texture->set_wrap_mode(EggTexture::WM_clamp);
839  break;
840  }
841 
842  switch (flt_texture->_repeat_u) {
843  case FltTexture::RT_repeat:
844  egg_texture->set_wrap_u(EggTexture::WM_repeat);
845  break;
846 
847  case FltTexture::RT_clamp:
848  egg_texture->set_wrap_u(EggTexture::WM_clamp);
849  break;
850  }
851 
852  switch (flt_texture->_repeat_v) {
853  case FltTexture::RT_repeat:
854  egg_texture->set_wrap_v(EggTexture::WM_repeat);
855  break;
856 
857  case FltTexture::RT_clamp:
858  egg_texture->set_wrap_v(EggTexture::WM_clamp);
859  break;
860  }
861 
862  switch (flt_texture->_env_type) {
863  case FltTexture::ET_modulate:
864  egg_texture->set_env_type(EggTexture::ET_modulate);
865  break;
866 
867  case FltTexture::ET_decal:
868  egg_texture->set_env_type(EggTexture::ET_decal);
869  break;
870 
871  case FltTexture::ET_blend:
872  case FltTexture::ET_color:
873  // Not supported.
874  break;
875  }
876 
877  switch (flt_texture->_internal_format) {
878  case FltTexture::IF_default:
879  break;
880 
881  case FltTexture::IF_i_12a_4:
882  case FltTexture::IF_ia_12:
883  case FltTexture::IF_ia_8:
884  egg_texture->set_format(EggTexture::F_luminance_alpha);
885  break;
886 
887  case FltTexture::IF_rgb_5:
888  egg_texture->set_format(EggTexture::F_rgb5);
889  break;
890 
891  case FltTexture::IF_rgba_4:
892  egg_texture->set_format(EggTexture::F_rgba4);
893  break;
894 
895 
896  case FltTexture::IF_rgba_8:
897  egg_texture->set_format(EggTexture::F_rgba8);
898  break;
899 
900  case FltTexture::IF_rgba_12:
901  egg_texture->set_format(EggTexture::F_rgba12);
902  break;
903 
904  case FltTexture::IF_i_16:
905  if (flt_texture->_intensity_is_alpha) {
906  egg_texture->set_format(EggTexture::F_alpha);
907  } else {
908  egg_texture->set_format(EggTexture::F_luminance);
909  }
910  break;
911 
912  case FltTexture::IF_rgb_12:
913  egg_texture->set_format(EggTexture::F_rgb12);
914  break;
915  }
916 
917  parse_comment(flt_texture, egg_texture);
918  return egg_texture;
919 }
A base class for any of a number of kinds of geometry primitives: polygons, point lights...
Definition: eggPrimitive.h:51
bool parse_egg(const string &egg_syntax)
Parses the egg syntax given in the indicate string as if it had been read from the egg file within th...
Definition: eggNode.cxx:268
virtual bool supports_compressed() const
Returns true if this file type can transparently load compressed files (with a .pz extension)...
A base class for any of a broad family of flt beads that include an ID.
Definition: fltBeadID.h:27
Filename get_texture_filename() const
Returns the name of the texture image file.
Definition: fltTexture.cxx:109
bool had_error() const
Returns true if an error was detected during the conversion process (unless _allow_errors is true)...
void set_pos(double pos)
Sets the vertex position.
Definition: eggVertex.I:54
A base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:51
int get_num_children() const
Returns the number of child records of this record.
Definition: fltRecord.cxx:70
Defines a texture map that may be applied to geometry.
Definition: eggTexture.h:33
The main grouping bead of the flt file.
Definition: fltGroup.h:26
bool handle_external_reference(EggGroupNode *egg_parent, const Filename &ref_filename)
Handles an external reference in the source file.
void set_texture(EggTexture *texture)
Replaces the current list of textures with the indicated texture.
Definition: eggPrimitive.I:139
A base class for any of a broad family of flt records that represent particular beads in the hierarch...
Definition: fltBead.h:33
A single face bead, e.g.
Definition: fltFace.h:26
const string & get_id() const
Returns the id (name) of this particular bead.
Definition: fltBeadID.cxx:37
This class supervises the construction of an EggData structure from the data represented by the FltHe...
LColor get_color() const
Returns the color set on this particular attribute.
bool has_color() const
Returns true if the vertex has a primary color indicated, false otherwise.
Definition: fltVertex.I:23
This is a base class for both FltFace and FltMesh, which are two different kinds of geometric primiti...
Definition: fltGeometry.h:36
A single point, or a collection of points as defined by a single <PointLight> entry.
Definition: eggPoint.h:27
bool has_color() const
Returns true if the face has a primary color indicated, false otherwise.
Definition: fltGeometry.I:99
This is the first bead in the file, the top of the bead hierarchy, and the primary interface to readi...
Definition: fltHeader.h:48
virtual string get_name() const
Returns the English name of the file type this converter supports.
This keeps track of relevant things about the traversal as we walk through the flt hierarchy...
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:39
void set_bface_flag(bool flag)
Sets the backfacing flag of the polygon.
Definition: eggPrimitive.I:289
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition: eggGroup.h:36
virtual DistanceUnit get_input_units()
This may be called after convert_file() has been called and returned true, indicating a successful co...
FltRecord * get_subface(int n) const
Returns the nth subface of this record.
Definition: fltRecord.cxx:125
void clear_error()
Resets the error flag to the no-error state.
A list of vertices, typically added as a child of a face bead.
Definition: fltVertexList.h:31
const string & get_comment() const
Retrieves the comment for this record, or empty string if the record has no comment.
Definition: fltRecord.cxx:275
Represents a single texture in the texture palette.
Definition: fltTexture.h:29
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal...
Definition: eggVertex.h:41
The base class for all kinds of records in a MultiGen OpenFlight file.
Definition: fltRecord.h:40
Represents a single vertex in the vertex palette.
Definition: fltVertex.h:35
An external reference to another flt file (possibly to a specific bead within the flt file)...
A single polygon.
Definition: eggPolygon.h:26
virtual string get_extension() const
Returns the common extension of the file type this converter supports.
The main objecting bead of the flt file.
Definition: fltObject.h:26
bool convert_flt(const FltHeader *flt_header)
Fills up the egg_data structure according to the indicated lwo structure.
FltRecord * get_child(int n) const
Returns the nth child of this record.
Definition: fltRecord.cxx:80
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
Filename get_ref_filename() const
Returns the name of the referenced file.
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
Definition: lpoint3.h:544
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
LColor get_color() const
Returns the primary color of the face, as a four-component value (including alpha as the transparency...
Definition: fltGeometry.cxx:65
A base class for things that may be directly added into the egg hierarchy.
Definition: eggNode.h:38
virtual SomethingToEggConverter * make_copy()
Allocates and returns a new copy of the converter.
EggGroupNode * get_synthetic_group(const string &name, const FltBead *transform_bead, FltGeometry::BillboardType type=FltGeometry::BT_none)
Sometimes it is necessary to synthesize a group within a particular EggGroup, for instance to insert ...
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:63
virtual bool convert_file(const Filename &filename)
Handles the reading of the input file and converting it to egg.
LColor get_color() const
If has_color() indicates true, returns the color of the vertex, as a four-component value...
Definition: fltVertex.cxx:123
bool has_texture() const
Returns true if the face has a texture applied, false otherwise.
Definition: fltGeometry.I:23
A Level-of-Detail record.
Definition: fltLOD.h:26
This is a base class for a family of converter classes that manage a conversion from some file type t...
FltTexture * get_texture() const
Returns the texture applied to this face, or NULL if no texture was applied.
Definition: fltGeometry.I:34
EggVertex * create_unique_vertex(const EggVertex &copy)
Creates a new vertex in the pool that is a copy of the indicated one and returns it.
A collection of vertices.
Definition: eggVertexPool.h:46
EggVertex * add_vertex(EggVertex *vertex)
Adds the indicated vertex to the end of the primitive&#39;s list of vertices, and returns it...
A SwitchCondition that switches the levels-of-detail based on distance from the camera&#39;s eyepoint...
void set_transform(const FltBead *flt_bead, EggGroup *egg_group)
Sets up the group to reflect the transform indicated by the given record, if any. ...
int get_num_subfaces() const
Returns the number of subface records of this record.
Definition: fltRecord.cxx:115