00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "bamToEgg.h"
00020
00021 #include "pandaNode.h"
00022 #include "workingNodePath.h"
00023 #include "nodePath.h"
00024 #include "billboardEffect.h"
00025 #include "renderEffects.h"
00026 #include "transformState.h"
00027 #include "colorScaleAttrib.h"
00028 #include "colorAttrib.h"
00029 #include "textureAttrib.h"
00030 #include "cullFaceAttrib.h"
00031 #include "lodNode.h"
00032 #include "geomNode.h"
00033 #include "geom.h"
00034 #include "geomTri.h"
00035 #include "string_utils.h"
00036 #include "bamFile.h"
00037 #include "eggGroup.h"
00038 #include "eggVertexPool.h"
00039 #include "eggVertex.h"
00040 #include "eggPrimitive.h"
00041 #include "eggPolygon.h"
00042 #include "eggTexture.h"
00043 #include "eggMaterial.h"
00044 #include "somethingToEggConverter.h"
00045 #include "dcast.h"
00046
00047
00048
00049
00050
00051
00052
00053 BamToEgg::
00054 BamToEgg() :
00055 SomethingToEgg("Bam", ".bam")
00056 {
00057 add_path_replace_options();
00058 add_path_store_options();
00059
00060 set_program_description
00061 ("This program converts native Panda Bam files to egg. The conversion "
00062 "is somewhat incomplete; running egg2bam followed by bam2egg should not "
00063 " be expected to yield the same egg file you started with.");
00064
00065 redescribe_option
00066 ("cs",
00067 "Specify the coordinate system of the input " + _format_name +
00068 " file. By default, this is taken from the Configrc file, which "
00069 "is currently " + format_string(default_coordinate_system) + ".");
00070
00071 _coordinate_system = default_coordinate_system;
00072 }
00073
00074
00075
00076
00077
00078
00079 void BamToEgg::
00080 run() {
00081 BamFile bam_file;
00082
00083 if (!bam_file.open_read(_input_filename)) {
00084 nout << "Unable to read " << _input_filename << "\n";
00085 exit(1);
00086 }
00087
00088 nout << _input_filename << " : Bam version "
00089 << bam_file.get_file_major_ver() << "."
00090 << bam_file.get_file_minor_ver() << "\n";
00091
00092 typedef pvector<TypedWritable *> Objects;
00093 Objects objects;
00094 TypedWritable *object = bam_file.read_object();
00095 while (object != (TypedWritable *)NULL || !bam_file.is_eof()) {
00096 if (object != (TypedWritable *)NULL) {
00097 objects.push_back(object);
00098 }
00099 object = bam_file.read_object();
00100 }
00101 bam_file.resolve();
00102 bam_file.close();
00103
00104 _data.set_coordinate_system(_coordinate_system);
00105 _vpool = new EggVertexPool("vpool");
00106 _data.add_child(_vpool);
00107
00108 if (objects.size() == 1 &&
00109 objects[0]->is_of_type(PandaNode::get_class_type())) {
00110 PandaNode *node = DCAST(PandaNode, objects[0]);
00111 NodePath root(node);
00112 convert_node(WorkingNodePath(root), &_data, false);
00113
00114 } else {
00115 nout << "File does not contain a scene graph.\n";
00116 exit(1);
00117 }
00118
00119
00120 if (_vpool->empty()) {
00121 _data.remove_child(_vpool);
00122 }
00123
00124 write_egg_file();
00125 }
00126
00127
00128
00129
00130
00131
00132
00133
00134 void BamToEgg::
00135 convert_node(const WorkingNodePath &node_path, EggGroupNode *egg_parent,
00136 bool has_decal) {
00137 PandaNode *node = node_path.node();
00138 if (node->is_geom_node()) {
00139 convert_geom_node(DCAST(GeomNode, node), node_path, egg_parent, has_decal);
00140
00141 } else if (node->is_of_type(LODNode::get_class_type())) {
00142 convert_lod_node(DCAST(LODNode, node), node_path, egg_parent, has_decal);
00143
00144 } else {
00145
00146 EggGroup *egg_group = new EggGroup(node->get_name());
00147 egg_parent->add_child(egg_group);
00148 apply_node_properties(egg_group, node);
00149
00150 recurse_nodes(node_path, egg_group, has_decal);
00151 }
00152 }
00153
00154
00155
00156
00157
00158
00159
00160 void BamToEgg::
00161 convert_lod_node(LODNode *node, const WorkingNodePath &node_path,
00162 EggGroupNode *egg_parent, bool has_decal) {
00163
00164
00165 EggGroup *egg_group = new EggGroup(node->get_name());
00166 egg_parent->add_child(egg_group);
00167 apply_node_properties(egg_group, node);
00168
00169 int num_children = node->get_num_children();
00170 int num_switches = node->get_num_switches();
00171
00172 num_children = min(num_children, num_switches);
00173
00174 for (int i = 0; i < num_children; i++) {
00175 PandaNode *child = node->get_child(i);
00176
00177
00178 PT(EggGroup) next_group = new EggGroup;
00179 convert_node(WorkingNodePath(node_path, child), next_group, has_decal);
00180
00181 if (next_group->size() == 1) {
00182
00183
00184 EggNode *child_node = *next_group->begin();
00185 if (child_node->is_of_type(EggGroup::get_class_type())) {
00186 PT(EggGroup) child = DCAST(EggGroup, child_node);
00187 next_group->remove_child(child.p());
00188 next_group = child;
00189 }
00190 }
00191
00192
00193 float in = node->get_in(i);
00194 float out = node->get_out(i);
00195 LPoint3f center = node->get_center();
00196 EggSwitchConditionDistance dist(in, out, LCAST(double, center));
00197 next_group->set_lod(dist);
00198 egg_group->add_child(next_group.p());
00199 }
00200 }
00201
00202
00203
00204
00205
00206
00207
00208 void BamToEgg::
00209 convert_geom_node(GeomNode *node, const WorkingNodePath &node_path,
00210 EggGroupNode *egg_parent, bool has_decal) {
00211 PT(EggGroup) egg_group = new EggGroup(node->get_name());
00212 bool fancy_attributes = apply_node_properties(egg_group, node);
00213
00214 if (node->get_effects()->has_decal()) {
00215 has_decal = true;
00216 }
00217
00218 if (has_decal) {
00219 egg_group->set_decal_flag(true);
00220 }
00221
00222 if (fancy_attributes || has_decal) {
00223
00224
00225
00226 egg_parent->add_child(egg_group.p());
00227 egg_parent = egg_group;
00228 }
00229
00230 NodePath np = node_path.get_node_path();
00231 CPT(RenderState) net_state = np.get_net_state();
00232 CPT(TransformState) net_transform = np.get_net_transform();
00233 LMatrix4f net_mat = net_transform->get_mat();
00234 LMatrix4f inv = LCAST(float, egg_parent->get_vertex_frame_inv());
00235 net_mat = net_mat * inv;
00236
00237
00238 int num_geoms = node->get_num_geoms();
00239 for (int i = 0; i < num_geoms; i++) {
00240 CPT(RenderState) geom_state = net_state->compose(node->get_geom_state(i));
00241
00242 Geom *geom = node->get_geom(i);
00243
00244
00245 PT(Geom) exploded = geom->explode();
00246
00247
00248
00249 if (exploded->is_of_type(GeomTri::get_class_type())) {
00250 convert_geom_tri(DCAST(GeomTri, exploded), geom_state, net_mat,
00251 egg_parent);
00252 }
00253 }
00254
00255 recurse_nodes(node_path, egg_parent, has_decal);
00256 }
00257
00258
00259
00260
00261
00262
00263 void BamToEgg::
00264 convert_geom_tri(GeomTri *geom, const RenderState *net_state,
00265 const LMatrix4f &net_mat, EggGroupNode *egg_parent) {
00266 int nprims = geom->get_num_prims();
00267 Geom::VertexIterator vi = geom->make_vertex_iterator();
00268 Geom::NormalIterator ni = geom->make_normal_iterator();
00269 Geom::TexCoordIterator ti = geom->make_texcoord_iterator();
00270 Geom::ColorIterator ci = geom->make_color_iterator();
00271
00272 GeomBindType vb = geom->get_binding(G_COORD);
00273 GeomBindType nb = geom->get_binding(G_NORMAL);
00274 GeomBindType tb = geom->get_binding(G_TEXCOORD);
00275 GeomBindType cb = geom->get_binding(G_COLOR);
00276
00277
00278 LVecBase4f color_scale(1.0f, 1.0f, 1.0f, 1.0f);
00279 const RenderAttrib *color_scale_attrib = net_state->get_attrib(ColorScaleAttrib::get_class_type());
00280 if (color_scale_attrib != (const RenderAttrib *)NULL) {
00281 const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, color_scale_attrib);
00282 color_scale = csa->get_scale();
00283 }
00284
00285
00286 bool has_color_override = false;
00287 bool has_color_off = false;
00288 Colorf color_override;
00289 const RenderAttrib *color_attrib = net_state->get_attrib(ColorAttrib::get_class_type());
00290 if (color_attrib != (const RenderAttrib *)NULL) {
00291 const ColorAttrib *ca = DCAST(ColorAttrib, color_attrib);
00292 if (ca->get_color_type() == ColorAttrib::T_flat) {
00293 has_color_override = true;
00294 color_override = ca->get_color();
00295 color_override.set(color_override[0] * color_scale[0],
00296 color_override[1] * color_scale[1],
00297 color_override[2] * color_scale[2],
00298 color_override[3] * color_scale[3]);
00299
00300 } else if (ca->get_color_type() == ColorAttrib::T_off) {
00301 has_color_off = true;
00302 }
00303 }
00304
00305
00306 EggTexture *egg_tex = (EggTexture *)NULL;
00307 const RenderAttrib *tex_attrib = net_state->get_attrib(TextureAttrib::get_class_type());
00308 if (tex_attrib != (const RenderAttrib *)NULL) {
00309 const TextureAttrib *ta = DCAST(TextureAttrib, tex_attrib);
00310 egg_tex = get_egg_texture(ta->get_texture());
00311 }
00312
00313
00314 bool bface = false;
00315 const RenderAttrib *cf_attrib = net_state->get_attrib(CullFaceAttrib::get_class_type());
00316 if (cf_attrib != (const RenderAttrib *)NULL) {
00317 const CullFaceAttrib *cfa = DCAST(CullFaceAttrib, cf_attrib);
00318 if (cfa->get_effective_mode() == CullFaceAttrib::M_cull_none) {
00319 bface = true;
00320 }
00321 }
00322
00323 Normalf normal;
00324 Colorf color;
00325
00326
00327 if (nb == G_OVERALL) {
00328 normal = geom->get_next_normal(ni);
00329 }
00330 if (cb == G_OVERALL) {
00331 color = geom->get_next_color(ci);
00332 }
00333
00334 for (int i = 0; i < nprims; i++) {
00335
00336 if (nb == G_PER_PRIM) {
00337 normal = geom->get_next_normal(ni);
00338 }
00339 if (cb == G_PER_PRIM) {
00340 color = geom->get_next_color(ci);
00341 }
00342
00343 EggPolygon *egg_poly = new EggPolygon;
00344 egg_parent->add_child(egg_poly);
00345 if (egg_tex != (EggTexture *)NULL) {
00346 egg_poly->set_texture(egg_tex);
00347 }
00348
00349 if (bface) {
00350 egg_poly->set_bface_flag(true);
00351 }
00352
00353 for (int j = 0; j < 3; j++) {
00354 EggVertex egg_vert;
00355
00356
00357 if (vb == G_PER_VERTEX) {
00358 Vertexf vertex = geom->get_next_vertex(vi);
00359 egg_vert.set_pos(LCAST(double, vertex * net_mat));
00360 }
00361 if (nb == G_PER_VERTEX) {
00362 normal = geom->get_next_normal(ni) * net_mat;
00363 }
00364 if (tb == G_PER_VERTEX) {
00365 TexCoordf uv = geom->get_next_texcoord(ti);
00366 egg_vert.set_uv(LCAST(double, uv));
00367 }
00368 if (cb == G_PER_VERTEX) {
00369 color = geom->get_next_color(ci);
00370 }
00371
00372 if (nb != G_OFF) {
00373 egg_vert.set_normal(LCAST(double, normal * net_mat));
00374 }
00375
00376 if (has_color_override) {
00377 egg_vert.set_color(color_override);
00378
00379 } else if (!has_color_off && cb != G_OFF) {
00380 egg_vert.set_color(Colorf(color[0] * color_scale[0],
00381 color[1] * color_scale[1],
00382 color[2] * color_scale[2],
00383 color[3] * color_scale[3]));
00384 }
00385
00386 EggVertex *new_egg_vert = _vpool->create_unique_vertex(egg_vert);
00387 egg_poly->add_vertex(new_egg_vert);
00388 }
00389 }
00390 }
00391
00392
00393
00394
00395
00396
00397 void BamToEgg::
00398 recurse_nodes(const WorkingNodePath &node_path, EggGroupNode *egg_parent,
00399 bool has_decal) {
00400 PandaNode *node = node_path.node();
00401 int num_children = node->get_num_children();
00402
00403 for (int i = 0; i < num_children; i++) {
00404 PandaNode *child = node->get_child(i);
00405 convert_node(WorkingNodePath(node_path, child), egg_parent, has_decal);
00406 }
00407 }
00408
00409
00410
00411
00412
00413
00414
00415
00416 bool BamToEgg::
00417 apply_node_properties(EggGroup *egg_group, PandaNode *node) {
00418 bool any_applied = false;
00419
00420 if (node->get_draw_mask().is_zero()) {
00421
00422
00423 egg_group->add_object_type("backstage");
00424 }
00425
00426 const RenderEffects *effects = node->get_effects();
00427 const BillboardEffect *bbe = effects->get_billboard();
00428 if (bbe != (const BillboardEffect *)NULL) {
00429 if (bbe->get_axial_rotate()) {
00430 egg_group->set_billboard_type(EggGroup::BT_axis);
00431 any_applied = true;
00432
00433 } else if (bbe->get_eye_relative()) {
00434 egg_group->set_billboard_type(EggGroup::BT_point_camera_relative);
00435 any_applied = true;
00436
00437 } else {
00438 egg_group->set_billboard_type(EggGroup::BT_point_world_relative);
00439 any_applied = true;
00440 }
00441 }
00442
00443 const TransformState *transform = node->get_transform();
00444 if (!transform->is_identity()) {
00445 if (transform->has_components()) {
00446
00447
00448 const LVecBase3f &scale = transform->get_scale();
00449 const LQuaternionf &quat = transform->get_quat();
00450 const LVecBase3f &pos = transform->get_pos();
00451 if (!scale.almost_equal(LVecBase3f(1.0f, 1.0f, 1.0f))) {
00452 egg_group->add_scale(LCAST(double, scale));
00453 }
00454 if (!quat.is_identity()) {
00455 egg_group->add_rotate(LCAST(double, quat));
00456 }
00457 if (!pos.almost_equal(LVecBase3f::zero())) {
00458 egg_group->add_translate(LCAST(double, pos));
00459 }
00460
00461 } else if (transform->has_mat()) {
00462
00463 const LMatrix4f &mat = transform->get_mat();
00464 egg_group->set_transform(LCAST(double, mat));
00465 }
00466 any_applied = true;
00467 }
00468
00469 return any_applied;
00470 }
00471
00472
00473
00474
00475
00476
00477
00478 EggTexture *BamToEgg::
00479 get_egg_texture(Texture *tex) {
00480 if (tex != (Texture *)NULL) {
00481 if (tex->has_filename()) {
00482 Filename filename = _path_replace->convert_path(tex->get_filename());
00483 EggTexture temp(filename.get_basename_wo_extension(), filename);
00484 if (tex->has_alpha_filename()) {
00485 Filename alpha = _path_replace->convert_path(tex->get_alpha_filename());
00486 temp.set_alpha_filename(alpha);
00487 }
00488
00489 switch (tex->get_minfilter()) {
00490 case Texture::FT_invalid:
00491 break;
00492 case Texture::FT_nearest:
00493 temp.set_minfilter(EggTexture::FT_nearest);
00494 break;
00495 case Texture::FT_linear:
00496 temp.set_minfilter(EggTexture::FT_linear);
00497 break;
00498 case Texture::FT_nearest_mipmap_nearest:
00499 temp.set_minfilter(EggTexture::FT_nearest_mipmap_nearest);
00500 break;
00501 case Texture::FT_linear_mipmap_nearest:
00502 temp.set_minfilter(EggTexture::FT_linear_mipmap_nearest);
00503 break;
00504 case Texture::FT_nearest_mipmap_linear:
00505 temp.set_minfilter(EggTexture::FT_nearest_mipmap_linear);
00506 break;
00507 case Texture::FT_linear_mipmap_linear:
00508 temp.set_minfilter(EggTexture::FT_linear_mipmap_linear);
00509 break;
00510 }
00511
00512 switch (tex->get_magfilter()) {
00513 case Texture::FT_nearest:
00514 temp.set_magfilter(EggTexture::FT_nearest);
00515 break;
00516 case Texture::FT_linear:
00517 temp.set_magfilter(EggTexture::FT_linear);
00518 break;
00519 default:
00520 break;
00521 }
00522
00523 switch (tex->get_wrapu()) {
00524 case Texture::WM_clamp:
00525 temp.set_wrap_u(EggTexture::WM_clamp);
00526 break;
00527 case Texture::WM_repeat:
00528 temp.set_wrap_u(EggTexture::WM_repeat);
00529 break;
00530
00531 default:
00532
00533
00534 break;
00535 }
00536
00537 switch (tex->get_wrapv()) {
00538 case Texture::WM_clamp:
00539 temp.set_wrap_v(EggTexture::WM_clamp);
00540 break;
00541 case Texture::WM_repeat:
00542 temp.set_wrap_v(EggTexture::WM_repeat);
00543 break;
00544
00545 default:
00546
00547
00548 break;
00549 }
00550
00551 PixelBuffer *pbuf = tex->get_ram_image();
00552 if (pbuf != (PixelBuffer *)NULL) {
00553 switch (pbuf->get_format()) {
00554 case PixelBuffer::F_red:
00555 temp.set_format(EggTexture::F_red);
00556 break;
00557 case PixelBuffer::F_green:
00558 temp.set_format(EggTexture::F_green);
00559 break;
00560 case PixelBuffer::F_blue:
00561 temp.set_format(EggTexture::F_blue);
00562 break;
00563 case PixelBuffer::F_alpha:
00564 temp.set_format(EggTexture::F_alpha);
00565 break;
00566 case PixelBuffer::F_rgb:
00567 temp.set_format(EggTexture::F_rgb);
00568 break;
00569 case PixelBuffer::F_rgb5:
00570 temp.set_format(EggTexture::F_rgb5);
00571 break;
00572 case PixelBuffer::F_rgb8:
00573 temp.set_format(EggTexture::F_rgb8);
00574 break;
00575 case PixelBuffer::F_rgb12:
00576 temp.set_format(EggTexture::F_rgb12);
00577 break;
00578 case PixelBuffer::F_rgb332:
00579 temp.set_format(EggTexture::F_rgb332);
00580 break;
00581 case PixelBuffer::F_rgba:
00582 temp.set_format(EggTexture::F_rgba);
00583 break;
00584 case PixelBuffer::F_rgbm:
00585 temp.set_format(EggTexture::F_rgbm);
00586 break;
00587 case PixelBuffer::F_rgba4:
00588 temp.set_format(EggTexture::F_rgba4);
00589 break;
00590 case PixelBuffer::F_rgba5:
00591 temp.set_format(EggTexture::F_rgba5);
00592 break;
00593 case PixelBuffer::F_rgba8:
00594 temp.set_format(EggTexture::F_rgba8);
00595 break;
00596 case PixelBuffer::F_rgba12:
00597 temp.set_format(EggTexture::F_rgba12);
00598 break;
00599 case PixelBuffer::F_luminance:
00600 temp.set_format(EggTexture::F_luminance);
00601 break;
00602 case PixelBuffer::F_luminance_alpha:
00603 temp.set_format(EggTexture::F_luminance_alpha);
00604 break;
00605 case PixelBuffer::F_luminance_alphamask:
00606 temp.set_format(EggTexture::F_luminance_alphamask);
00607 break;
00608 default:
00609 break;
00610 }
00611 }
00612
00613 return _textures.create_unique_texture(temp, ~EggTexture::E_tref_name);
00614 }
00615 }
00616
00617 return NULL;
00618 }
00619
00620
00621 int main(int argc, char *argv[]) {
00622 BamToEgg prog;
00623 prog.parse_command_line(argc, argv);
00624 prog.run();
00625 return 0;
00626 }