Panda3D
 All Classes Functions Variables Enumerations
fltToEggConverter.cxx
00001 // Filename: fltToEggConverter.cxx
00002 // Created by:  drose (17Apr01)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "fltToEggConverter.h"
00016 
00017 #include "fltRecord.h"
00018 #include "fltLOD.h"
00019 #include "fltGroup.h"
00020 #include "fltObject.h"
00021 #include "fltBeadID.h"
00022 #include "fltBead.h"
00023 #include "fltFace.h"
00024 #include "fltVertex.h"
00025 #include "fltVertexList.h"
00026 #include "fltExternalReference.h"
00027 #include "dcast.h"
00028 #include "eggData.h"
00029 #include "eggGroup.h"
00030 #include "eggSwitchCondition.h"
00031 #include "eggPrimitive.h"
00032 #include "eggPolygon.h"
00033 #include "eggPoint.h"
00034 #include "eggVertex.h"
00035 #include "eggVertexPool.h"
00036 #include "eggExternalReference.h"
00037 #include "string_utils.h"
00038 
00039 
00040 ////////////////////////////////////////////////////////////////////
00041 //     Function: FltToEggConverter::Constructor
00042 //       Access: Public
00043 //  Description:
00044 ////////////////////////////////////////////////////////////////////
00045 FltToEggConverter::
00046 FltToEggConverter() {
00047   _compose_transforms = false;
00048   _flt_units = DU_invalid;
00049 }
00050 
00051 ////////////////////////////////////////////////////////////////////
00052 //     Function: FltToEggConverter::Copy Constructor
00053 //       Access: Public
00054 //  Description:
00055 ////////////////////////////////////////////////////////////////////
00056 FltToEggConverter::
00057 FltToEggConverter(const FltToEggConverter &copy) :
00058   SomethingToEggConverter(copy),
00059   _compose_transforms(copy._compose_transforms)
00060 {
00061 }
00062 
00063 ////////////////////////////////////////////////////////////////////
00064 //     Function: FltToEggConverter::Destructor
00065 //       Access: Public
00066 //  Description:
00067 ////////////////////////////////////////////////////////////////////
00068 FltToEggConverter::
00069 ~FltToEggConverter() {
00070   cleanup();
00071 }
00072 
00073 ////////////////////////////////////////////////////////////////////
00074 //     Function: FltToEggConverter::make_copy
00075 //       Access: Public, Virtual
00076 //  Description: Allocates and returns a new copy of the converter.
00077 ////////////////////////////////////////////////////////////////////
00078 SomethingToEggConverter *FltToEggConverter::
00079 make_copy() {
00080   return new FltToEggConverter(*this);
00081 }
00082 
00083 
00084 ////////////////////////////////////////////////////////////////////
00085 //     Function: FltToEggConverter::get_name
00086 //       Access: Public, Virtual
00087 //  Description: Returns the English name of the file type this
00088 //               converter supports.
00089 ////////////////////////////////////////////////////////////////////
00090 string FltToEggConverter::
00091 get_name() const {
00092   return "MultiGen";
00093 }
00094 
00095 ////////////////////////////////////////////////////////////////////
00096 //     Function: FltToEggConverter::get_extension
00097 //       Access: Public, Virtual
00098 //  Description: Returns the common extension of the file type this
00099 //               converter supports.
00100 ////////////////////////////////////////////////////////////////////
00101 string FltToEggConverter::
00102 get_extension() const {
00103   return "flt";
00104 }
00105 
00106 ////////////////////////////////////////////////////////////////////
00107 //     Function: FltToEggConverter::supports_compressed
00108 //       Access: Published, Virtual
00109 //  Description: Returns true if this file type can transparently load
00110 //               compressed files (with a .pz extension), false
00111 //               otherwise.
00112 ////////////////////////////////////////////////////////////////////
00113 bool FltToEggConverter::
00114 supports_compressed() const {
00115   return true;
00116 }
00117 
00118 ////////////////////////////////////////////////////////////////////
00119 //     Function: FltToEggConverter::convert_file
00120 //       Access: Public, Virtual
00121 //  Description: Handles the reading of the input file and converting
00122 //               it to egg.  Returns true if successful, false
00123 //               otherwise.
00124 //
00125 //               This is designed to be as generic as possible,
00126 //               generally in support of run-time loading.
00127 //               Command-line converters may choose to use
00128 //               convert_flt() instead, as it provides more control.
00129 ////////////////////////////////////////////////////////////////////
00130 bool FltToEggConverter::
00131 convert_file(const Filename &filename) {
00132   PT(FltHeader) header = new FltHeader(_path_replace);
00133 
00134   nout << "Reading " << filename << "\n";
00135   FltError result = header->read_flt(filename);
00136   if (result != FE_ok) {
00137     nout << "Unable to read: " << result << "\n";
00138     return false;
00139   }
00140 
00141   header->check_version();
00142 
00143   _flt_units = header->get_units();
00144 
00145   return convert_flt(header);
00146 }
00147 
00148 ////////////////////////////////////////////////////////////////////
00149 //     Function: FltToEggConverter::get_input_units
00150 //       Access: Public, Virtual
00151 //  Description: This may be called after convert_file() has been
00152 //               called and returned true, indicating a successful
00153 //               conversion.  It will return the distance units
00154 //               represented by the converted egg file, if known, or
00155 //               DU_invalid if not known.
00156 ////////////////////////////////////////////////////////////////////
00157 DistanceUnit FltToEggConverter::
00158 get_input_units() {
00159   return _flt_units;
00160 }
00161 
00162 ////////////////////////////////////////////////////////////////////
00163 //     Function: FltToEggConverter::convert_flt
00164 //       Access: Public
00165 //  Description: Fills up the egg_data structure according to the
00166 //               indicated lwo structure.
00167 ////////////////////////////////////////////////////////////////////
00168 bool FltToEggConverter::
00169 convert_flt(const FltHeader *flt_header) {
00170   if (_egg_data->get_coordinate_system() == CS_default) {
00171     _egg_data->set_coordinate_system(CS_zup_right);
00172   }
00173 
00174   clear_error();
00175   _flt_header = flt_header;
00176 
00177   // Generate a default vertex pool.
00178   _main_egg_vpool = new EggVertexPool("vpool");
00179   _egg_data->add_child(_main_egg_vpool.p());
00180 
00181   // We could populate the vertex pool right away, but it's better to
00182   // defer each vertex until we encounter it, since some of the
00183   // vertices may need to be adjusted to match the particular polygon
00184   // they're assigned to (for instance, to apply a transparency or
00185   // something).
00186 
00187   FltToEggLevelState state(this);
00188   state._egg_parent = _egg_data;
00189   convert_record(_flt_header, state);
00190 
00191   if (_main_egg_vpool->empty()) {
00192     // If we didn't get any global vertices, remove the vertex pool
00193     // just for cleanliness.
00194     _egg_data->remove_child(_main_egg_vpool.p());
00195   }
00196 
00197   cleanup();
00198 
00199   return !had_error();
00200 }
00201 
00202 ////////////////////////////////////////////////////////////////////
00203 //     Function: FltToEggConverter::cleanup
00204 //       Access: Private
00205 //  Description: Frees all the internal data structures after we're
00206 //               done converting, and resets the converter to its
00207 //               initial state.
00208 ////////////////////////////////////////////////////////////////////
00209 void FltToEggConverter::
00210 cleanup() {
00211   _flt_header.clear();
00212   _main_egg_vpool.clear();
00213   _textures.clear();
00214 }
00215 
00216 ////////////////////////////////////////////////////////////////////
00217 //     Function: FltToEggConverter::convert_record
00218 //       Access: Private
00219 //  Description: Converts the record and all of its children.
00220 ////////////////////////////////////////////////////////////////////
00221 void FltToEggConverter::
00222 convert_record(const FltRecord *flt_record, FltToEggLevelState &state) {
00223   int num_children = flt_record->get_num_children();
00224 
00225   for (int i = 0; i < num_children; i++) {
00226     const FltRecord *child = flt_record->get_child(i);
00227     dispatch_record(child, state);
00228   }
00229 }
00230 
00231 ////////////////////////////////////////////////////////////////////
00232 //     Function: FltToEggConverter::dispatch_record
00233 //       Access: Private
00234 //  Description: Determines what kind of record this is and calls the
00235 //               appropriate convert function.
00236 ////////////////////////////////////////////////////////////////////
00237 void FltToEggConverter::
00238 dispatch_record(const FltRecord *flt_record, FltToEggLevelState &state) {
00239   if (flt_record->is_of_type(FltLOD::get_class_type())) {
00240     convert_lod(DCAST(FltLOD, flt_record), state);
00241 
00242   } else if (flt_record->is_of_type(FltGroup::get_class_type())) {
00243     convert_group(DCAST(FltGroup, flt_record), state);
00244 
00245   } else if (flt_record->is_of_type(FltObject::get_class_type())) {
00246     convert_object(DCAST(FltObject, flt_record), state);
00247 
00248   } else if (flt_record->is_of_type(FltFace::get_class_type())) {
00249     convert_face(DCAST(FltFace, flt_record), state);
00250 
00251   } else if (flt_record->is_of_type(FltExternalReference::get_class_type())) {
00252     convert_ext_ref(DCAST(FltExternalReference, flt_record), state);
00253 
00254     // Fallbacks.
00255   } else if (flt_record->is_of_type(FltBeadID::get_class_type())) {
00256     convert_bead_id(DCAST(FltBeadID, flt_record), state);
00257 
00258   } else if (flt_record->is_of_type(FltBead::get_class_type())) {
00259     convert_bead(DCAST(FltBead, flt_record), state);
00260 
00261   } else {
00262     convert_record(flt_record, state);
00263   }
00264 }
00265 
00266 ////////////////////////////////////////////////////////////////////
00267 //     Function: FltToEggConverter::convert_lod
00268 //       Access: Private
00269 //  Description: Converts the LOD bead and all of its children.
00270 ////////////////////////////////////////////////////////////////////
00271 void FltToEggConverter::
00272 convert_lod(const FltLOD *flt_lod, FltToEggLevelState &state) {
00273   EggGroup *egg_group = new EggGroup(flt_lod->get_id());
00274   state._egg_parent->add_child(egg_group);
00275 
00276   EggSwitchConditionDistance lod
00277     (flt_lod->_switch_in, flt_lod->_switch_out,
00278      LPoint3d(flt_lod->_center_x, flt_lod->_center_y, flt_lod->_center_z),
00279      flt_lod->_transition_range);
00280   egg_group->set_lod(lod);
00281 
00282   state.set_transform(flt_lod, egg_group);
00283   parse_comment(flt_lod, egg_group);
00284 
00285   FltToEggLevelState next_state(state);
00286   next_state._egg_parent = egg_group;
00287   convert_record(flt_lod, next_state);
00288 }
00289 
00290 ////////////////////////////////////////////////////////////////////
00291 //     Function: FltToEggConverter::convert_group
00292 //       Access: Private
00293 //  Description: Converts the group and all of its children.
00294 ////////////////////////////////////////////////////////////////////
00295 void FltToEggConverter::
00296 convert_group(const FltGroup *flt_group, FltToEggLevelState &state) {
00297   EggGroup *egg_group = new EggGroup(flt_group->get_id());
00298   state._egg_parent->add_child(egg_group);
00299 
00300   if ((flt_group->_flags & FltGroup::F_forward_animation) != 0) {
00301     // It's a sequence animation.
00302     egg_group->set_switch_flag(true);
00303     egg_group->set_switch_fps(24.0);
00304   }
00305 
00306   state.set_transform(flt_group, egg_group);
00307   parse_comment(flt_group, egg_group);
00308 
00309   ///*** replicate count.
00310 
00311   FltToEggLevelState next_state(state);
00312   next_state._egg_parent = egg_group;
00313   convert_record(flt_group, next_state);
00314 }
00315 
00316 ////////////////////////////////////////////////////////////////////
00317 //     Function: FltToEggConverter::convert_object
00318 //       Access: Private
00319 //  Description: Converts the object and all of its children.
00320 ////////////////////////////////////////////////////////////////////
00321 void FltToEggConverter::
00322 convert_object(const FltObject *flt_object, FltToEggLevelState &state) {
00323   EggGroup *egg_group = new EggGroup(flt_object->get_id());
00324   state._egg_parent->add_child(egg_group);
00325 
00326   state.set_transform(flt_object, egg_group);
00327   parse_comment(flt_object, egg_group);
00328 
00329   FltToEggLevelState next_state(state);
00330   next_state._flt_object = flt_object;
00331   next_state._egg_parent = egg_group;
00332   convert_record(flt_object, next_state);
00333 }
00334 
00335 ////////////////////////////////////////////////////////////////////
00336 //     Function: FltToEggConverter::convert_bead_id
00337 //       Access: Private
00338 //  Description: Converts the generic bead (with ID) and all of its
00339 //               children.
00340 ////////////////////////////////////////////////////////////////////
00341 void FltToEggConverter::
00342 convert_bead_id(const FltBeadID *flt_bead, FltToEggLevelState &state) {
00343   nout << "Don't know how to convert beads of type " << flt_bead->get_type()
00344        << "\n";
00345   EggGroup *egg_group = new EggGroup(flt_bead->get_id());
00346   state._egg_parent->add_child(egg_group);
00347 
00348   state.set_transform(flt_bead, egg_group);
00349   parse_comment(flt_bead, egg_group);
00350 
00351   FltToEggLevelState next_state(state);
00352   next_state._egg_parent = egg_group;
00353   convert_record(flt_bead, next_state);
00354 }
00355 
00356 ////////////////////////////////////////////////////////////////////
00357 //     Function: FltToEggConverter::convert_bead
00358 //       Access: Private
00359 //  Description: Converts the generic bead (without ID) and all of its
00360 //               children.
00361 ////////////////////////////////////////////////////////////////////
00362 void FltToEggConverter::
00363 convert_bead(const FltBead *flt_bead, FltToEggLevelState &state) {
00364   nout << "Don't know how to convert beads of type " << flt_bead->get_type()
00365        << "\n";
00366   EggGroup *egg_group = new EggGroup;
00367   state._egg_parent->add_child(egg_group);
00368 
00369   state.set_transform(flt_bead, egg_group);
00370   parse_comment(flt_bead, egg_group);
00371 
00372   FltToEggLevelState next_state(state);
00373   next_state._egg_parent = egg_group;
00374   convert_record(flt_bead, next_state);
00375 }
00376 
00377 ////////////////////////////////////////////////////////////////////
00378 //     Function: FltToEggConverter::convert_face
00379 //       Access: Private
00380 //  Description: Converts the face and all of its children.
00381 ////////////////////////////////////////////////////////////////////
00382 void FltToEggConverter::
00383 convert_face(const FltFace *flt_face, FltToEggLevelState &state) {
00384   bool is_light;
00385   switch (flt_face->_draw_type) {
00386   case FltGeometry::DT_omni_light:
00387   case FltGeometry::DT_uni_light:
00388   case FltGeometry::DT_bi_light:
00389     is_light = true;
00390     break;
00391 
00392   default:
00393     is_light = false;
00394   }
00395 
00396   PT(EggPrimitive) egg_prim;
00397   if (is_light) {
00398     egg_prim = new EggPoint;
00399   } else {
00400     egg_prim = new EggPolygon;
00401   }
00402 
00403   // Collect the vertices for this primitive.
00404   pvector< PT_EggVertex > vertices;
00405 
00406   const FltVertexList *vlist = (FltVertexList *)NULL;
00407   int num_children = flt_face->get_num_children();
00408   for (int i = 0; i < num_children && vlist == (FltVertexList *)NULL; i++) {
00409     const FltRecord *child = flt_face->get_child(i);
00410     if (child->is_of_type(FltVertexList::get_class_type())) {
00411       vlist = DCAST(FltVertexList, child);
00412     }
00413   }
00414 
00415   if (vlist != (FltVertexList *)NULL) {
00416     int num_vertices = vlist->get_num_vertices();
00417     for (int i = 0; i < num_vertices; i++) {
00418       FltVertex *flt_vertex = vlist->get_vertex(i);
00419       vertices.push_back(make_egg_vertex(flt_vertex));
00420     }
00421   }
00422 
00423   setup_geometry(flt_face, state, egg_prim, _main_egg_vpool, vertices);
00424 }
00425 
00426 ////////////////////////////////////////////////////////////////////
00427 //     Function: FltToEggConverter::convert_ext_ref
00428 //       Access: Private
00429 //  Description: Converts the external reference node.
00430 ////////////////////////////////////////////////////////////////////
00431 void FltToEggConverter::
00432 convert_ext_ref(const FltExternalReference *flt_ext, FltToEggLevelState &state) {
00433   // Get a group node to put the reference into.
00434   EggGroupNode *egg_parent =
00435     state.get_synthetic_group("", flt_ext);
00436 
00437   handle_external_reference(egg_parent, flt_ext->get_ref_filename());
00438 }
00439 
00440 ////////////////////////////////////////////////////////////////////
00441 //     Function: FltToEggConverter::setup_geometry
00442 //       Access: Private
00443 //  Description: Applies the state indicated in the FltGeometry record
00444 //               to the indicated EggPrimitive and all of its
00445 //               indicated vertices, and then officially adds the
00446 //               vertices to the vertex pool and to the primitive, and
00447 //               adds the primitive to its appropriate parent.
00448 ////////////////////////////////////////////////////////////////////
00449 void FltToEggConverter::
00450 setup_geometry(const FltGeometry *flt_geom, FltToEggLevelState &state,
00451                EggPrimitive *egg_prim, EggVertexPool *egg_vpool,
00452                const FltToEggConverter::EggVertices &vertices) {
00453 
00454   // Determine what the appropriate parent will be.
00455   EggGroupNode *egg_parent =
00456     state.get_synthetic_group(flt_geom->get_id(), flt_geom,
00457                               flt_geom->_billboard_type);
00458 
00459   // Create a new state to reflect the new parent.
00460   FltToEggLevelState next_state(state);
00461   next_state._egg_parent = egg_parent;
00462 
00463   // Check for decals onto the primitive.
00464   convert_subfaces(flt_geom, next_state);
00465 
00466   // Add the primitive to its new home.
00467   next_state._egg_parent->add_child(egg_prim);
00468 
00469   // Now examine the vertices.
00470   EggVertices::const_iterator vi;
00471 
00472   bool use_vertex_color = true;
00473   bool keep_normals = true;
00474   switch (flt_geom->_light_mode) {
00475   case FltGeometry::LM_face_no_normal:
00476     use_vertex_color = false;
00477     keep_normals = false;
00478     break;
00479 
00480   case FltGeometry::LM_vertex_no_normal:
00481     use_vertex_color = true;
00482     keep_normals = false;
00483     break;
00484 
00485   case FltGeometry::LM_face_with_normal:
00486     use_vertex_color = false;
00487     keep_normals = true;
00488     break;
00489 
00490   case FltGeometry::LM_vertex_with_normal:
00491     use_vertex_color = true;
00492     keep_normals = true;
00493     break;
00494   }
00495 
00496   LColor face_color = flt_geom->get_color();
00497 
00498   if (state._flt_object != (FltObject *)NULL) {
00499     // If we have a FltObject above us, it might also specify a
00500     // transparency.  This combines with our existing transparency.
00501     PN_stdfloat alpha = 1.0 - (state._flt_object->_transparency / 65535.0);
00502     face_color[3] *= alpha;
00503   }
00504 
00505   egg_prim->set_color(face_color);
00506 
00507   if (flt_geom->has_texture()) {
00508     // If the geometry has a texture, apply it.
00509     egg_prim->set_texture(make_egg_texture(flt_geom->get_texture()));
00510 
00511     if (flt_geom->_texwhite) {
00512       // If the geometry should be colored white under the texture,
00513       // then eliminate vertex colors.
00514       use_vertex_color = false;
00515     }
00516   }
00517 
00518   if (use_vertex_color) {
00519     // If we're to use vertex color instead of the face color, remove
00520     // the face color to eliminate any ambiguity.
00521     egg_prim->clear_color();
00522 
00523     // Also, make sure the transparency is set correctly across all
00524     // vertices.
00525     for (vi = vertices.begin(); vi != vertices.end(); ++vi) {
00526       EggVertex *vertex = (*vi);
00527       if (vertex->has_color()) {
00528         LColor vertex_color = vertex->get_color();
00529         vertex_color[3] = face_color[3];
00530         vertex->set_color(vertex_color);
00531       } else {
00532         if (flt_geom->has_color()) {
00533           // If a vertex doesn't have a color but the face does, set
00534           // the vertex to use the face color.
00535           vertex->set_color(face_color);
00536         }
00537       }
00538     }
00539 
00540   } else {
00541     // If we're to use face color instead of vertex color, remove the
00542     // vertex color to eliminate any ambiguity.
00543     for (vi = vertices.begin(); vi != vertices.end(); ++vi) {
00544       (*vi)->clear_color();
00545     }
00546   }
00547 
00548   if (!keep_normals) {
00549     // If we're not to use the normals, then eliminate them.
00550     for (vi = vertices.begin(); vi != vertices.end(); ++vi) {
00551       (*vi)->clear_normal();
00552     }
00553   }
00554 
00555   if (flt_geom->_draw_type == FltGeometry::DT_solid_no_cull) {
00556     // A double-sided polygon.
00557     egg_prim->set_bface_flag(true);
00558   }
00559 
00560   for (vi = vertices.begin(); vi != vertices.end(); ++vi) {
00561     EggVertex *egg_vertex = egg_vpool->create_unique_vertex(*(*vi));
00562     egg_prim->add_vertex(egg_vertex);
00563   }
00564 
00565   parse_comment(flt_geom, egg_prim);
00566 }
00567 
00568 ////////////////////////////////////////////////////////////////////
00569 //     Function: FltToEggConverter::convert_subfaces
00570 //       Access: Public
00571 //  Description: Records all of the subfaces of the indicated group as
00572 //               coplanar polygons (i.e. decals) of the group.
00573 //
00574 //               If coplanar polygons exist, the state is modified so
00575 //               that _egg_parent is the new group to which the base
00576 //               polygons should be added.  Therefore, subfaces should
00577 //               be defined before the ordinary children are
00578 //               processed.
00579 ////////////////////////////////////////////////////////////////////
00580 void FltToEggConverter::
00581 convert_subfaces(const FltRecord *flt_record, FltToEggLevelState &state) {
00582   int num_subfaces = flt_record->get_num_subfaces();
00583   if (num_subfaces == 0) {
00584     // No subfaces.
00585     return;
00586   }
00587 
00588   // Create a new group to contain the base polygons.
00589   EggGroup *egg_group = new EggGroup("decal_base");
00590   state._egg_parent->add_child(egg_group);
00591   state._egg_parent = egg_group;
00592 
00593   egg_group->set_decal_flag(true);
00594 
00595   // Now create a nested group to hold the decals.
00596   EggGroup *decal_group = new EggGroup("decals");
00597   egg_group->add_child(decal_group);
00598   egg_group = decal_group;
00599 
00600   FltToEggLevelState next_state(state);
00601   next_state._egg_parent = decal_group;
00602 
00603   for (int i = 0; i < num_subfaces; i++) {
00604     const FltRecord *subface = flt_record->get_subface(i);
00605     dispatch_record(subface, next_state);
00606   }
00607 }
00608 
00609 ////////////////////////////////////////////////////////////////////
00610 //     Function: FltToEggConverter::parse_comment
00611 //       Access: Private
00612 //  Description: Scans the comment on this record for "<egg> { ... }"
00613 //               and parses the enclosed string as if it appeared in
00614 //               the egg file.  Returns true on success, false on
00615 //               syntax error (in which case _error is also set to
00616 //               true).
00617 ////////////////////////////////////////////////////////////////////
00618 bool FltToEggConverter::
00619 parse_comment(const FltBeadID *flt_bead, EggNode *egg_node) {
00620   return parse_comment(flt_bead->get_comment(), flt_bead->get_id(), egg_node);
00621 }
00622 
00623 ////////////////////////////////////////////////////////////////////
00624 //     Function: FltToEggConverter::parse_comment
00625 //       Access: Private
00626 //  Description: Scans the comment on this record for "<egg> { ... }"
00627 //               and parses the enclosed string as if it appeared in
00628 //               the egg file.  Returns true on success, false on
00629 //               syntax error (in which case _error is also set to
00630 //               true).
00631 ////////////////////////////////////////////////////////////////////
00632 bool FltToEggConverter::
00633 parse_comment(const FltBead *flt_bead, EggNode *egg_node) {
00634   return parse_comment(flt_bead->get_comment(), "anonymous", egg_node);
00635 }
00636 
00637 ////////////////////////////////////////////////////////////////////
00638 //     Function: FltToEggConverter::parse_comment
00639 //       Access: Private
00640 //  Description: Scans the comment on this record for "<egg> { ... }"
00641 //               and parses the enclosed string as if it appeared in
00642 //               the egg file.  Returns true on success, false on
00643 //               syntax error (in which case _error is also set to
00644 //               true).
00645 ////////////////////////////////////////////////////////////////////
00646 bool FltToEggConverter::
00647 parse_comment(const FltTexture *flt_texture, EggNode *egg_node) {
00648   return parse_comment(flt_texture->get_comment(), 
00649                        flt_texture->get_texture_filename(), egg_node);
00650 }
00651 
00652 ////////////////////////////////////////////////////////////////////
00653 //     Function: FltToEggConverter::parse_comment
00654 //       Access: Private
00655 //  Description: Scans the comment on this record for "<egg> { ... }"
00656 //               and parses the enclosed string as if it appeared in
00657 //               the egg file.  Returns true on success, false on
00658 //               syntax error (in which case _error is also set to
00659 //               true).
00660 ////////////////////////////////////////////////////////////////////
00661 bool FltToEggConverter::
00662 parse_comment(const string &comment, const string &name,
00663               EggNode *egg_node) {
00664   if (comment.empty()) {
00665     // No comment.
00666     return true;
00667   }
00668 
00669   // Scan for <egg>.
00670   static const string egg_str = "<egg>";
00671 
00672   size_t p;
00673   p = 0;
00674   while (p < comment.length() &&
00675          cmp_nocase(comment.substr(p, 5), egg_str) != 0) {
00676     p++;
00677   }
00678 
00679   if (p >= comment.length()) {
00680     // No "<egg>" in the comment.
00681     return true;
00682   }
00683 
00684   p += 5;
00685   // Now scan past whitespace for the open curly brace.
00686   while (p < comment.length() && isspace(comment[p])) {
00687     ++p;
00688   }
00689   if (p >= comment.length() || comment[p] != '{') {
00690     nout << "No opening brace in comment for "
00691          << name << "\n\n";
00692     _error = true;
00693     return false;
00694   }
00695 
00696   // Here's the beginning of the string after "<egg> {".  Now lop off
00697   // the closing brace at the end.
00698   ++p;
00699   size_t q = comment.length() - 1;
00700   while (q > p && comment[q] != '}') {
00701     --q;
00702   }
00703   if (q == p) {
00704     nout << "No closing brace in comment for "
00705          << name << "\n\n";
00706     _error = true;
00707     return false;
00708   }
00709 
00710   string egg_syntax = comment.substr(p, q - p);
00711 
00712   if (!egg_node->parse_egg(egg_syntax)) {
00713     nout << "Syntax error in comment for "
00714          << name << "\n\n";
00715     _error = true;
00716     return false;
00717   }
00718 
00719   // Correctly parsed!
00720   return true;
00721 }
00722 
00723 ////////////////////////////////////////////////////////////////////
00724 //     Function: FltToEggConverter::make_egg_vertex
00725 //       Access: Private
00726 //  Description: Makes a new EggVertex for the indicated FltVertex.
00727 //               The vertex is not automatically added to the vertex
00728 //               pool.
00729 ////////////////////////////////////////////////////////////////////
00730 PT_EggVertex FltToEggConverter::
00731 make_egg_vertex(const FltVertex *flt_vertex) {
00732   PT_EggVertex egg_vertex = new EggVertex;
00733   egg_vertex->set_pos(flt_vertex->_pos);
00734 
00735   if (flt_vertex->_has_normal) {
00736     egg_vertex->set_normal(LCAST(double, flt_vertex->_normal));
00737   }
00738 
00739   if (flt_vertex->_has_uv) {
00740     egg_vertex->set_uv(LCAST(double, flt_vertex->_uv));
00741   }
00742 
00743   if (flt_vertex->has_color()) {
00744     egg_vertex->set_color(flt_vertex->get_color());
00745   }
00746 
00747   return egg_vertex;
00748 }
00749 
00750 ////////////////////////////////////////////////////////////////////
00751 //     Function: FltToEggConverter::make_egg_texture
00752 //       Access: Private
00753 //  Description: Makes a new EggTexture for the indicated FltTexture,
00754 //               or returns a pointer to one previously made for the
00755 //               same FltTexture.
00756 ////////////////////////////////////////////////////////////////////
00757 PT_EggTexture FltToEggConverter::
00758 make_egg_texture(const FltTexture *flt_texture) {
00759   Textures::const_iterator ti;
00760   ti = _textures.find(flt_texture);
00761   if (ti != _textures.end()) {
00762     // There's one previously created.
00763     return (*ti).second;
00764   }
00765 
00766   // Create a new one.
00767   string tref_name = format_string(flt_texture->_pattern_index);
00768   Filename filename = flt_texture->get_texture_filename();
00769 
00770   PT_EggTexture egg_texture = new EggTexture(tref_name, filename);
00771 
00772   _textures.insert(Textures::value_type(flt_texture, egg_texture));
00773 
00774   // Set up the texture properties.
00775 
00776   switch (flt_texture->_min_filter) {
00777   case FltTexture::MN_point:
00778     egg_texture->set_minfilter(EggTexture::FT_nearest);
00779     break;
00780 
00781   case FltTexture::MN_bilinear:
00782     egg_texture->set_minfilter(EggTexture::FT_linear);
00783     break;
00784 
00785   case FltTexture::MN_mipmap_point:
00786     egg_texture->set_minfilter(EggTexture::FT_nearest_mipmap_nearest);
00787     break;
00788 
00789   case FltTexture::MN_mipmap_linear:
00790     egg_texture->set_minfilter(EggTexture::FT_nearest_mipmap_linear);
00791     break;
00792 
00793   case FltTexture::MN_mipmap_bilinear:
00794     egg_texture->set_minfilter(EggTexture::FT_linear_mipmap_nearest);
00795     break;
00796 
00797   case FltTexture::MN_mipmap_trilinear:
00798   case FltTexture::MN_OB_mipmap:
00799     egg_texture->set_minfilter(EggTexture::FT_linear_mipmap_linear);
00800     break;
00801 
00802   case FltTexture::MN_bicubic:
00803   case FltTexture::MN_bilinear_gequal:
00804   case FltTexture::MN_bilinear_lequal:
00805   case FltTexture::MN_bicubic_gequal:
00806   case FltTexture::MN_bicubic_lequal:
00807     // Not supported.
00808     break;
00809   }
00810 
00811   switch (flt_texture->_mag_filter) {
00812   case FltTexture::MG_point:
00813     egg_texture->set_magfilter(EggTexture::FT_nearest);
00814     break;
00815 
00816   case FltTexture::MG_bilinear:
00817     egg_texture->set_magfilter(EggTexture::FT_linear);
00818     break;
00819 
00820   case FltTexture::MG_bicubic:
00821   case FltTexture::MG_sharpen:
00822   case FltTexture::MG_add_detail:
00823   case FltTexture::MG_modulate_detail:
00824   case FltTexture::MG_bilinear_gequal:
00825   case FltTexture::MG_bilinear_lequal:
00826   case FltTexture::MG_bicubic_gequal:
00827   case FltTexture::MG_bicubic_lequal:
00828     // Not supported.
00829     break;
00830   }
00831 
00832   switch (flt_texture->_repeat) {
00833   case FltTexture::RT_repeat:
00834     egg_texture->set_wrap_mode(EggTexture::WM_repeat);
00835     break;
00836 
00837   case FltTexture::RT_clamp:
00838     egg_texture->set_wrap_mode(EggTexture::WM_clamp);
00839     break;
00840   }
00841 
00842   switch (flt_texture->_repeat_u) {
00843   case FltTexture::RT_repeat:
00844     egg_texture->set_wrap_u(EggTexture::WM_repeat);
00845     break;
00846 
00847   case FltTexture::RT_clamp:
00848     egg_texture->set_wrap_u(EggTexture::WM_clamp);
00849     break;
00850   }
00851 
00852   switch (flt_texture->_repeat_v) {
00853   case FltTexture::RT_repeat:
00854     egg_texture->set_wrap_v(EggTexture::WM_repeat);
00855     break;
00856 
00857   case FltTexture::RT_clamp:
00858     egg_texture->set_wrap_v(EggTexture::WM_clamp);
00859     break;
00860   }
00861 
00862   switch (flt_texture->_env_type) {
00863   case FltTexture::ET_modulate:
00864     egg_texture->set_env_type(EggTexture::ET_modulate);
00865     break;
00866 
00867   case FltTexture::ET_decal:
00868     egg_texture->set_env_type(EggTexture::ET_decal);
00869     break;
00870 
00871   case FltTexture::ET_blend:
00872   case FltTexture::ET_color:
00873     // Not supported.
00874     break;
00875   }
00876 
00877   switch (flt_texture->_internal_format) {
00878   case FltTexture::IF_default:
00879     break;
00880 
00881   case FltTexture::IF_i_12a_4:
00882   case FltTexture::IF_ia_12:
00883   case FltTexture::IF_ia_8:
00884     egg_texture->set_format(EggTexture::F_luminance_alpha);
00885     break;
00886 
00887   case FltTexture::IF_rgb_5:
00888     egg_texture->set_format(EggTexture::F_rgb5);
00889     break;
00890 
00891   case FltTexture::IF_rgba_4:
00892     egg_texture->set_format(EggTexture::F_rgba4);
00893     break;
00894 
00895 
00896   case FltTexture::IF_rgba_8:
00897     egg_texture->set_format(EggTexture::F_rgba8);
00898     break;
00899 
00900   case FltTexture::IF_rgba_12:
00901     egg_texture->set_format(EggTexture::F_rgba12);
00902     break;
00903 
00904   case FltTexture::IF_i_16:
00905     if (flt_texture->_intensity_is_alpha) {
00906       egg_texture->set_format(EggTexture::F_alpha);
00907     } else {
00908       egg_texture->set_format(EggTexture::F_luminance);
00909     }
00910     break;
00911 
00912   case FltTexture::IF_rgb_12:
00913     egg_texture->set_format(EggTexture::F_rgb12);
00914     break;
00915   }
00916 
00917   parse_comment(flt_texture, egg_texture);
00918   return egg_texture;
00919 }
 All Classes Functions Variables Enumerations