00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "eggToFlt.h"
00016 #include "fltHeader.h"
00017 #include "fltBead.h"
00018 #include "fltGroup.h"
00019 #include "fltFace.h"
00020 #include "fltVertexList.h"
00021 #include "fltVertex.h"
00022 #include "fltTexture.h"
00023 #include "fltTransformTranslate.h"
00024 #include "fltTransformRotateAboutEdge.h"
00025 #include "fltTransformScale.h"
00026 #include "fltTransformGeneralMatrix.h"
00027 #include "eggPolygon.h"
00028 #include "eggPoint.h"
00029 #include "eggPrimitive.h"
00030 #include "eggExternalReference.h"
00031 #include "eggGroup.h"
00032 #include "eggGroupNode.h"
00033 #include "eggTexture.h"
00034 #include "eggTransform.h"
00035 #include "dcast.h"
00036 #include "string_utils.h"
00037 #include "vector_string.h"
00038 #include "pystub.h"
00039
00040
00041
00042
00043
00044
00045 EggToFlt::
00046 EggToFlt() :
00047 EggToSomething("MultiGen", ".flt", true, false)
00048 {
00049 set_binary_output(true);
00050 set_program_description
00051 ("egg2lt converts files from egg format to MultiGen .flt "
00052 "format. It attempts to be as robust as possible, and matches "
00053 "the capabilities of flt2egg. Generally, converting a model "
00054 "from egg2lt and then back via flt2egg will result in essentially "
00055 "the same egg file, within the limitations of what can be "
00056 "represented in flt.");
00057
00058 add_option
00059 ("attr", "none/new/all", 0,
00060 "Specifies whether to write (or rewrite) .attr files for each "
00061 "texture image. MultiGen stores texture properties like mipmapping "
00062 "in a separate .attr file for each different texture image. "
00063 "If this parameter is \"none\", these files will not be generated; "
00064 "if this is \"new\", these files will only be generated if they "
00065 "do not already exist (even if the properties have changed). "
00066 "Specifying \"all\" causes these to be rewritten every time.",
00067 &EggToFlt::dispatch_attr, NULL, &_auto_attr_update);
00068
00069
00070
00071 remove_option("cs");
00072 _coordinate_system = CS_zup_right;
00073 _got_coordinate_system = true;
00074 _auto_attr_update = FltHeader::AU_if_missing;
00075 }
00076
00077
00078
00079
00080
00081
00082 void EggToFlt::
00083 run() {
00084 _flt_header = new FltHeader(_path_replace);
00085 _flt_header->set_auto_attr_update(_auto_attr_update);
00086
00087 traverse(_data, _flt_header, FltGeometry::BT_none);
00088
00089
00090 FltError result = _flt_header->write_flt(get_output());
00091 if (result != FE_ok) {
00092 nout << "Cannot write " << get_output_filename() << "\n";
00093 exit(1);
00094 }
00095 }
00096
00097
00098
00099
00100
00101
00102 bool EggToFlt::
00103 dispatch_attr(const string &opt, const string &arg, void *var) {
00104 FltHeader::AttrUpdate *ip = (FltHeader::AttrUpdate *)var;
00105
00106 if (cmp_nocase(arg, "none") == 0) {
00107 *ip = FltHeader::AU_none;
00108
00109 } else if (cmp_nocase(arg, "new") == 0) {
00110 *ip = FltHeader::AU_if_missing;
00111
00112 } else if (cmp_nocase(arg, "all") == 0) {
00113 *ip = FltHeader::AU_always;
00114
00115 } else {
00116 nout << "-" << opt
00117 << " requires either \"none\", \"new\", or \"all\".\n";
00118 return false;
00119 }
00120
00121 return true;
00122 }
00123
00124
00125
00126
00127
00128
00129 void EggToFlt::
00130 traverse(EggNode *egg_node, FltBead *flt_node,
00131 FltGeometry::BillboardType billboard) {
00132 if (egg_node->is_of_type(EggPolygon::get_class_type()) ||
00133 egg_node->is_of_type(EggPoint::get_class_type())) {
00134
00135 EggPrimitive *egg_primitive = DCAST(EggPrimitive, egg_node);
00136 convert_primitive(egg_primitive, flt_node, billboard);
00137
00138 } else if (egg_node->is_of_type(EggExternalReference::get_class_type())) {
00139
00140
00141 } else if (egg_node->is_of_type(EggGroup::get_class_type())) {
00142
00143 EggGroup *egg_group = DCAST(EggGroup, egg_node);
00144
00145 if (egg_group->get_group_type() == EggGroup::GT_joint) {
00146
00147 return;
00148 }
00149
00150 convert_group(egg_group, flt_node, billboard);
00151
00152 } else if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
00153
00154 EggGroupNode *egg_group = DCAST(EggGroupNode, egg_node);
00155 EggGroupNode::iterator ci;
00156 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
00157 traverse(*ci, flt_node, billboard);
00158 }
00159 }
00160 }
00161
00162
00163
00164
00165
00166
00167
00168
00169 void EggToFlt::
00170 convert_primitive(EggPrimitive *egg_primitive, FltBead *flt_node,
00171 FltGeometry::BillboardType billboard) {
00172 FltFace *flt_face = new FltFace(_flt_header);
00173 flt_node->add_child(flt_face);
00174
00175 flt_face->_billboard_type = billboard;
00176
00177 if (egg_primitive->has_color()) {
00178 flt_face->set_color(egg_primitive->get_color());
00179 }
00180
00181 if (egg_primitive->is_of_type(EggPoint::get_class_type())) {
00182
00183 flt_face->_draw_type = FltFace::DT_omni_light;
00184
00185 } else if (egg_primitive->get_bface_flag()) {
00186
00187 flt_face->_draw_type = FltFace::DT_solid_no_cull;
00188
00189 } else {
00190
00191 flt_face->_draw_type = FltFace::DT_solid_cull_backface;
00192 }
00193
00194 if (egg_primitive->has_texture()) {
00195 EggTexture *egg_texture = egg_primitive->get_texture();
00196 FltTexture *flt_texture = get_flt_texture(egg_texture);
00197 flt_face->set_texture(flt_texture);
00198 }
00199
00200
00201
00202
00203 FltVertexList *flt_vertices = new FltVertexList(_flt_header);
00204 flt_face->add_child(flt_vertices);
00205
00206 EggPrimitive::iterator vi;
00207 bool all_verts_have_color = true;
00208 bool all_verts_have_normal = true;
00209 for (vi = egg_primitive->begin(); vi != egg_primitive->end(); ++vi) {
00210 EggVertex *egg_vertex = (*vi);
00211 FltVertex *flt_vertex = get_flt_vertex(egg_vertex, egg_primitive);
00212 flt_vertices->add_vertex(flt_vertex);
00213
00214 if (!egg_vertex->has_color()) {
00215 all_verts_have_color = false;
00216 }
00217 if (!egg_vertex->has_normal()) {
00218 all_verts_have_normal = false;
00219 }
00220 }
00221 if (all_verts_have_color) {
00222
00223
00224 if (all_verts_have_normal) {
00225
00226 flt_face->_light_mode = FltFace::LM_vertex_with_normal;
00227 } else {
00228 flt_face->_light_mode = FltFace::LM_vertex_no_normal;
00229 }
00230 } else {
00231 if (all_verts_have_normal) {
00232 flt_face->_light_mode = FltFace::LM_face_with_normal;
00233 } else {
00234 flt_face->_light_mode = FltFace::LM_face_no_normal;
00235 }
00236 }
00237 }
00238
00239
00240
00241
00242
00243
00244
00245
00246 void EggToFlt::
00247 convert_group(EggGroup *egg_group, FltBead *flt_node,
00248 FltGeometry::BillboardType billboard) {
00249 ostringstream egg_syntax;
00250
00251 FltGroup *flt_group = new FltGroup(_flt_header);
00252 flt_node->add_child(flt_group);
00253
00254 flt_group->set_id(egg_group->get_name());
00255
00256 switch (egg_group->get_billboard_type()) {
00257
00258
00259 case EggGroup::BT_axis:
00260 billboard = FltGeometry::BT_axial;
00261 break;
00262
00263 case EggGroup::BT_point_world_relative:
00264 billboard = FltGeometry::BT_point;
00265 break;
00266
00267 case EggGroup::BT_point_camera_relative:
00268
00269 billboard = FltGeometry::BT_fixed;
00270 break;
00271
00272 default:
00273 break;
00274 }
00275
00276 if (egg_group->has_transform()) {
00277 apply_transform(egg_group, flt_group);
00278 }
00279
00280 if (egg_group->get_switch_flag()) {
00281 if (egg_group->get_switch_fps() != 0.0) {
00282
00283 flt_group->_flags |= FltGroup::F_forward_animation;
00284 egg_syntax
00285 << " <Scalar> fps { " << egg_group->get_switch_fps() << " }\n";
00286 } else {
00287
00288 egg_group->write_switch_flags(egg_syntax, 2);
00289 }
00290 }
00291
00292
00293
00294
00295 egg_group->write_collide_flags(egg_syntax, 2);
00296 egg_group->write_model_flags(egg_syntax, 2);
00297 egg_group->write_object_types(egg_syntax, 2);
00298 egg_group->write_decal_flags(egg_syntax, 2);
00299 egg_group->write_tags(egg_syntax, 2);
00300 egg_group->write_render_mode(egg_syntax, 2);
00301
00302 apply_egg_syntax(egg_syntax.str(), flt_group);
00303
00304 EggGroup::iterator ci;
00305 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
00306 traverse(*ci, flt_group, billboard);
00307 }
00308 }
00309
00310
00311
00312
00313
00314
00315
00316 void EggToFlt::
00317 apply_transform(EggTransform *egg_transform, FltBead *flt_node) {
00318 flt_node->clear_transform();
00319
00320 bool components_ok = true;
00321 int num_components = egg_transform->get_num_components();
00322 for (int i = num_components - 1; i >= 0 && components_ok; i--) {
00323 switch (egg_transform->get_component_type(i)) {
00324 case EggTransform::CT_translate2d:
00325 {
00326 FltTransformTranslate *translate =
00327 new FltTransformTranslate(_flt_header);
00328 LVector2d v2 = egg_transform->get_component_vec2(i);
00329 translate->set(LPoint3d::zero(), LVector3d(v2[0], v2[1], 0.0));
00330 flt_node->add_transform_step(translate);
00331 }
00332 break;
00333
00334 case EggTransform::CT_translate3d:
00335 {
00336 FltTransformTranslate *translate =
00337 new FltTransformTranslate(_flt_header);
00338 translate->set(LPoint3d::zero(), egg_transform->get_component_vec3(i));
00339 flt_node->add_transform_step(translate);
00340 }
00341 break;
00342
00343 case EggTransform::CT_rotate2d:
00344 {
00345 FltTransformRotateAboutEdge *rotate =
00346 new FltTransformRotateAboutEdge(_flt_header);
00347 rotate->set(LPoint3d::zero(), LPoint3d(0.0, 0.0, 1.0),
00348 egg_transform->get_component_number(i));
00349 flt_node->add_transform_step(rotate);
00350 }
00351 break;
00352
00353 case EggTransform::CT_rotx:
00354 {
00355 FltTransformRotateAboutEdge *rotate =
00356 new FltTransformRotateAboutEdge(_flt_header);
00357 rotate->set(LPoint3d::zero(), LPoint3d(1.0, 0.0, 0.0),
00358 egg_transform->get_component_number(i));
00359 flt_node->add_transform_step(rotate);
00360 }
00361 break;
00362
00363 case EggTransform::CT_roty:
00364 {
00365 FltTransformRotateAboutEdge *rotate =
00366 new FltTransformRotateAboutEdge(_flt_header);
00367 rotate->set(LPoint3d::zero(), LPoint3d(0.0, 1.0, 0.0),
00368 egg_transform->get_component_number(i));
00369 flt_node->add_transform_step(rotate);
00370 }
00371 break;
00372
00373 case EggTransform::CT_rotz:
00374 {
00375 FltTransformRotateAboutEdge *rotate =
00376 new FltTransformRotateAboutEdge(_flt_header);
00377 rotate->set(LPoint3d::zero(), LPoint3d(0.0, 0.0, 1.0),
00378 egg_transform->get_component_number(i));
00379 flt_node->add_transform_step(rotate);
00380 }
00381 break;
00382
00383 case EggTransform::CT_rotate3d:
00384 {
00385 FltTransformRotateAboutEdge *rotate =
00386 new FltTransformRotateAboutEdge(_flt_header);
00387 rotate->set(LPoint3d::zero(), egg_transform->get_component_vec3(i),
00388 egg_transform->get_component_number(i));
00389 flt_node->add_transform_step(rotate);
00390 }
00391 break;
00392
00393 case EggTransform::CT_scale2d:
00394 {
00395 FltTransformScale *scale = new FltTransformScale(_flt_header);
00396 LVector2d v2 = egg_transform->get_component_vec2(i);
00397 scale->set(LPoint3d::zero(), LVector3(v2[0], v2[1], 1.0f));
00398 flt_node->add_transform_step(scale);
00399 }
00400 break;
00401
00402 case EggTransform::CT_scale3d:
00403 {
00404 FltTransformScale *scale = new FltTransformScale(_flt_header);
00405 scale->set(LPoint3d::zero(), LCAST(PN_stdfloat, egg_transform->get_component_vec3(i)));
00406 flt_node->add_transform_step(scale);
00407 }
00408 break;
00409
00410 case EggTransform::CT_uniform_scale:
00411 {
00412 FltTransformScale *scale = new FltTransformScale(_flt_header);
00413 PN_stdfloat factor = (PN_stdfloat)egg_transform->get_component_number(i);
00414 scale->set(LPoint3d::zero(), LVecBase3(factor, factor, factor));
00415 flt_node->add_transform_step(scale);
00416 }
00417 break;
00418
00419 case EggTransform::CT_matrix3:
00420 {
00421 FltTransformGeneralMatrix *matrix =
00422 new FltTransformGeneralMatrix(_flt_header);
00423 const LMatrix3d &m = egg_transform->get_component_mat3(i);
00424 LMatrix4d mat4(m(0, 0), m(0, 1), 0.0, m(0, 2),
00425 m(1, 0), m(1, 1), 0.0, m(1, 2),
00426 0.0, 0.0, 1.0, 0.0,
00427 m(2, 0), m(2, 1), 0.0, m(2, 2));
00428 matrix->set_matrix(mat4);
00429 flt_node->add_transform_step(matrix);
00430 }
00431 break;
00432
00433 case EggTransform::CT_matrix4:
00434 {
00435 FltTransformGeneralMatrix *matrix =
00436 new FltTransformGeneralMatrix(_flt_header);
00437 matrix->set_matrix(egg_transform->get_component_mat4(i));
00438 flt_node->add_transform_step(matrix);
00439 }
00440 break;
00441
00442 default:
00443
00444 components_ok = false;
00445 }
00446 }
00447
00448 if (components_ok) {
00449
00450 if (!flt_node->get_transform().almost_equal(egg_transform->get_transform3d())) {
00451 nout << "Incorrect transform! Expected:\n";
00452 egg_transform->get_transform3d().write(nout, 2);
00453 nout << "Computed:\n";
00454 flt_node->get_transform().write(nout, 2);
00455 nout << "\n";
00456 components_ok = false;
00457 }
00458 }
00459
00460 if (!components_ok) {
00461
00462 flt_node->set_transform(egg_transform->get_transform3d());
00463 }
00464 }
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475 void EggToFlt::
00476 apply_egg_syntax(const string &egg_syntax, FltRecord *flt_record) {
00477 if (!egg_syntax.empty()) {
00478 ostringstream out;
00479 out << "<egg> {\n"
00480 << egg_syntax
00481 << "}";
00482 flt_record->set_comment(out.str());
00483 }
00484 }
00485
00486
00487
00488
00489
00490
00491
00492
00493 FltVertex *EggToFlt::
00494 get_flt_vertex(EggVertex *egg_vertex, EggNode *context) {
00495 const LMatrix4d *frame = context->get_vertex_to_node_ptr();
00496 VertexMap &vertex_map = _vertex_map_per_frame[frame];
00497
00498 VertexMap::iterator vi = vertex_map.find(egg_vertex);
00499 if (vi != vertex_map.end()) {
00500 return (*vi).second;
00501 }
00502 FltVertex *flt_vertex = new FltVertex(_flt_header);
00503 flt_vertex->_pos = egg_vertex->get_pos3();
00504
00505 if (egg_vertex->has_color()) {
00506 flt_vertex->set_color(egg_vertex->get_color());
00507 }
00508 if (egg_vertex->has_normal()) {
00509 flt_vertex->_normal = LCAST(PN_stdfloat, egg_vertex->get_normal());
00510 flt_vertex->_has_normal = true;
00511 }
00512 if (egg_vertex->has_uv()) {
00513 flt_vertex->_uv = LCAST(PN_stdfloat, egg_vertex->get_uv());
00514 flt_vertex->_has_uv = true;
00515 }
00516
00517 if (frame != (const LMatrix4d *)NULL) {
00518 flt_vertex->_pos = flt_vertex->_pos * (*frame);
00519 flt_vertex->_normal = flt_vertex->_normal * LCAST(PN_stdfloat, (*frame));
00520 }
00521
00522 _flt_header->add_vertex(flt_vertex);
00523 vertex_map[egg_vertex] = flt_vertex;
00524
00525 return flt_vertex;
00526 }
00527
00528
00529
00530
00531
00532
00533
00534
00535 FltTexture *EggToFlt::
00536 get_flt_texture(EggTexture *egg_texture) {
00537
00538
00539
00540 Filename filename = egg_texture->get_filename();
00541 TextureMap::iterator vi = _texture_map.find(filename);
00542 if (vi != _texture_map.end()) {
00543 return (*vi).second;
00544 }
00545 FltTexture *flt_texture = new FltTexture(_flt_header);
00546 flt_texture->set_texture_filename(filename);
00547
00548 switch (egg_texture->get_minfilter()) {
00549 case EggTexture::FT_nearest:
00550 flt_texture->_min_filter = FltTexture::MN_point;
00551 break;
00552
00553 case EggTexture::FT_linear:
00554 flt_texture->_min_filter = FltTexture::MN_bilinear;
00555 break;
00556
00557 case EggTexture::FT_nearest_mipmap_nearest:
00558 flt_texture->_min_filter = FltTexture::MN_mipmap_point;
00559 break;
00560
00561 case EggTexture::FT_nearest_mipmap_linear:
00562 flt_texture->_min_filter = FltTexture::MN_mipmap_linear;
00563 break;
00564
00565 case EggTexture::FT_linear_mipmap_nearest:
00566 flt_texture->_min_filter = FltTexture::MN_mipmap_bilinear;
00567 break;
00568
00569 case EggTexture::FT_linear_mipmap_linear:
00570 flt_texture->_min_filter = FltTexture::MN_mipmap_trilinear;
00571 break;
00572
00573 default:
00574 break;
00575 }
00576
00577 switch (egg_texture->get_magfilter()) {
00578 case EggTexture::FT_nearest:
00579 flt_texture->_mag_filter = FltTexture::MG_point;
00580 break;
00581
00582 case EggTexture::FT_linear:
00583 flt_texture->_mag_filter = FltTexture::MG_bilinear;
00584 break;
00585
00586 default:
00587 break;
00588 }
00589
00590 switch (egg_texture->get_wrap_mode()) {
00591 case EggTexture::WM_repeat:
00592 flt_texture->_repeat = FltTexture::RT_repeat;
00593 break;
00594
00595 case EggTexture::WM_clamp:
00596 flt_texture->_repeat = FltTexture::RT_clamp;
00597 break;
00598
00599 default:
00600 break;
00601 }
00602
00603 switch (egg_texture->get_wrap_u()) {
00604 case EggTexture::WM_repeat:
00605 flt_texture->_repeat_u = FltTexture::RT_repeat;
00606 break;
00607
00608 case EggTexture::WM_clamp:
00609 flt_texture->_repeat_u = FltTexture::RT_clamp;
00610 break;
00611
00612 default:
00613 break;
00614 }
00615
00616 switch (egg_texture->get_wrap_v()) {
00617 case EggTexture::WM_repeat:
00618 flt_texture->_repeat_v = FltTexture::RT_repeat;
00619 break;
00620
00621 case EggTexture::WM_clamp:
00622 flt_texture->_repeat_v = FltTexture::RT_clamp;
00623 break;
00624
00625 default:
00626 break;
00627 }
00628
00629 switch (egg_texture->get_env_type()) {
00630 case EggTexture::ET_modulate:
00631 flt_texture->_env_type = FltTexture::ET_modulate;
00632 break;
00633
00634 case EggTexture::ET_decal:
00635 flt_texture->_env_type = FltTexture::ET_decal;
00636 break;
00637
00638 default:
00639 break;
00640 }
00641
00642 switch (egg_texture->get_format()) {
00643 case EggTexture::F_luminance_alpha:
00644 case EggTexture::F_luminance_alphamask:
00645 flt_texture->_internal_format = FltTexture::IF_ia_8;
00646 break;
00647
00648 case EggTexture::F_rgb5:
00649 case EggTexture::F_rgb332:
00650 flt_texture->_internal_format = FltTexture::IF_rgb_5;
00651 break;
00652
00653 case EggTexture::F_rgba4:
00654 case EggTexture::F_rgba5:
00655 flt_texture->_internal_format = FltTexture::IF_rgba_4;
00656 break;
00657
00658 case EggTexture::F_rgba8:
00659 case EggTexture::F_rgba:
00660 case EggTexture::F_rgbm:
00661 case EggTexture::F_rgb:
00662 case EggTexture::F_rgb8:
00663 flt_texture->_internal_format = FltTexture::IF_rgba_8;
00664 break;
00665
00666 case EggTexture::F_rgba12:
00667 flt_texture->_internal_format = FltTexture::IF_rgba_12;
00668 break;
00669
00670 case EggTexture::F_alpha:
00671 flt_texture->_internal_format = FltTexture::IF_i_16;
00672 flt_texture->_intensity_is_alpha = true;
00673 break;
00674
00675 case EggTexture::F_luminance:
00676 flt_texture->_internal_format = FltTexture::IF_i_16;
00677 break;
00678
00679 case EggTexture::F_rgb12:
00680 flt_texture->_internal_format = FltTexture::IF_rgb_12;
00681 break;
00682
00683 default:
00684 break;
00685 }
00686
00687 _flt_header->add_texture(flt_texture);
00688 _texture_map[filename] = flt_texture;
00689
00690 return flt_texture;
00691 }
00692
00693
00694
00695 int main(int argc, char *argv[]) {
00696
00697 pystub();
00698
00699 EggToFlt prog;
00700 prog.parse_command_line(argc, argv);
00701 prog.run();
00702 return 0;
00703 }