00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "pandabase.h"
00020
00021 #include "eggLoader.h"
00022 #include "config_egg2pg.h"
00023 #include "nodePath.h"
00024 #include "renderState.h"
00025 #include "transformState.h"
00026 #include "textureAttrib.h"
00027 #include "textureApplyAttrib.h"
00028 #include "texturePool.h"
00029 #include "billboardEffect.h"
00030 #include "cullFaceAttrib.h"
00031 #include "cullBinAttrib.h"
00032 #include "transparencyAttrib.h"
00033 #include "decalEffect.h"
00034 #include "depthTestAttrib.h"
00035 #include "depthWriteAttrib.h"
00036 #include "materialAttrib.h"
00037 #include "materialPool.h"
00038 #include "geomNode.h"
00039 #include "sequenceNode.h"
00040 #include "switchNode.h"
00041 #include "lodNode.h"
00042 #include "modelNode.h"
00043 #include "modelRoot.h"
00044 #include "string_utils.h"
00045 #include "eggPrimitive.h"
00046 #include "eggPoint.h"
00047 #include "eggTextureCollection.h"
00048 #include "eggNurbsCurve.h"
00049 #include "eggGroupNode.h"
00050 #include "eggGroup.h"
00051 #include "eggPolygon.h"
00052 #include "eggBin.h"
00053 #include "eggTable.h"
00054 #include "eggBinner.h"
00055 #include "eggVertexPool.h"
00056 #include "characterMaker.h"
00057 #include "character.h"
00058 #include "animBundleMaker.h"
00059 #include "animBundleNode.h"
00060 #include "selectiveChildNode.h"
00061 #include "collisionNode.h"
00062 #include "collisionSphere.h"
00063 #include "collisionPlane.h"
00064 #include "collisionPolygon.h"
00065 #include "parametricCurve.h"
00066 #include "nurbsCurve.h"
00067 #include "classicNurbsCurve.h"
00068 #include "nurbsCurveInterface.h"
00069
00070 #include <ctype.h>
00071 #include <algorithm>
00072
00073
00074
00075 class LODInstance {
00076 public:
00077 LODInstance(EggNode *egg_node);
00078 bool operator < (const LODInstance &other) const {
00079 return _d->_switch_in < other._d->_switch_in;
00080 }
00081
00082 EggNode *_egg_node;
00083 const EggSwitchConditionDistance *_d;
00084 };
00085
00086 LODInstance::
00087 LODInstance(EggNode *egg_node) {
00088 nassertv(egg_node != NULL);
00089 _egg_node = egg_node;
00090
00091
00092
00093
00094 EggGroup *egg_group = DCAST(EggGroup, egg_node);
00095 nassertv(egg_group->has_lod());
00096 const EggSwitchCondition &sw = egg_group->get_lod();
00097
00098
00099 _d = DCAST(EggSwitchConditionDistance, &sw);
00100 }
00101
00102
00103
00104
00105
00106
00107
00108 EggLoader::
00109 EggLoader() {
00110
00111 _data.set_coordinate_system(egg_coordinate_system);
00112 _error = false;
00113 }
00114
00115
00116
00117
00118
00119
00120 EggLoader::
00121 EggLoader(const EggData &data) :
00122 _data(data)
00123 {
00124 _error = false;
00125 }
00126
00127
00128
00129
00130
00131
00132
00133 void EggLoader::
00134 build_graph() {
00135 _deferred_nodes.clear();
00136
00137
00138 EggBinner binner;
00139 binner.make_bins(&_data);
00140
00141
00142 load_textures();
00143
00144
00145 _root = new ModelRoot(_data.get_egg_filename().get_basename());
00146 make_node(&_data, _root);
00147 _builder.build();
00148
00149 reparent_decals();
00150
00151 apply_deferred_nodes(_root, DeferredNodeProperty());
00152 }
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163 void EggLoader::
00164 reparent_decals() {
00165 Decals::const_iterator di;
00166 for (di = _decals.begin(); di != _decals.end(); ++di) {
00167 PandaNode *node = (*di);
00168 nassertv(node != (PandaNode *)NULL);
00169
00170
00171 NodePath parent(node);
00172
00173
00174 NodePath geom_parent;
00175 int num_children = parent.get_num_children();
00176 for (int i = 0; i < num_children; i++) {
00177 NodePath child = parent.get_child(i);
00178
00179 if (child.node()->is_of_type(GeomNode::get_class_type())) {
00180 if (!geom_parent.is_empty()) {
00181
00182 egg2pg_cat.error()
00183 << "Decal onto " << parent.node()->get_name()
00184 << " uses base geometry with multiple GeomNodes.\n";
00185 _error = true;
00186 }
00187 geom_parent = child;
00188 }
00189 }
00190
00191 if (geom_parent.is_empty()) {
00192
00193 egg2pg_cat.error()
00194 << "Ignoring decal onto " << parent.node()->get_name()
00195 << "; no geometry within group.\n";
00196 _error = true;
00197 } else {
00198
00199
00200
00201 int i = 0;
00202 while (i < num_children) {
00203 NodePath child = parent.get_child(i);
00204
00205 if (child.node()->is_of_type(GeomNode::get_class_type())) {
00206 i++;
00207 } else {
00208 child.reparent_to(geom_parent);
00209 num_children--;
00210 }
00211 }
00212
00213
00214 geom_parent.node()->set_effect(DecalEffect::make());
00215 }
00216 }
00217 }
00218
00219
00220
00221
00222
00223
00224
00225 void EggLoader::
00226 make_nonindexed_primitive(EggPrimitive *egg_prim, PandaNode *parent,
00227 const LMatrix4d *transform) {
00228 BuilderBucket bucket;
00229 setup_bucket(bucket, parent, egg_prim);
00230
00231 LMatrix4d mat;
00232
00233 if (transform != NULL) {
00234 mat = (*transform);
00235 } else {
00236 mat = egg_prim->get_vertex_to_node();
00237 }
00238
00239 BuilderPrim bprim;
00240 bprim.set_type(BPT_poly);
00241 if (egg_prim->is_of_type(EggPoint::get_class_type())) {
00242 bprim.set_type(BPT_point);
00243 }
00244
00245 if (egg_prim->has_normal()) {
00246 Normald norm = egg_prim->get_normal() * mat;
00247 norm.normalize();
00248 bprim.set_normal(LCAST(float, norm));
00249 }
00250 if (egg_prim->has_color() && !egg_false_color) {
00251 bprim.set_color(egg_prim->get_color());
00252 }
00253
00254 bool has_vert_color = true;
00255 EggPrimitive::const_iterator vi;
00256 for (vi = egg_prim->begin(); vi != egg_prim->end(); ++vi) {
00257 EggVertex *egg_vert = *vi;
00258 if (egg_vert->get_num_dimensions() != 3) {
00259 egg2pg_cat.error()
00260 << "Vertex " << egg_vert->get_pool()->get_name()
00261 << ":" << egg_vert->get_index() << " has dimension "
00262 << egg_vert->get_num_dimensions() << "\n";
00263 } else {
00264 BuilderVertex bvert(LCAST(float, egg_vert->get_pos3() * mat));
00265
00266 if (egg_vert->has_normal()) {
00267 Normald norm = egg_vert->get_normal() * mat;
00268 norm.normalize();
00269 bvert.set_normal(LCAST(float, norm));
00270 }
00271 if (egg_vert->has_color() && !egg_false_color) {
00272 bvert.set_color(egg_vert->get_color());
00273 } else {
00274
00275
00276 has_vert_color = false;
00277 }
00278 if (egg_vert->has_uv()) {
00279 TexCoordd uv = egg_vert->get_uv();
00280 if (egg_prim->has_texture() &&
00281 egg_prim->get_texture()->has_transform()) {
00282
00283 uv = uv * egg_prim->get_texture()->get_transform();
00284 }
00285 bvert.set_texcoord(LCAST(float, uv));
00286 }
00287
00288 bprim.add_vertex(bvert);
00289 }
00290 }
00291
00292
00293
00294 if (!egg_prim->has_color() && !has_vert_color && !egg_false_color) {
00295 bprim.set_color(Colorf(1.0, 1.0, 1.0, 1.0));
00296 }
00297
00298 _builder.add_prim(bucket, bprim);
00299 }
00300
00301
00302
00303
00304
00305
00306 void EggLoader::
00307 make_indexed_primitive(EggPrimitive *egg_prim, PandaNode *parent,
00308 const LMatrix4d *transform,
00309 ComputedVerticesMaker &_comp_verts_maker) {
00310 BuilderBucket bucket;
00311 setup_bucket(bucket, parent, egg_prim);
00312
00313 bucket.set_coords(_comp_verts_maker._coords);
00314 bucket.set_normals(_comp_verts_maker._norms);
00315 bucket.set_texcoords(_comp_verts_maker._texcoords);
00316 bucket.set_colors(_comp_verts_maker._colors);
00317
00318 LMatrix4d mat;
00319
00320 if (transform != NULL) {
00321 mat = (*transform);
00322 } else {
00323 mat = egg_prim->get_vertex_to_node();
00324 }
00325
00326 BuilderPrimI bprim;
00327 bprim.set_type(BPT_poly);
00328 if (egg_prim->is_of_type(EggPoint::get_class_type())) {
00329 bprim.set_type(BPT_point);
00330 }
00331
00332 if (egg_prim->has_normal()) {
00333
00334
00335 _comp_verts_maker.begin_new_space();
00336 EggPrimitive::const_iterator vi;
00337 for (vi = egg_prim->begin(); vi != egg_prim->end(); ++vi) {
00338 EggVertex *egg_vert = *vi;
00339 _comp_verts_maker.add_vertex_joints(egg_vert, egg_prim);
00340 }
00341 _comp_verts_maker.mark_space();
00342
00343 int nindex =
00344 _comp_verts_maker.add_normal(egg_prim->get_normal(),
00345 egg_prim->_dnormals, mat);
00346
00347 bprim.set_normal(nindex);
00348 }
00349
00350 if (egg_prim->has_color() && !egg_false_color) {
00351 int cindex =
00352 _comp_verts_maker.add_color(egg_prim->get_color(),
00353 egg_prim->_drgbas);
00354 bprim.set_color(cindex);
00355 }
00356
00357 bool has_vert_color = true;
00358 EggPrimitive::const_iterator vi;
00359 for (vi = egg_prim->begin(); vi != egg_prim->end(); ++vi) {
00360 EggVertex *egg_vert = *vi;
00361
00362 if (egg_vert->get_num_dimensions() != 3) {
00363 egg2pg_cat.error()
00364 << "Vertex " << egg_vert->get_pool()->get_name()
00365 << ":" << egg_vert->get_index() << " has dimension "
00366 << egg_vert->get_num_dimensions() << "\n";
00367 } else {
00368
00369
00370 _comp_verts_maker.begin_new_space();
00371 _comp_verts_maker.add_vertex_joints(egg_vert, egg_prim);
00372 _comp_verts_maker.mark_space();
00373
00374 int vindex =
00375 _comp_verts_maker.add_vertex(egg_vert->get_pos3(),
00376 egg_vert->_dxyzs, mat);
00377 BuilderVertexI bvert(vindex);
00378
00379 if (egg_vert->has_normal()) {
00380 int nindex =
00381 _comp_verts_maker.add_normal(egg_vert->get_normal(),
00382 egg_vert->_dnormals,
00383 mat);
00384 bvert.set_normal(nindex);
00385 }
00386
00387 if (egg_vert->has_color() && !egg_false_color) {
00388 int cindex =
00389 _comp_verts_maker.add_color(egg_vert->get_color(),
00390 egg_vert->_drgbas);
00391 bvert.set_color(cindex);
00392 } else {
00393
00394
00395 has_vert_color = false;
00396 }
00397
00398 if (egg_vert->has_uv()) {
00399 TexCoordd uv = egg_vert->get_uv();
00400 LMatrix3d mat;
00401
00402 if (egg_prim->has_texture() &&
00403 egg_prim->get_texture()->has_transform()) {
00404
00405 mat = egg_prim->get_texture()->get_transform();
00406 } else {
00407 mat = LMatrix3d::ident_mat();
00408 }
00409
00410 int tindex =
00411 _comp_verts_maker.add_texcoord(uv, egg_vert->_duvs, mat);
00412 bvert.set_texcoord(tindex);
00413 }
00414
00415 bprim.add_vertex(bvert);
00416 }
00417 }
00418
00419
00420
00421 if (!egg_prim->has_color() && !has_vert_color && !egg_false_color) {
00422 int cindex =
00423 _comp_verts_maker.add_color(Colorf(1.0, 1.0, 1.0, 1.0),
00424 EggMorphColorList());
00425 bprim.set_color(cindex);
00426 }
00427
00428 _builder.add_prim(bucket, bprim);
00429 }
00430
00431
00432
00433
00434
00435
00436 void EggLoader::
00437 load_textures() {
00438
00439 EggTextureCollection tc;
00440 tc.find_used_textures(&_data);
00441
00442
00443
00444 EggTextureCollection::TextureReplacement replace;
00445 tc.collapse_equivalent_textures(EggTexture::E_complete_filename,
00446 replace);
00447
00448 EggTextureCollection::iterator ti;
00449 for (ti = tc.begin(); ti != tc.end(); ++ti) {
00450 PT(EggTexture) egg_tex = (*ti);
00451
00452 TextureDef def;
00453 if (load_texture(def, egg_tex)) {
00454
00455
00456 _textures[egg_tex] = def;
00457 }
00458 }
00459
00460
00461
00462 EggTextureCollection::TextureReplacement::const_iterator ri;
00463 for (ri = replace.begin(); ri != replace.end(); ++ri) {
00464 PT(EggTexture) orig = (*ri).first;
00465 PT(EggTexture) repl = (*ri).second;
00466
00467 _textures[orig] = _textures[repl];
00468 }
00469 }
00470
00471
00472
00473
00474
00475
00476
00477 bool EggLoader::
00478 load_texture(TextureDef &def, const EggTexture *egg_tex) {
00479
00480
00481 int wanted_channels = 0;
00482 bool wanted_alpha = false;
00483 switch (egg_tex->get_format()) {
00484 case EggTexture::F_red:
00485 case EggTexture::F_green:
00486 case EggTexture::F_blue:
00487 case EggTexture::F_alpha:
00488 case EggTexture::F_luminance:
00489 wanted_channels = 1;
00490 wanted_alpha = false;
00491 break;
00492
00493 case EggTexture::F_luminance_alpha:
00494 case EggTexture::F_luminance_alphamask:
00495 wanted_channels = 2;
00496 wanted_alpha = true;
00497 break;
00498
00499 case EggTexture::F_rgb:
00500 case EggTexture::F_rgb12:
00501 case EggTexture::F_rgb8:
00502 case EggTexture::F_rgb5:
00503 case EggTexture::F_rgb332:
00504 wanted_channels = 3;
00505 wanted_alpha = false;
00506 break;
00507
00508 case EggTexture::F_rgba:
00509 case EggTexture::F_rgbm:
00510 case EggTexture::F_rgba12:
00511 case EggTexture::F_rgba8:
00512 case EggTexture::F_rgba4:
00513 case EggTexture::F_rgba5:
00514 wanted_channels = 4;
00515 wanted_alpha = true;
00516 break;
00517
00518 case EggTexture::F_unspecified:
00519 break;
00520 }
00521
00522 Texture *tex;
00523 if (egg_tex->has_alpha_filename() && wanted_alpha) {
00524 tex = TexturePool::load_texture(egg_tex->get_fullpath(),
00525 egg_tex->get_alpha_fullpath(),
00526 wanted_channels,
00527 egg_tex->get_alpha_file_channel());
00528 } else {
00529 tex = TexturePool::load_texture(egg_tex->get_fullpath(),
00530 wanted_channels);
00531 }
00532 if (tex == (Texture *)NULL) {
00533 return false;
00534 }
00535
00536
00537
00538
00539 tex->set_filename(egg_tex->get_filename());
00540 if (egg_tex->has_alpha_filename() && wanted_alpha) {
00541 tex->set_alpha_filename(egg_tex->get_alpha_filename());
00542 }
00543
00544 apply_texture_attributes(tex, egg_tex);
00545 CPT(RenderAttrib) apply = get_texture_apply_attributes(egg_tex);
00546
00547 def._texture = TextureAttrib::make(tex);
00548 def._apply = apply;
00549
00550 return true;
00551 }
00552
00553
00554
00555
00556
00557
00558
00559 void EggLoader::
00560 apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) {
00561 switch (egg_tex->determine_wrap_u()) {
00562 case EggTexture::WM_repeat:
00563 tex->set_wrapu(Texture::WM_repeat);
00564 break;
00565
00566 case EggTexture::WM_clamp:
00567 if (egg_ignore_clamp) {
00568 egg2pg_cat.warning()
00569 << "Ignoring clamp request\n";
00570 tex->set_wrapu(Texture::WM_repeat);
00571 } else {
00572 tex->set_wrapu(Texture::WM_clamp);
00573 }
00574 break;
00575
00576 case EggTexture::WM_unspecified:
00577 break;
00578
00579 default:
00580 egg2pg_cat.warning()
00581 << "Unexpected texture wrap flag: "
00582 << (int)egg_tex->determine_wrap_u() << "\n";
00583 }
00584
00585 switch (egg_tex->determine_wrap_v()) {
00586 case EggTexture::WM_repeat:
00587 tex->set_wrapv(Texture::WM_repeat);
00588 break;
00589
00590 case EggTexture::WM_clamp:
00591 if (egg_ignore_clamp) {
00592 egg2pg_cat.warning()
00593 << "Ignoring clamp request\n";
00594 tex->set_wrapv(Texture::WM_repeat);
00595 } else {
00596 tex->set_wrapv(Texture::WM_clamp);
00597 }
00598 break;
00599
00600 case EggTexture::WM_unspecified:
00601 break;
00602
00603 default:
00604 egg2pg_cat.warning()
00605 << "Unexpected texture wrap flag: "
00606 << (int)egg_tex->determine_wrap_v() << "\n";
00607 }
00608
00609 switch (egg_tex->get_minfilter()) {
00610 case EggTexture::FT_nearest:
00611 tex->set_minfilter(Texture::FT_nearest);
00612 break;
00613
00614 case EggTexture::FT_linear:
00615 if (egg_ignore_filters) {
00616 egg2pg_cat.warning()
00617 << "Ignoring minfilter request\n";
00618 tex->set_minfilter(Texture::FT_nearest);
00619 } else {
00620 tex->set_minfilter(Texture::FT_linear);
00621 }
00622 break;
00623
00624 case EggTexture::FT_nearest_mipmap_nearest:
00625 if (egg_ignore_filters) {
00626 egg2pg_cat.warning()
00627 << "Ignoring minfilter request\n";
00628 tex->set_minfilter(Texture::FT_nearest);
00629 } else if (egg_ignore_mipmaps) {
00630 egg2pg_cat.warning()
00631 << "Ignoring mipmap request\n";
00632 tex->set_minfilter(Texture::FT_nearest);
00633 } else {
00634 tex->set_minfilter(Texture::FT_nearest_mipmap_nearest);
00635 }
00636 break;
00637
00638 case EggTexture::FT_linear_mipmap_nearest:
00639 if (egg_ignore_filters) {
00640 egg2pg_cat.warning()
00641 << "Ignoring minfilter request\n";
00642 tex->set_minfilter(Texture::FT_nearest);
00643 } else if (egg_ignore_mipmaps) {
00644 egg2pg_cat.warning()
00645 << "Ignoring mipmap request\n";
00646 tex->set_minfilter(Texture::FT_linear);
00647 } else {
00648 tex->set_minfilter(Texture::FT_linear_mipmap_nearest);
00649 }
00650 break;
00651
00652 case EggTexture::FT_nearest_mipmap_linear:
00653 if (egg_ignore_filters) {
00654 egg2pg_cat.warning()
00655 << "Ignoring minfilter request\n";
00656 tex->set_minfilter(Texture::FT_nearest);
00657 } else if (egg_ignore_mipmaps) {
00658 egg2pg_cat.warning()
00659 << "Ignoring mipmap request\n";
00660 tex->set_minfilter(Texture::FT_nearest);
00661 } else {
00662 tex->set_minfilter(Texture::FT_nearest_mipmap_linear);
00663 }
00664 break;
00665
00666 case EggTexture::FT_linear_mipmap_linear:
00667 if (egg_ignore_filters) {
00668 egg2pg_cat.warning()
00669 << "Ignoring minfilter request\n";
00670 tex->set_minfilter(Texture::FT_nearest);
00671 } else if (egg_ignore_mipmaps) {
00672 egg2pg_cat.warning()
00673 << "Ignoring mipmap request\n";
00674 tex->set_minfilter(Texture::FT_linear);
00675 } else {
00676 tex->set_minfilter(Texture::FT_linear_mipmap_linear);
00677 }
00678 break;
00679
00680 case EggTexture::FT_unspecified:
00681
00682 if (egg_ignore_filters) {
00683 tex->set_minfilter(Texture::FT_nearest);
00684 } else {
00685 tex->set_minfilter(Texture::FT_linear);
00686 }
00687 }
00688
00689 switch (egg_tex->get_magfilter()) {
00690 case EggTexture::FT_nearest:
00691 case EggTexture::FT_nearest_mipmap_nearest:
00692 case EggTexture::FT_nearest_mipmap_linear:
00693 tex->set_magfilter(Texture::FT_nearest);
00694 break;
00695
00696 case EggTexture::FT_linear:
00697 case EggTexture::FT_linear_mipmap_nearest:
00698 case EggTexture::FT_linear_mipmap_linear:
00699 if (egg_ignore_filters) {
00700 egg2pg_cat.warning()
00701 << "Ignoring magfilter request\n";
00702 tex->set_magfilter(Texture::FT_nearest);
00703 } else {
00704 tex->set_magfilter(Texture::FT_linear);
00705 }
00706 break;
00707
00708 case EggTexture::FT_unspecified:
00709
00710 if (egg_ignore_filters) {
00711 tex->set_magfilter(Texture::FT_nearest);
00712 } else {
00713 tex->set_magfilter(Texture::FT_linear);
00714 }
00715 }
00716
00717 if (egg_tex->has_anisotropic_degree()) {
00718 tex->set_anisotropic_degree(egg_tex->get_anisotropic_degree());
00719 }
00720
00721 if (tex->_pbuffer->get_num_components() == 1) {
00722 switch (egg_tex->get_format()) {
00723 case EggTexture::F_red:
00724 tex->_pbuffer->set_format(PixelBuffer::F_red);
00725 break;
00726 case EggTexture::F_green:
00727 tex->_pbuffer->set_format(PixelBuffer::F_green);
00728 break;
00729 case EggTexture::F_blue:
00730 tex->_pbuffer->set_format(PixelBuffer::F_blue);
00731 break;
00732 case EggTexture::F_alpha:
00733 tex->_pbuffer->set_format(PixelBuffer::F_alpha);
00734 break;
00735 case EggTexture::F_luminance:
00736 tex->_pbuffer->set_format(PixelBuffer::F_luminance);
00737 break;
00738
00739 case EggTexture::F_unspecified:
00740 break;
00741
00742 default:
00743 egg2pg_cat.warning()
00744 << "Ignoring inappropriate format " << egg_tex->get_format()
00745 << " for 1-component texture " << egg_tex->get_name() << "\n";
00746 }
00747
00748 } else if (tex->_pbuffer->get_num_components() == 2) {
00749 switch (egg_tex->get_format()) {
00750 case EggTexture::F_luminance_alpha:
00751 tex->_pbuffer->set_format(PixelBuffer::F_luminance_alpha);
00752 break;
00753
00754 case EggTexture::F_luminance_alphamask:
00755 tex->_pbuffer->set_format(PixelBuffer::F_luminance_alphamask);
00756 break;
00757
00758 case EggTexture::F_unspecified:
00759 break;
00760
00761 default:
00762 egg2pg_cat.warning()
00763 << "Ignoring inappropriate format " << egg_tex->get_format()
00764 << " for 2-component texture " << egg_tex->get_name() << "\n";
00765 }
00766
00767 } else if (tex->_pbuffer->get_num_components() == 3) {
00768 switch (egg_tex->get_format()) {
00769 case EggTexture::F_rgb:
00770 tex->_pbuffer->set_format(PixelBuffer::F_rgb);
00771 break;
00772 case EggTexture::F_rgb12:
00773 if (tex->_pbuffer->get_component_width() >= 2) {
00774
00775 tex->_pbuffer->set_format(PixelBuffer::F_rgb12);
00776 } else {
00777 egg2pg_cat.warning()
00778 << "Ignoring inappropriate format " << egg_tex->get_format()
00779 << " for 8-bit texture " << egg_tex->get_name() << "\n";
00780 }
00781 break;
00782 case EggTexture::F_rgb8:
00783 case EggTexture::F_rgba8:
00784
00785
00786
00787 tex->_pbuffer->set_format(PixelBuffer::F_rgb8);
00788 break;
00789 case EggTexture::F_rgb5:
00790 tex->_pbuffer->set_format(PixelBuffer::F_rgb5);
00791 break;
00792 case EggTexture::F_rgb332:
00793 tex->_pbuffer->set_format(PixelBuffer::F_rgb332);
00794 break;
00795
00796 case EggTexture::F_unspecified:
00797 break;
00798
00799 default:
00800 egg2pg_cat.warning()
00801 << "Ignoring inappropriate format " << egg_tex->get_format()
00802 << " for 3-component texture " << egg_tex->get_name() << "\n";
00803 }
00804
00805 } else if (tex->_pbuffer->get_num_components() == 4) {
00806 switch (egg_tex->get_format()) {
00807 case EggTexture::F_rgba:
00808 tex->_pbuffer->set_format(PixelBuffer::F_rgba);
00809 break;
00810 case EggTexture::F_rgbm:
00811 tex->_pbuffer->set_format(PixelBuffer::F_rgbm);
00812 break;
00813 case EggTexture::F_rgba12:
00814 if (tex->_pbuffer->get_component_width() >= 2) {
00815
00816 tex->_pbuffer->set_format(PixelBuffer::F_rgba12);
00817 } else {
00818 egg2pg_cat.warning()
00819 << "Ignoring inappropriate format " << egg_tex->get_format()
00820 << " for 8-bit texture " << egg_tex->get_name() << "\n";
00821 }
00822 break;
00823 case EggTexture::F_rgba8:
00824 tex->_pbuffer->set_format(PixelBuffer::F_rgba8);
00825 break;
00826 case EggTexture::F_rgba4:
00827 tex->_pbuffer->set_format(PixelBuffer::F_rgba4);
00828 break;
00829 case EggTexture::F_rgba5:
00830 tex->_pbuffer->set_format(PixelBuffer::F_rgba5);
00831 break;
00832
00833 case EggTexture::F_unspecified:
00834 break;
00835
00836 default:
00837 egg2pg_cat.warning()
00838 << "Ignoring inappropriate format " << egg_tex->get_format()
00839 << " for 4-component texture " << egg_tex->get_name() << "\n";
00840 }
00841 }
00842 }
00843
00844
00845
00846
00847
00848
00849 CPT(RenderAttrib) EggLoader::
00850 get_texture_apply_attributes(const EggTexture *egg_tex) {
00851 CPT(RenderAttrib) result = TextureApplyAttrib::make(TextureApplyAttrib::M_modulate);
00852 if (egg_always_decal_textures) {
00853 result = TextureApplyAttrib::make(TextureApplyAttrib::M_decal);
00854
00855 } else {
00856 switch (egg_tex->get_env_type()) {
00857 case EggTexture::ET_modulate:
00858 result = TextureApplyAttrib::make(TextureApplyAttrib::M_modulate);
00859 break;
00860
00861 case EggTexture::ET_decal:
00862 result = TextureApplyAttrib::make(TextureApplyAttrib::M_decal);
00863 break;
00864
00865 case EggTexture::ET_unspecified:
00866 break;
00867
00868 default:
00869 egg2pg_cat.warning()
00870 << "Invalid texture environment "
00871 << (int)egg_tex->get_env_type() << "\n";
00872 }
00873 }
00874
00875 return result;
00876 }
00877
00878
00879
00880
00881
00882
00883
00884
00885 CPT(RenderAttrib) EggLoader::
00886 get_material_attrib(const EggMaterial *egg_mat, bool bface) {
00887 Materials &materials = bface ? _materials_bface : _materials;
00888
00889
00890 Materials::const_iterator mi;
00891 mi = materials.find(egg_mat);
00892 if (mi != materials.end()) {
00893 return (*mi).second;
00894 }
00895
00896
00897
00898 PT(Material) mat = new Material;
00899 if (egg_mat->has_diff()) {
00900 mat->set_diffuse(egg_mat->get_diff());
00901
00902
00903 mat->set_ambient(egg_mat->get_diff());
00904 }
00905 if (egg_mat->has_amb()) {
00906 mat->set_ambient(egg_mat->get_amb());
00907 }
00908 if (egg_mat->has_emit()) {
00909 mat->set_emission(egg_mat->get_emit());
00910 }
00911 if (egg_mat->has_spec()) {
00912 mat->set_specular(egg_mat->get_spec());
00913 }
00914 if (egg_mat->has_shininess()) {
00915 mat->set_shininess(egg_mat->get_shininess());
00916 }
00917 if (egg_mat->has_local()) {
00918 mat->set_local(egg_mat->get_local());
00919 }
00920
00921 mat->set_twoside(bface);
00922
00923
00924 const Material *shared_mat = MaterialPool::get_material(mat);
00925
00926
00927 CPT(RenderAttrib) mt = MaterialAttrib::make(shared_mat);
00928 materials.insert(Materials::value_type(egg_mat, mt));
00929
00930 return mt;
00931 }
00932
00933
00934
00935
00936
00937
00938
00939 void EggLoader::
00940 setup_bucket(BuilderBucket &bucket, PandaNode *parent,
00941 EggPrimitive *egg_prim) {
00942 bucket._node = parent;
00943 bucket._mesh = egg_mesh;
00944 bucket._retesselate_coplanar = egg_retesselate_coplanar;
00945 bucket._unroll_fans = egg_unroll_fans;
00946 bucket._show_tstrips = egg_show_tstrips;
00947 bucket._show_qsheets = egg_show_qsheets;
00948 bucket._show_quads = egg_show_quads;
00949 bucket._show_normals = egg_show_normals;
00950 bucket._normal_scale = egg_normal_scale;
00951 bucket._subdivide_polys = egg_subdivide_polys;
00952 bucket._consider_fans = egg_consider_fans;
00953 bucket._max_tfan_angle = egg_max_tfan_angle;
00954 bucket._min_tfan_tris = egg_min_tfan_tris;
00955 bucket._coplanar_threshold = egg_coplanar_threshold;
00956
00957
00958
00959
00960
00961 if (egg_prim->has_name() && !isdigit(egg_prim->get_name()[0])) {
00962 bucket.set_name(egg_prim->get_name());
00963 }
00964
00965
00966
00967
00968
00969
00970
00971
00972 EggRenderMode::AlphaMode am = EggRenderMode::AM_unspecified;
00973 EggRenderMode::DepthWriteMode dwm = EggRenderMode::DWM_unspecified;
00974 EggRenderMode::DepthTestMode dtm = EggRenderMode::DTM_unspecified;
00975 bool implicit_alpha = false;
00976 bool has_draw_order = false;
00977 int draw_order = 0;
00978 bool has_bin = false;
00979 string bin;
00980
00981 EggRenderMode *render_mode;
00982 render_mode = egg_prim->determine_alpha_mode();
00983 if (render_mode != (EggRenderMode *)NULL) {
00984 am = render_mode->get_alpha_mode();
00985 }
00986 render_mode = egg_prim->determine_depth_write_mode();
00987 if (render_mode != (EggRenderMode *)NULL) {
00988 dwm = render_mode->get_depth_write_mode();
00989 }
00990 render_mode = egg_prim->determine_depth_test_mode();
00991 if (render_mode != (EggRenderMode *)NULL) {
00992 dtm = render_mode->get_depth_test_mode();
00993 }
00994 render_mode = egg_prim->determine_draw_order();
00995 if (render_mode != (EggRenderMode *)NULL) {
00996 has_draw_order = true;
00997 draw_order = render_mode->get_draw_order();
00998 }
00999 render_mode = egg_prim->determine_bin();
01000 if (render_mode != (EggRenderMode *)NULL) {
01001 has_bin = true;
01002 bin = render_mode->get_bin();
01003 }
01004
01005 bucket.add_attrib(TextureAttrib::make_off());
01006 if (egg_prim->has_texture()) {
01007 PT(EggTexture) egg_tex = egg_prim->get_texture();
01008
01009 const TextureDef &def = _textures[egg_tex];
01010 if (def._texture != (const RenderAttrib *)NULL) {
01011 bucket.add_attrib(def._texture);
01012 bucket.add_attrib(def._apply);
01013
01014
01015
01016
01017 if (am == EggRenderMode::AM_unspecified) {
01018 const TextureAttrib *tex_attrib = DCAST(TextureAttrib, def._texture);
01019 Texture *tex = tex_attrib->get_texture();
01020 nassertv(tex != (Texture *)NULL);
01021 int num_components = tex->_pbuffer->get_num_components();
01022 if (egg_tex->has_alpha_channel(num_components)) {
01023 implicit_alpha = true;
01024 }
01025 }
01026 }
01027 }
01028
01029 if (egg_prim->has_material()) {
01030 CPT(RenderAttrib) mt =
01031 get_material_attrib(egg_prim->get_material(),
01032 egg_prim->get_bface_flag());
01033 bucket.add_attrib(mt);
01034 }
01035
01036
01037
01038
01039 if (am == EggRenderMode::AM_unspecified) {
01040 if (egg_prim->has_color()) {
01041 if (egg_prim->get_color()[3] != 1.0) {
01042 implicit_alpha = true;
01043 }
01044 }
01045 EggPrimitive::const_iterator vi;
01046 for (vi = egg_prim->begin();
01047 !implicit_alpha && vi != egg_prim->end();
01048 ++vi) {
01049 if ((*vi)->has_color()) {
01050 if ((*vi)->get_color()[3] != 1.0) {
01051 implicit_alpha = true;
01052 }
01053 }
01054 }
01055
01056 if (implicit_alpha) {
01057 am = EggRenderMode::AM_on;
01058 }
01059 }
01060
01061 if (am == EggRenderMode::AM_on) {
01062
01063 am = egg_alpha_mode;
01064 }
01065
01066 switch (am) {
01067 case EggRenderMode::AM_on:
01068 case EggRenderMode::AM_blend:
01069 bucket.add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
01070 break;
01071
01072 case EggRenderMode::AM_blend_no_occlude:
01073 bucket.add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
01074 bucket.add_attrib(DepthWriteAttrib::make(DepthWriteAttrib::M_off));
01075 break;
01076
01077 case EggRenderMode::AM_ms:
01078 bucket.add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_multisample));
01079 break;
01080
01081 case EggRenderMode::AM_ms_mask:
01082 bucket.add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_multisample_mask));
01083 break;
01084
01085 case EggRenderMode::AM_binary:
01086 bucket.add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_binary));
01087 break;
01088
01089 case EggRenderMode::AM_dual:
01090 bucket.add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_dual));
01091 break;
01092
01093 default:
01094 break;
01095 }
01096
01097 switch (dwm) {
01098 case EggRenderMode::DWM_on:
01099 bucket.add_attrib(DepthWriteAttrib::make(DepthWriteAttrib::M_on));
01100 break;
01101
01102 case EggRenderMode::DWM_off:
01103 bucket.add_attrib(DepthWriteAttrib::make(DepthWriteAttrib::M_off));
01104 break;
01105
01106 default:
01107 break;
01108 }
01109
01110 switch (dtm) {
01111 case EggRenderMode::DTM_on:
01112 bucket.add_attrib(DepthTestAttrib::make(DepthTestAttrib::M_less));
01113 break;
01114
01115 case EggRenderMode::DTM_off:
01116 bucket.add_attrib(DepthTestAttrib::make(DepthTestAttrib::M_none));
01117 break;
01118
01119 default:
01120 break;
01121 }
01122
01123 if (has_bin) {
01124 bucket.add_attrib(CullBinAttrib::make(bin, draw_order));
01125
01126 } else if (has_draw_order) {
01127 bucket.add_attrib(CullBinAttrib::make("fixed", draw_order));
01128 }
01129
01130
01131 if (egg_prim->get_bface_flag()) {
01132
01133
01134 bucket.add_attrib(CullFaceAttrib::make(CullFaceAttrib::M_cull_none));
01135 }
01136 }
01137
01138
01139
01140
01141
01142
01143
01144
01145 PandaNode *EggLoader::
01146 make_node(EggNode *egg_node, PandaNode *parent) {
01147 if (egg_node->is_of_type(EggNurbsCurve::get_class_type())) {
01148 return make_node(DCAST(EggNurbsCurve, egg_node), parent);
01149 } else if (egg_node->is_of_type(EggPrimitive::get_class_type())) {
01150 return make_node(DCAST(EggPrimitive, egg_node), parent);
01151 } else if (egg_node->is_of_type(EggBin::get_class_type())) {
01152 return make_node(DCAST(EggBin, egg_node), parent);
01153 } else if (egg_node->is_of_type(EggGroup::get_class_type())) {
01154 return make_node(DCAST(EggGroup, egg_node), parent);
01155 } else if (egg_node->is_of_type(EggTable::get_class_type())) {
01156 return make_node(DCAST(EggTable, egg_node), parent);
01157 } else if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
01158 return make_node(DCAST(EggGroupNode, egg_node), parent);
01159 }
01160
01161 return (PandaNode *)NULL;
01162 }
01163
01164
01165
01166
01167
01168
01169 PandaNode *EggLoader::
01170 make_node(EggNurbsCurve *egg_curve, PandaNode *parent) {
01171 assert(parent != NULL);
01172 assert(!parent->is_geom_node());
01173
01174 PT(ParametricCurve) curve;
01175
01176 if (egg_load_classic_nurbs_curves) {
01177 curve = new ClassicNurbsCurve;
01178 } else {
01179 curve = new NurbsCurve;
01180 }
01181
01182 NurbsCurveInterface *nurbs = curve->get_nurbs_interface();
01183 nassertr(nurbs != (NurbsCurveInterface *)NULL, (PandaNode *)NULL);
01184
01185 if (egg_curve->get_order() < 1 || egg_curve->get_order() > 4) {
01186 egg2pg_cat.error()
01187 << "Invalid NURBSCurve order for " << egg_curve->get_name() << ": "
01188 << egg_curve->get_order() << "\n";
01189 _error = true;
01190 return (PandaNode *)NULL;
01191 }
01192
01193 nurbs->set_order(egg_curve->get_order());
01194
01195 EggPrimitive::const_iterator pi;
01196 for (pi = egg_curve->begin(); pi != egg_curve->end(); ++pi) {
01197 nurbs->append_cv(LCAST(float, (*pi)->get_pos4()));
01198 }
01199
01200 int num_knots = egg_curve->get_num_knots();
01201 if (num_knots != nurbs->get_num_knots()) {
01202 egg2pg_cat.error()
01203 << "Invalid NURBSCurve number of knots for "
01204 << egg_curve->get_name() << ": got " << num_knots
01205 << " knots, expected " << nurbs->get_num_knots() << "\n";
01206 _error = true;
01207 return (PandaNode *)NULL;
01208 }
01209
01210 for (int i = 0; i < num_knots; i++) {
01211 nurbs->set_knot(i, egg_curve->get_knot(i));
01212 }
01213
01214 switch (egg_curve->get_curve_type()) {
01215 case EggCurve::CT_xyz:
01216 curve->set_curve_type(PCT_XYZ);
01217 break;
01218
01219 case EggCurve::CT_hpr:
01220 curve->set_curve_type(PCT_HPR);
01221 break;
01222
01223 case EggCurve::CT_t:
01224 curve->set_curve_type(PCT_T);
01225 break;
01226
01227 default:
01228 break;
01229 }
01230 curve->set_name(egg_curve->get_name());
01231
01232 if (!curve->recompute()) {
01233 egg2pg_cat.error()
01234 << "Invalid NURBSCurve " << egg_curve->get_name() << "\n";
01235 _error = true;
01236 return (PandaNode *)NULL;
01237 }
01238
01239 parent->add_child(curve);
01240 return curve;
01241 }
01242
01243
01244
01245
01246
01247
01248 PandaNode *EggLoader::
01249 make_node(EggPrimitive *egg_prim, PandaNode *parent) {
01250 assert(parent != NULL);
01251 assert(!parent->is_of_type(GeomNode::get_class_type()));
01252
01253 if (egg_prim->cleanup()) {
01254 if (parent->is_of_type(SelectiveChildNode::get_class_type())) {
01255
01256
01257
01258 PandaNode *group = new PandaNode(egg_prim->get_name());
01259 parent->add_child(group);
01260 make_nonindexed_primitive(egg_prim, group);
01261 return group;
01262 }
01263
01264
01265
01266
01267
01268 make_nonindexed_primitive(egg_prim, parent);
01269 }
01270 return (PandaNode *)NULL;
01271 }
01272
01273
01274
01275
01276
01277
01278 PandaNode *EggLoader::
01279 make_node(EggBin *egg_bin, PandaNode *parent) {
01280
01281
01282
01283
01284 nassertr((EggBinner::BinNumber)egg_bin->get_bin_number() == EggBinner::BN_lod, NULL);
01285 LODNode *lod_node = new LODNode(egg_bin->get_name());
01286
01287 pvector<LODInstance> instances;
01288
01289 EggGroup::const_iterator ci;
01290 for (ci = egg_bin->begin(); ci != egg_bin->end(); ++ci) {
01291 LODInstance instance(*ci);
01292 instances.push_back(instance);
01293 }
01294
01295
01296
01297 sort(instances.begin(), instances.end());
01298
01299 if (!instances.empty()) {
01300
01301
01302 lod_node->set_center(LCAST(float, instances[0]._d->_center));
01303 }
01304
01305 for (size_t i = 0; i < instances.size(); i++) {
01306
01307 const LODInstance &instance = instances[i];
01308 make_node(instance._egg_node, lod_node);
01309
01310
01311
01312 nassertr(lod_node->get_center().almost_equal
01313 (LCAST(float, instance._d->_center), 0.01), NULL);
01314
01315
01316 lod_node->add_switch(instance._d->_switch_in, instance._d->_switch_out);
01317 }
01318
01319 return create_group_arc(egg_bin, parent, lod_node);
01320 }
01321
01322
01323
01324
01325
01326
01327
01328 PandaNode *EggLoader::
01329 make_node(EggGroup *egg_group, PandaNode *parent) {
01330 PT(PandaNode) node = NULL;
01331
01332 if (egg_group->get_num_object_types() != 0) {
01333 pset<string> expanded;
01334 pvector<string> expanded_history;
01335 if (!expand_object_types(egg_group, expanded, expanded_history)) {
01336 return NULL;
01337 }
01338 }
01339
01340 if (egg_group->get_dart_type() != EggGroup::DT_none) {
01341
01342 CharacterMaker char_maker(egg_group, *this);
01343 node = char_maker.make_node();
01344
01345 } else if (egg_group->get_cs_type() != EggGroup::CST_none &&
01346 egg_group->get_cs_type() != EggGroup::CST_geode) {
01347
01348 node = new CollisionNode(egg_group->get_name());
01349
01350 make_collision_solids(egg_group, egg_group, (CollisionNode *)node.p());
01351 if ((egg_group->get_collide_flags() & EggGroup::CF_keep) != 0) {
01352
01353
01354 EggGroup::const_iterator ci;
01355 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
01356 make_node(*ci, parent);
01357 }
01358 }
01359
01360 node = create_group_arc(egg_group, parent, node);
01361
01362 if (!egg_show_collision_solids) {
01363 node->set_draw_mask(DrawMask::all_off());
01364 }
01365 return node;
01366
01367 } else if (egg_group->get_switch_flag()) {
01368 if (egg_group->get_switch_fps() != 0.0) {
01369
01370 node = new SequenceNode(egg_group->get_switch_fps(),
01371 egg_group->get_name());
01372 } else {
01373
01374 node = new SwitchNode(egg_group->get_name());
01375 }
01376
01377 EggGroup::const_iterator ci;
01378 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
01379 make_node(*ci, node);
01380 }
01381
01382 } else if (egg_group->get_model_flag() ||
01383 egg_group->get_dcs_type() != EggGroup::DC_none) {
01384
01385 node = new ModelNode(egg_group->get_name());
01386 switch (egg_group->get_dcs_type()) {
01387 case EggGroup::DC_net:
01388 DCAST(ModelNode, node)->set_preserve_transform(ModelNode::PT_net);
01389 break;
01390
01391 case EggGroup::DC_local:
01392 case EggGroup::DC_default:
01393 DCAST(ModelNode, node)->set_preserve_transform(ModelNode::PT_local);
01394 break;
01395
01396 case EggGroup::DC_none:
01397 break;
01398 }
01399
01400 EggGroup::const_iterator ci;
01401 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
01402 make_node(*ci, node);
01403 }
01404
01405 } else {
01406
01407 node = new PandaNode(egg_group->get_name());
01408
01409 EggGroup::const_iterator ci;
01410 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
01411 make_node(*ci, node);
01412 }
01413 }
01414
01415 if (node == (PandaNode *)NULL) {
01416 return NULL;
01417 }
01418 return create_group_arc(egg_group, parent, node);
01419 }
01420
01421
01422
01423
01424
01425
01426
01427
01428
01429 PandaNode *EggLoader::
01430 create_group_arc(EggGroup *egg_group, PandaNode *parent, PandaNode *node) {
01431 parent->add_child(node);
01432
01433
01434 if (egg_group->has_transform()) {
01435 node->set_transform(make_transform(egg_group));
01436 }
01437
01438
01439 switch (egg_group->get_billboard_type()) {
01440 case EggGroup::BT_point_camera_relative:
01441 node->set_effect(BillboardEffect::make_point_eye());
01442 break;
01443
01444 case EggGroup::BT_point_world_relative:
01445 node->set_effect(BillboardEffect::make_point_world());
01446 break;
01447
01448 case EggGroup::BT_axis:
01449 node->set_effect(BillboardEffect::make_axis());
01450 break;
01451
01452 case EggGroup::BT_none:
01453 break;
01454 }
01455
01456 if (egg_group->get_decal_flag()) {
01457 if (egg_ignore_decals) {
01458 egg2pg_cat.error()
01459 << "Ignoring decal flag on " << egg_group->get_name() << "\n";
01460 _error = true;
01461 }
01462
01463
01464
01465
01466
01467 _decals.insert(node);
01468 }
01469
01470
01471
01472
01473 DeferredNodeProperty def;
01474 if (egg_group->has_collide_mask()) {
01475 def._from_collide_mask = egg_group->get_collide_mask();
01476 def._into_collide_mask = egg_group->get_collide_mask();
01477 def._flags |=
01478 DeferredNodeProperty::F_has_from_collide_mask |
01479 DeferredNodeProperty::F_has_into_collide_mask;
01480 }
01481 if (egg_group->has_from_collide_mask()) {
01482 def._from_collide_mask = egg_group->get_from_collide_mask();
01483 def._flags |= DeferredNodeProperty::F_has_from_collide_mask;
01484 }
01485 if (egg_group->has_into_collide_mask()) {
01486 def._into_collide_mask = egg_group->get_into_collide_mask();
01487 def._flags |= DeferredNodeProperty::F_has_into_collide_mask;
01488 }
01489
01490 if (def._flags != 0) {
01491 _deferred_nodes[node] = def;
01492 }
01493
01494 return node;
01495 }
01496
01497
01498
01499
01500
01501
01502 PandaNode *EggLoader::
01503 make_node(EggTable *egg_table, PandaNode *parent) {
01504 if (egg_table->get_table_type() != EggTable::TT_bundle) {
01505
01506
01507 return make_node(DCAST(EggGroupNode, egg_table), parent);
01508 }
01509
01510
01511
01512 AnimBundleMaker bundle_maker(egg_table);
01513 AnimBundleNode *node = bundle_maker.make_node();
01514 parent->add_child(node);
01515 return node;
01516 }
01517
01518
01519
01520
01521
01522
01523
01524 PandaNode *EggLoader::
01525 make_node(EggGroupNode *egg_group, PandaNode *parent) {
01526 PandaNode *node = new PandaNode(egg_group->get_name());
01527
01528 EggGroupNode::const_iterator ci;
01529 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
01530 make_node(*ci, node);
01531 }
01532
01533 parent->add_child(node);
01534 return node;
01535 }
01536
01537
01538
01539
01540
01541
01542
01543
01544 void EggLoader::
01545 make_collision_solids(EggGroup *start_group, EggGroup *egg_group,
01546 CollisionNode *cnode) {
01547 if (egg_group->get_cs_type() != EggGroup::CST_none) {
01548 start_group = egg_group;
01549 }
01550
01551 switch (start_group->get_cs_type()) {
01552 case EggGroup::CST_none:
01553 case EggGroup::CST_geode:
01554
01555 return;
01556
01557 case EggGroup::CST_inverse_sphere:
01558
01559 egg2pg_cat.error()
01560 << "Not presently supported: <Collide> { "
01561 << egg_group->get_cs_type() << " }\n";
01562 _error = true;
01563 break;
01564
01565 case EggGroup::CST_plane:
01566 make_collision_plane(egg_group, cnode, start_group->get_collide_flags());
01567 break;
01568
01569 case EggGroup::CST_polygon:
01570 make_collision_polygon(egg_group, cnode, start_group->get_collide_flags());
01571 break;
01572
01573 case EggGroup::CST_polyset:
01574 make_collision_polyset(egg_group, cnode, start_group->get_collide_flags());
01575 break;
01576
01577 case EggGroup::CST_sphere:
01578 make_collision_sphere(egg_group, cnode, start_group->get_collide_flags());
01579 break;
01580 }
01581
01582 if ((start_group->get_collide_flags() & EggGroup::CF_descend) != 0) {
01583
01584 EggGroup::const_iterator ci;
01585 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
01586 if ((*ci)->is_of_type(EggGroup::get_class_type())) {
01587 make_collision_solids(start_group, DCAST(EggGroup, *ci), cnode);
01588 }
01589 }
01590 }
01591 }
01592
01593
01594
01595
01596
01597
01598
01599 void EggLoader::
01600 make_collision_plane(EggGroup *egg_group, CollisionNode *cnode,
01601 EggGroup::CollideFlags flags) {
01602 EggGroup *geom_group = find_collision_geometry(egg_group);
01603 if (geom_group != (EggGroup *)NULL) {
01604 EggGroup::const_iterator ci;
01605 for (ci = geom_group->begin(); ci != geom_group->end(); ++ci) {
01606 if ((*ci)->is_of_type(EggPolygon::get_class_type())) {
01607 CollisionPlane *csplane =
01608 create_collision_plane(DCAST(EggPolygon, *ci), egg_group);
01609 if (csplane != (CollisionPlane *)NULL) {
01610 apply_collision_flags(csplane, flags);
01611 cnode->add_solid(csplane);
01612 return;
01613 }
01614 }
01615 }
01616 }
01617 }
01618
01619
01620
01621
01622
01623
01624
01625 void EggLoader::
01626 make_collision_polygon(EggGroup *egg_group, CollisionNode *cnode,
01627 EggGroup::CollideFlags flags) {
01628
01629 EggGroup *geom_group = find_collision_geometry(egg_group);
01630 if (geom_group != (EggGroup *)NULL) {
01631 EggGroup::const_iterator ci;
01632 for (ci = geom_group->begin(); ci != geom_group->end(); ++ci) {
01633 if ((*ci)->is_of_type(EggPolygon::get_class_type())) {
01634 create_collision_polygons(cnode, DCAST(EggPolygon, *ci),
01635 egg_group, flags);
01636 }
01637 }
01638 }
01639 }
01640
01641
01642
01643
01644
01645
01646
01647 void EggLoader::
01648 make_collision_polyset(EggGroup *egg_group, CollisionNode *cnode,
01649 EggGroup::CollideFlags flags) {
01650 EggGroup *geom_group = find_collision_geometry(egg_group);
01651 if (geom_group != (EggGroup *)NULL) {
01652 EggGroup::const_iterator ci;
01653 for (ci = geom_group->begin(); ci != geom_group->end(); ++ci) {
01654 if ((*ci)->is_of_type(EggPolygon::get_class_type())) {
01655 create_collision_polygons(cnode, DCAST(EggPolygon, *ci),
01656 egg_group, flags);
01657 }
01658 }
01659 }
01660 }
01661
01662
01663
01664
01665
01666
01667
01668 void EggLoader::
01669 make_collision_sphere(EggGroup *egg_group, CollisionNode *cnode,
01670 EggGroup::CollideFlags flags) {
01671 EggGroup *geom_group = find_collision_geometry(egg_group);
01672 if (geom_group != (EggGroup *)NULL) {
01673
01674 pset<EggVertex *> vertices;
01675
01676 EggGroup::const_iterator ci;
01677 for (ci = geom_group->begin(); ci != geom_group->end(); ++ci) {
01678 if ((*ci)->is_of_type(EggPrimitive::get_class_type())) {
01679 EggPrimitive *prim = DCAST(EggPrimitive, *ci);
01680 EggPrimitive::const_iterator pi;
01681 for (pi = prim->begin(); pi != prim->end(); ++pi) {
01682 vertices.insert(*pi);
01683 }
01684 }
01685 }
01686
01687
01688 int num_vertices = 0;
01689 LPoint3d center(0.0, 0.0, 0.0);
01690 pset<EggVertex *>::const_iterator vi;
01691
01692 for (vi = vertices.begin(); vi != vertices.end(); ++vi) {
01693 EggVertex *vtx = (*vi);
01694 if (vtx->get_num_dimensions() == 3) {
01695 center += vtx->get_pos3();
01696 num_vertices++;
01697
01698 } else if (vtx->get_num_dimensions() == 4) {
01699 LPoint4d p4 = vtx->get_pos4();
01700 if (p4[3] != 0.0) {
01701 center += LPoint3d(p4[0], p4[1], p4[2]) / p4[3];
01702 num_vertices++;
01703 }
01704 }
01705 }
01706
01707 if (num_vertices > 0) {
01708 center /= (double)num_vertices;
01709
01710 LMatrix4d mat = egg_group->get_vertex_to_node();
01711 center = center * mat;
01712
01713
01714 double radius2 = 0.0;
01715 for (vi = vertices.begin(); vi != vertices.end(); ++vi) {
01716 EggVertex *vtx = (*vi);
01717 if (vtx->get_num_dimensions() == 3) {
01718 LPoint3d p3 = vtx->get_pos3();
01719 LVector3d v = p3 * mat - center;
01720 radius2 = max(radius2, v.length_squared());
01721
01722 } else if (vtx->get_num_dimensions() == 4) {
01723 LPoint4d p4 = vtx->get_pos4();
01724 if (p4[3] != 0.0) {
01725 LPoint3d p3 = LPoint3d(p4[0], p4[1], p4[2]) / p4[3];
01726 LVector3d v = p3 * mat - center;
01727 radius2 = max(radius2, v.length_squared());
01728 }
01729 }
01730 }
01731
01732 float radius = sqrtf(radius2);
01733 CollisionSphere *cssphere =
01734 new CollisionSphere(LCAST(float, center), radius);
01735 apply_collision_flags(cssphere, flags);
01736 cnode->add_solid(cssphere);
01737 }
01738 }
01739 }
01740
01741
01742
01743
01744
01745
01746
01747
01748 void EggLoader::
01749 apply_collision_flags(CollisionSolid *solid,
01750 EggGroup::CollideFlags flags) {
01751 if ((flags & EggGroup::CF_intangible) != 0) {
01752 solid->set_tangible(false);
01753 }
01754 }
01755
01756
01757
01758
01759
01760
01761
01762 EggGroup *EggLoader::
01763 find_collision_geometry(EggGroup *egg_group) {
01764 if ((egg_group->get_collide_flags() & EggGroup::CF_descend) != 0) {
01765
01766
01767 return egg_group;
01768 }
01769
01770
01771 EggGroup::const_iterator ci;
01772 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
01773 if ((*ci)->is_of_type(EggPolygon::get_class_type())) {
01774
01775 return egg_group;
01776 }
01777 }
01778
01779
01780
01781 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
01782 if ((*ci)->is_of_type(EggGroup::get_class_type())) {
01783 EggGroup *child_group = DCAST(EggGroup, *ci);
01784 if (child_group->get_cs_type() == egg_group->get_cs_type()) {
01785 return child_group;
01786 }
01787 }
01788 }
01789
01790
01791 return NULL;
01792 }
01793
01794
01795
01796
01797
01798
01799
01800 CollisionPlane *EggLoader::
01801 create_collision_plane(EggPolygon *egg_poly, EggGroup *parent_group) {
01802 if (!egg_poly->cleanup()) {
01803 egg2pg_cat.error()
01804 << "Degenerate collision plane in " << parent_group->get_name()
01805 << "\n";
01806 _error = true;
01807 return NULL;
01808 }
01809
01810 LMatrix4d mat = egg_poly->get_vertex_to_node();
01811
01812 pvector<Vertexf> vertices;
01813 if (!egg_poly->empty()) {
01814 EggPolygon::const_iterator vi;
01815 vi = egg_poly->begin();
01816
01817 Vertexd vert = (*vi)->get_pos3() * mat;
01818 vertices.push_back(LCAST(float, vert));
01819
01820 Vertexd last_vert = vert;
01821 ++vi;
01822 while (vi != egg_poly->end()) {
01823 vert = (*vi)->get_pos3() * mat;
01824 if (!vert.almost_equal(last_vert)) {
01825 vertices.push_back(LCAST(float, vert));
01826 }
01827
01828 last_vert = vert;
01829 ++vi;
01830 }
01831 }
01832
01833 if (vertices.size() < 3) {
01834 return NULL;
01835 }
01836 Planef plane(vertices[0], vertices[1], vertices[2]);
01837 return new CollisionPlane(plane);
01838 }
01839
01840
01841
01842
01843
01844
01845
01846
01847 void EggLoader::
01848 create_collision_polygons(CollisionNode *cnode, EggPolygon *egg_poly,
01849 EggGroup *parent_group,
01850 EggGroup::CollideFlags flags) {
01851 LMatrix4d mat = egg_poly->get_vertex_to_node();
01852
01853 PT(EggGroup) group = new EggGroup;
01854
01855 if (!egg_poly->triangulate_into(group, false)) {
01856 egg2pg_cat.error()
01857 << "Degenerate collision polygon in " << parent_group->get_name()
01858 << "\n";
01859 _error = true;
01860 return;
01861 }
01862
01863 if (group->size() != 1) {
01864 egg2pg_cat.error()
01865 << "Concave collision polygon in " << parent_group->get_name()
01866 << "\n";
01867 _error = true;
01868 }
01869
01870 EggGroup::iterator ci;
01871 for (ci = group->begin(); ci != group->end(); ++ci) {
01872 EggPolygon *poly = DCAST(EggPolygon, *ci);
01873
01874 pvector<Vertexf> vertices;
01875 if (!poly->empty()) {
01876 EggPolygon::const_iterator vi;
01877 vi = poly->begin();
01878
01879 Vertexd vert = (*vi)->get_pos3() * mat;
01880 vertices.push_back(LCAST(float, vert));
01881
01882 Vertexd last_vert = vert;
01883 ++vi;
01884 while (vi != poly->end()) {
01885 vert = (*vi)->get_pos3() * mat;
01886 if (!vert.almost_equal(last_vert)) {
01887 vertices.push_back(LCAST(float, vert));
01888 }
01889
01890 last_vert = vert;
01891 ++vi;
01892 }
01893 }
01894
01895 if (vertices.size() >= 3) {
01896 const Vertexf *vertices_begin = &vertices[0];
01897 const Vertexf *vertices_end = vertices_begin + vertices.size();
01898 CollisionPolygon *cspoly =
01899 new CollisionPolygon(vertices_begin, vertices_end);
01900 apply_collision_flags(cspoly, flags);
01901 cnode->add_solid(cspoly);
01902 }
01903 }
01904 }
01905
01906
01907
01908
01909
01910
01911
01912
01913
01914 void EggLoader::
01915 apply_deferred_nodes(PandaNode *node, const DeferredNodeProperty &prop) {
01916 DeferredNodeProperty next_prop(prop);
01917
01918
01919 DeferredNodes::const_iterator dni;
01920 dni = _deferred_nodes.find(node);
01921
01922 if (dni != _deferred_nodes.end()) {
01923 const DeferredNodeProperty &def = (*dni).second;
01924 next_prop.compose(def);
01925 }
01926
01927
01928 next_prop.apply_to_node(node);
01929
01930 int num_children = node->get_num_children();
01931 for (int i = 0; i < num_children; i++) {
01932 apply_deferred_nodes(node->get_child(i), next_prop);
01933 }
01934 }
01935
01936
01937
01938
01939
01940
01941
01942
01943
01944
01945
01946
01947
01948 bool EggLoader::
01949 expand_object_types(EggGroup *egg_group, const pset<string> &expanded,
01950 const pvector<string> &expanded_history) {
01951 int num_object_types = egg_group->get_num_object_types();
01952
01953
01954
01955 vector_string object_types;
01956 int i;
01957 for (i = 0; i < num_object_types; i++) {
01958 object_types.push_back(egg_group->get_object_type(i));
01959 }
01960 egg_group->clear_object_types();
01961
01962 for (i = 0; i < num_object_types; i++) {
01963 string object_type = object_types[i];
01964 pset<string> new_expanded(expanded);
01965
01966
01967 if (!new_expanded.insert(object_type).second) {
01968 egg2pg_cat.error()
01969 << "Cycle in ObjectType expansions:\n";
01970 pvector<string>::const_iterator pi;
01971 for (pi = expanded_history.begin();
01972 pi != expanded_history.end();
01973 ++pi) {
01974 egg2pg_cat.error(false)
01975 << (*pi) << " -> ";
01976 }
01977 egg2pg_cat.error(false) << object_type << "\n";
01978 _error = true;
01979
01980 } else {
01981
01982 pvector<string> new_expanded_history(expanded_history);
01983 new_expanded_history.push_back(object_type);
01984
01985 if (!do_expand_object_type(egg_group, new_expanded,
01986 new_expanded_history, object_type)) {
01987
01988 return false;
01989 }
01990 }
01991 }
01992
01993 return true;
01994 }
01995
01996
01997
01998
01999
02000
02001 bool EggLoader::
02002 do_expand_object_type(EggGroup *egg_group, const pset<string> &expanded,
02003 const pvector<string> &expanded_history,
02004 const string &object_type) {
02005
02006
02007
02008 string egg_syntax =
02009 config_egg2pg.GetString("egg-object-type-" + downcase(object_type), "none");
02010
02011 if (egg_syntax == "none") {
02012
02013
02014 if (cmp_nocase_uh(object_type, "barrier") == 0) {
02015 egg_syntax = "<Collide> { Polyset descend }";
02016
02017 } else if (cmp_nocase_uh(object_type, "solidpoly") == 0) {
02018 egg_syntax = "<Collide> { Polyset descend solid }";
02019
02020 } else if (cmp_nocase_uh(object_type, "turnstile") == 0) {
02021 egg_syntax = "<Collide> { Polyset descend turnstile }";
02022
02023 } else if (cmp_nocase_uh(object_type, "sphere") == 0) {
02024 egg_syntax = "<Collide> { Sphere descend }";
02025
02026 } else if (cmp_nocase_uh(object_type, "trigger") == 0) {
02027 egg_syntax = "<Collide> { Polyset descend intangible }";
02028
02029 } else if (cmp_nocase_uh(object_type, "trigger_sphere") == 0) {
02030 egg_syntax = "<Collide> { Sphere descend intangible }";
02031
02032 } else if (cmp_nocase_uh(object_type, "eye_trigger") == 0) {
02033 egg_syntax = "<Collide> { Polyset descend intangible center }";
02034
02035 } else if (cmp_nocase_uh(object_type, "bubble") == 0) {
02036 egg_syntax = "<Collide> { Sphere keep descend }";
02037
02038 } else if (cmp_nocase_uh(object_type, "ghost") == 0) {
02039 egg_syntax = "<Scalar> collide-mask { 0 }";
02040
02041 } else if (cmp_nocase_uh(object_type, "dcs") == 0) {
02042 egg_syntax = "<DCS> { 1 }";
02043
02044 } else if (cmp_nocase_uh(object_type, "model") == 0) {
02045 egg_syntax = "<Model> { 1 }";
02046
02047 } else if (cmp_nocase_uh(object_type, "backstage") == 0) {
02048
02049 return false;
02050
02051 } else {
02052 egg2pg_cat.error()
02053 << "Unknown ObjectType " << object_type << "\n";
02054 _error = true;
02055 return true;
02056 }
02057 }
02058
02059 if (!egg_syntax.empty()) {
02060 if (!egg_group->parse_egg(egg_syntax)) {
02061 egg2pg_cat.error()
02062 << "Error while parsing definition for ObjectType "
02063 << object_type << "\n";
02064 _error = true;
02065
02066 } else {
02067
02068
02069 if (egg_group->get_num_object_types() != 0) {
02070 if (!expand_object_types(egg_group, expanded, expanded_history)) {
02071 return false;
02072 }
02073 }
02074 }
02075 }
02076
02077 return true;
02078 }
02079
02080
02081
02082
02083
02084
02085
02086
02087 CPT(TransformState) EggLoader::
02088 make_transform(const EggTransform3d *egg_transform) {
02089
02090
02091
02092 CPT(TransformState) ts = TransformState::make_identity();
02093 int num_components = egg_transform->get_num_components();
02094 for (int i = 0; i < num_components; i++) {
02095 switch (egg_transform->get_component_type(i)) {
02096 case EggTransform3d::CT_translate:
02097 {
02098 LVector3f trans(LCAST(float, egg_transform->get_component_vector(i)));
02099 ts = TransformState::make_pos(trans)->compose(ts);
02100 }
02101 break;
02102
02103 case EggTransform3d::CT_rotx:
02104 {
02105 LRotationf rot(LVector3f(1.0f, 0.0f, 0.0f),
02106 (float)egg_transform->get_component_number(i));
02107 ts = TransformState::make_quat(rot)->compose(ts);
02108 }
02109 break;
02110
02111 case EggTransform3d::CT_roty:
02112 {
02113 LRotationf rot(LVector3f(0.0f, 1.0f, 0.0f),
02114 (float)egg_transform->get_component_number(i));
02115 ts = TransformState::make_quat(rot)->compose(ts);
02116 }
02117 break;
02118
02119 case EggTransform3d::CT_rotz:
02120 {
02121 LRotationf rot(LVector3f(0.0f, 0.0f, 1.0f),
02122 (float)egg_transform->get_component_number(i));
02123 ts = TransformState::make_quat(rot)->compose(ts);
02124 }
02125 break;
02126
02127 case EggTransform3d::CT_rotate:
02128 {
02129 LRotationf rot(LCAST(float, egg_transform->get_component_vector(i)),
02130 (float)egg_transform->get_component_number(i));
02131 ts = TransformState::make_quat(rot)->compose(ts);
02132 }
02133 break;
02134
02135 case EggTransform3d::CT_scale:
02136 {
02137 LVecBase3f scale(LCAST(float, egg_transform->get_component_vector(i)));
02138 ts = TransformState::make_scale(scale)->compose(ts);
02139 }
02140 break;
02141
02142 case EggTransform3d::CT_uniform_scale:
02143 {
02144 float scale = (float)egg_transform->get_component_number(i);
02145 ts = TransformState::make_scale(scale)->compose(ts);
02146 }
02147 break;
02148
02149 case EggTransform3d::CT_matrix:
02150 {
02151 LMatrix4f mat(LCAST(float, egg_transform->get_component_matrix(i)));
02152 ts = TransformState::make_mat(mat)->compose(ts);
02153 }
02154 break;
02155
02156 case EggTransform3d::CT_invalid:
02157 nassertr(false, ts);
02158 break;
02159 }
02160 }
02161
02162 return ts;
02163 }