Panda3D
 All Classes Functions Variables Enumerations
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
const string & get_id() const
Returns the id (name) of this particular bead.
Definition: fltBeadID.cxx:37
A base class for any of a broad family of flt beads that include an ID.
Definition: fltBeadID.h:27
LColor get_color() const
Returns the color set on this particular attribute.
int get_num_subfaces() const
Returns the number of subface records of this record.
Definition: fltRecord.cxx:115
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
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 is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:63
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
FltRecord * get_child(int n) const
Returns the nth child of this record.
Definition: fltRecord.cxx:80
A single face bead, e.g.
Definition: fltFace.h:26
Filename get_texture_filename() const
Returns the name of the texture image file.
Definition: fltTexture.cxx:109
This class supervises the construction of an EggData structure from the data represented by the FltHe...
This is a base class for both FltFace and FltMesh, which are two different kinds of geometric primiti...
Definition: fltGeometry.h:36
bool has_texture() const
Returns true if the face has a texture applied, false otherwise.
Definition: fltGeometry.I:23
A single point, or a collection of points as defined by a single &lt;PointLight&gt; entry.
Definition: eggPoint.h:27
This is the first bead in the file, the top of the bead hierarchy, and the primary interface to readi...
Definition: fltHeader.h:48
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
virtual bool supports_compressed() const
Returns true if this file type can transparently load compressed files (with a .pz extension)...
The main glue of the egg hierarchy, this corresponds to the &lt;Group&gt;, &lt;Instance&gt;, and &lt;Joint&gt; 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...
void clear_error()
Resets the error flag to the no-error state.
virtual string get_extension() const
Returns the common extension of the file type this converter supports.
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
FltTexture * get_texture() const
Returns the texture applied to this face, or NULL if no texture was applied.
Definition: fltGeometry.I:34
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)...
bool had_error() const
Returns true if an error was detected during the conversion process (unless _allow_errors is true)...
A single polygon.
Definition: eggPolygon.h:26
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.
bool has_color() const
Returns true if the face has a primary color indicated, false otherwise.
Definition: fltGeometry.I:99
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:531
bool has_color() const
Returns true if the vertex has a primary color indicated, false otherwise.
Definition: fltVertex.I:23
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
FltRecord * get_subface(int n) const
Returns the nth subface of this record.
Definition: fltRecord.cxx:125
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.
int get_num_children() const
Returns the number of child records of this record.
Definition: fltRecord.cxx:70
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 ...
virtual bool convert_file(const Filename &filename)
Handles the reading of the input file and converting it to egg.
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
LColor get_color() const
If has_color() indicates true, returns the color of the vertex, as a four-component value...
Definition: fltVertex.cxx:123
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...
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. ...
virtual string get_name() const
Returns the English name of the file type this converter supports.