00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "pandabase.h"
00016
00017 #include "eggLoader.h"
00018 #include "eggRenderState.h"
00019 #include "egg_parametrics.h"
00020 #include "config_egg2pg.h"
00021 #include "config_egg.h"
00022 #include "nodePath.h"
00023 #include "renderState.h"
00024 #include "transformState.h"
00025 #include "texturePool.h"
00026 #include "billboardEffect.h"
00027 #include "decalEffect.h"
00028 #include "colorAttrib.h"
00029 #include "textureAttrib.h"
00030 #include "materialPool.h"
00031 #include "geomNode.h"
00032 #include "geomVertexFormat.h"
00033 #include "geomVertexArrayFormat.h"
00034 #include "geomVertexData.h"
00035 #include "geomVertexWriter.h"
00036 #include "geom.h"
00037 #include "geomTriangles.h"
00038 #include "geomTristrips.h"
00039 #include "geomTrifans.h"
00040 #include "geomLines.h"
00041 #include "geomLinestrips.h"
00042 #include "geomPoints.h"
00043 #include "sequenceNode.h"
00044 #include "switchNode.h"
00045 #include "portalNode.h"
00046 #include "occluderNode.h"
00047 #include "polylightNode.h"
00048 #include "lodNode.h"
00049 #include "modelNode.h"
00050 #include "modelRoot.h"
00051 #include "string_utils.h"
00052 #include "eggPrimitive.h"
00053 #include "eggPoint.h"
00054 #include "eggLine.h"
00055 #include "eggTextureCollection.h"
00056 #include "eggNurbsCurve.h"
00057 #include "eggNurbsSurface.h"
00058 #include "eggGroupNode.h"
00059 #include "eggGroup.h"
00060 #include "eggPolygon.h"
00061 #include "eggTriangleStrip.h"
00062 #include "eggTriangleFan.h"
00063 #include "eggBin.h"
00064 #include "eggTable.h"
00065 #include "eggBinner.h"
00066 #include "eggVertexPool.h"
00067 #include "pt_EggTexture.h"
00068 #include "characterMaker.h"
00069 #include "character.h"
00070 #include "animBundleMaker.h"
00071 #include "animBundleNode.h"
00072 #include "selectiveChildNode.h"
00073 #include "collisionNode.h"
00074 #include "collisionSphere.h"
00075 #include "collisionInvSphere.h"
00076 #include "collisionTube.h"
00077 #include "collisionPlane.h"
00078 #include "collisionPolygon.h"
00079 #include "collisionFloorMesh.h"
00080 #include "parametricCurve.h"
00081 #include "nurbsCurve.h"
00082 #include "nurbsCurveInterface.h"
00083 #include "nurbsCurveEvaluator.h"
00084 #include "nurbsSurfaceEvaluator.h"
00085 #include "ropeNode.h"
00086 #include "sheetNode.h"
00087 #include "look_at.h"
00088 #include "configVariableString.h"
00089 #include "transformBlendTable.h"
00090 #include "transformBlend.h"
00091 #include "sparseArray.h"
00092 #include "bitArray.h"
00093 #include "thread.h"
00094 #include "uvScrollNode.h"
00095 #include "textureStagePool.h"
00096 #include "cmath.h"
00097
00098 #include <ctype.h>
00099 #include <algorithm>
00100
00101
00102
00103 class LODInstance {
00104 public:
00105 LODInstance(EggNode *egg_node);
00106 bool operator < (const LODInstance &other) const {
00107 return _d->_switch_in < other._d->_switch_in;
00108 }
00109
00110 EggNode *_egg_node;
00111 const EggSwitchConditionDistance *_d;
00112 };
00113
00114 LODInstance::
00115 LODInstance(EggNode *egg_node) {
00116 nassertv(egg_node != NULL);
00117 _egg_node = egg_node;
00118
00119
00120
00121
00122 EggGroup *egg_group = DCAST(EggGroup, egg_node);
00123 nassertv(egg_group->has_lod());
00124 const EggSwitchCondition &sw = egg_group->get_lod();
00125
00126
00127 _d = DCAST(EggSwitchConditionDistance, &sw);
00128 }
00129
00130
00131
00132
00133
00134
00135
00136 EggLoader::
00137 EggLoader() {
00138
00139 _data = new EggData;
00140 _data->set_coordinate_system(egg_coordinate_system);
00141 _error = false;
00142 _dynamic_override = false;
00143 _dynamic_override_char_maker = NULL;
00144 }
00145
00146
00147
00148
00149
00150
00151
00152 EggLoader::
00153 EggLoader(const EggData *data) :
00154 _data(new EggData(*data))
00155 {
00156 _error = false;
00157 _dynamic_override = false;
00158 _dynamic_override_char_maker = NULL;
00159 }
00160
00161
00162
00163
00164
00165
00166
00167 void EggLoader::
00168 build_graph() {
00169 _deferred_nodes.clear();
00170
00171
00172
00173 if (!expand_all_object_types(_data)) {
00174 return;
00175 }
00176
00177
00178 load_textures();
00179
00180
00181 _data->clear_connected_shading();
00182 _data->remove_unused_vertices(true);
00183 _data->get_connected_shading();
00184 _data->unify_attributes(true, egg_flat_shading, true);
00185
00186
00187
00188
00189
00190 _data->clear_connected_shading();
00191 _data->remove_unused_vertices(true);
00192 _data->get_connected_shading();
00193
00194
00195
00196
00197
00198 separate_switches(_data);
00199
00200 if (egg_emulate_bface) {
00201 emulate_bface(_data);
00202 }
00203
00204
00205 _data->remove_invalid_primitives(true);
00206 EggBinner binner(*this);
00207 binner.make_bins(_data);
00208
00209
00210
00211
00212 _root = new ModelRoot(_data->get_egg_filename().get_basename());
00213 make_node(_data, _root);
00214
00215 reparent_decals();
00216 start_sequences();
00217
00218 apply_deferred_nodes(_root, DeferredNodeProperty());
00219 }
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229 void EggLoader::
00230 reparent_decals() {
00231 ExtraNodes::const_iterator di;
00232 for (di = _decals.begin(); di != _decals.end(); ++di) {
00233 PandaNode *node = (*di);
00234 nassertv(node != (PandaNode *)NULL);
00235
00236
00237 NodePath parent(node);
00238
00239
00240 NodePath geom_parent;
00241 int num_children = parent.get_num_children();
00242 for (int i = 0; i < num_children; i++) {
00243 NodePath child = parent.get_child(i);
00244
00245 if (child.node()->is_of_type(GeomNode::get_class_type())) {
00246 if (!geom_parent.is_empty()) {
00247
00248 egg2pg_cat.error()
00249 << "Decal onto " << parent.node()->get_name()
00250 << " uses base geometry with multiple GeomNodes.\n";
00251 _error = true;
00252 }
00253 geom_parent = child;
00254 }
00255 }
00256
00257 if (geom_parent.is_empty()) {
00258
00259 egg2pg_cat.error()
00260 << "Ignoring decal onto " << parent.node()->get_name()
00261 << "; no geometry within group.\n";
00262 _error = true;
00263 } else {
00264
00265
00266
00267 int i = 0;
00268 while (i < num_children) {
00269 NodePath child = parent.get_child(i);
00270
00271 if (child.node()->is_of_type(GeomNode::get_class_type())) {
00272 i++;
00273 } else {
00274 child.reparent_to(geom_parent);
00275 num_children--;
00276 }
00277 }
00278
00279
00280 geom_parent.node()->set_effect(DecalEffect::make());
00281 }
00282 }
00283 }
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294 void EggLoader::
00295 start_sequences() {
00296 ExtraNodes::const_iterator ni;
00297 for (ni = _sequences.begin(); ni != _sequences.end(); ++ni) {
00298 SequenceNode *node = DCAST(SequenceNode, (*ni));
00299 node->loop(true);
00300 }
00301 }
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313 void EggLoader::
00314 make_polyset(EggBin *egg_bin, PandaNode *parent, const LMatrix4d *transform,
00315 bool is_dynamic, CharacterMaker *character_maker) {
00316 if (egg_bin->empty()) {
00317
00318 return;
00319 }
00320
00321
00322
00323
00324 EggGroupNode::const_iterator ci = egg_bin->begin();
00325 nassertv(ci != egg_bin->end());
00326 CPT(EggPrimitive) first_prim = DCAST(EggPrimitive, (*ci));
00327 nassertv(first_prim != (EggPrimitive *)NULL);
00328 const EggRenderState *render_state;
00329 DCAST_INTO_V(render_state, first_prim->get_user_data(EggRenderState::get_class_type()));
00330
00331 if (render_state->_hidden && egg_suppress_hidden) {
00332
00333 return;
00334 }
00335
00336
00337
00338
00339
00340 EggVertexPools vertex_pools;
00341 egg_bin->rebuild_vertex_pools(vertex_pools, (unsigned int)egg_max_vertices,
00342 false);
00343
00344 if (egg_mesh) {
00345
00346 egg_bin->mesh_triangles(render_state->_flat_shaded ? EggGroupNode::T_flat_shaded : 0);
00347
00348 } else {
00349
00350
00351 egg_bin->triangulate_polygons(EggGroupNode::T_polygon | EggGroupNode::T_convex);
00352 }
00353
00354
00355
00356 egg_bin->apply_first_attribute(false);
00357 egg_bin->post_apply_flat_attribute(false);
00358
00359
00360
00361 PT(GeomNode) geom_node;
00362
00363
00364
00365
00366
00367 EggVertexPools::iterator vpi;
00368 for (vpi = vertex_pools.begin(); vpi != vertex_pools.end(); ++vpi) {
00369 EggVertexPool *vertex_pool = (*vpi);
00370 vertex_pool->remove_unused_vertices();
00371
00372
00373 bool has_overall_color;
00374 LColor overall_color;
00375 vertex_pool->check_overall_color(has_overall_color, overall_color);
00376 if (!egg_flat_colors) {
00377
00378
00379
00380 has_overall_color = false;
00381 }
00382
00383 PT(TransformBlendTable) blend_table;
00384 if (is_dynamic) {
00385
00386
00387 blend_table = make_blend_table(vertex_pool, egg_bin, character_maker);
00388
00389
00390
00391
00392
00393
00394 vertex_pool->sort_by_external_index();
00395 }
00396
00397
00398
00399 UniquePrimitives unique_primitives;
00400 Primitives primitives;
00401 for (ci = egg_bin->begin(); ci != egg_bin->end(); ++ci) {
00402 EggPrimitive *egg_prim;
00403 DCAST_INTO_V(egg_prim, (*ci));
00404 if (egg_prim->get_pool() == vertex_pool) {
00405 make_primitive(render_state, egg_prim, unique_primitives, primitives,
00406 has_overall_color, overall_color);
00407 }
00408 }
00409
00410 if (!primitives.empty()) {
00411 LMatrix4d mat;
00412 if (transform != NULL) {
00413 mat = (*transform);
00414 } else {
00415 mat = egg_bin->get_vertex_to_node();
00416 }
00417
00418
00419 PT(GeomVertexData) vertex_data =
00420 make_vertex_data(render_state, vertex_pool, egg_bin, mat, blend_table,
00421 is_dynamic, character_maker, has_overall_color);
00422 nassertv(vertex_data != (GeomVertexData *)NULL);
00423
00424
00425 PT(Geom) geom = new Geom(vertex_data);
00426
00427
00428 Primitives::const_iterator pi;
00429 for (pi = primitives.begin(); pi != primitives.end(); ++pi) {
00430 PT(GeomPrimitive) primitive = (*pi);
00431
00432 if (primitive->is_indexed()) {
00433
00434
00435 primitive->reserve_num_vertices(primitive->get_num_vertices());
00436 }
00437
00438 geom->add_primitive(primitive);
00439 }
00440
00441
00442
00443
00444
00445
00446 if (geom_node == (GeomNode *)NULL) {
00447
00448
00449
00450 if (parent->is_geom_node() && !render_state->_hidden) {
00451 geom_node = DCAST(GeomNode, parent);
00452
00453 } else {
00454 geom_node = new GeomNode(egg_bin->get_name());
00455 if (render_state->_hidden) {
00456 parent->add_stashed(geom_node);
00457 } else {
00458 parent->add_child(geom_node);
00459 }
00460 }
00461 }
00462
00463 CPT(RenderState) geom_state = render_state->_state;
00464 if (has_overall_color) {
00465 if (!overall_color.almost_equal(LColor(1.0f, 1.0f, 1.0f, 1.0f))) {
00466 geom_state = geom_state->add_attrib(ColorAttrib::make_flat(overall_color), -1);
00467 }
00468 } else {
00469 geom_state = geom_state->add_attrib(ColorAttrib::make_vertex(), -1);
00470 }
00471
00472 geom_node->add_geom(geom, geom_state);
00473 }
00474 }
00475
00476 if (geom_node != (GeomNode *)NULL && egg_show_normals) {
00477
00478 for (vpi = vertex_pools.begin(); vpi != vertex_pools.end(); ++vpi) {
00479 EggVertexPool *vertex_pool = (*vpi);
00480 show_normals(vertex_pool, geom_node);
00481 }
00482 }
00483 }
00484
00485
00486
00487
00488
00489
00490
00491 CPT(TransformState) EggLoader::
00492 make_transform(const EggTransform *egg_transform) {
00493
00494
00495
00496 CPT(TransformState) ts = TransformState::make_identity();
00497 int num_components = egg_transform->get_num_components();
00498 for (int i = 0; i < num_components; i++) {
00499 switch (egg_transform->get_component_type(i)) {
00500 case EggTransform::CT_translate2d:
00501 {
00502 LVecBase2 trans2d(LCAST(PN_stdfloat, egg_transform->get_component_vec2(i)));
00503 LVecBase3 trans3d(trans2d[0], trans2d[1], 0.0f);
00504 ts = TransformState::make_pos(trans3d)->compose(ts);
00505 }
00506 break;
00507
00508 case EggTransform::CT_translate3d:
00509 {
00510 LVecBase3 trans3d(LCAST(PN_stdfloat, egg_transform->get_component_vec3(i)));
00511 ts = TransformState::make_pos(trans3d)->compose(ts);
00512 }
00513 break;
00514
00515 case EggTransform::CT_rotate2d:
00516 {
00517 LRotation rot(LVector3(0.0f, 0.0f, 1.0f),
00518 (PN_stdfloat)egg_transform->get_component_number(i));
00519 ts = TransformState::make_quat(rot)->compose(ts);
00520 }
00521 break;
00522
00523 case EggTransform::CT_rotx:
00524 {
00525 LRotation rot(LVector3(1.0f, 0.0f, 0.0f),
00526 (PN_stdfloat)egg_transform->get_component_number(i));
00527 ts = TransformState::make_quat(rot)->compose(ts);
00528 }
00529 break;
00530
00531 case EggTransform::CT_roty:
00532 {
00533 LRotation rot(LVector3(0.0f, 1.0f, 0.0f),
00534 (PN_stdfloat)egg_transform->get_component_number(i));
00535 ts = TransformState::make_quat(rot)->compose(ts);
00536 }
00537 break;
00538
00539 case EggTransform::CT_rotz:
00540 {
00541 LRotation rot(LVector3(0.0f, 0.0f, 1.0f),
00542 (PN_stdfloat)egg_transform->get_component_number(i));
00543 ts = TransformState::make_quat(rot)->compose(ts);
00544 }
00545 break;
00546
00547 case EggTransform::CT_rotate3d:
00548 {
00549 LRotation rot(LCAST(PN_stdfloat, egg_transform->get_component_vec3(i)),
00550 (PN_stdfloat)egg_transform->get_component_number(i));
00551 ts = TransformState::make_quat(rot)->compose(ts);
00552 }
00553 break;
00554
00555 case EggTransform::CT_scale2d:
00556 {
00557 LVecBase2 scale2d(LCAST(PN_stdfloat, egg_transform->get_component_vec2(i)));
00558 LVecBase3 scale3d(scale2d[0], scale2d[1], 1.0f);
00559 ts = TransformState::make_scale(scale3d)->compose(ts);
00560 }
00561 break;
00562
00563 case EggTransform::CT_scale3d:
00564 {
00565 LVecBase3 scale3d(LCAST(PN_stdfloat, egg_transform->get_component_vec3(i)));
00566 ts = TransformState::make_scale(scale3d)->compose(ts);
00567 }
00568 break;
00569
00570 case EggTransform::CT_uniform_scale:
00571 {
00572 PN_stdfloat scale = (PN_stdfloat)egg_transform->get_component_number(i);
00573 ts = TransformState::make_scale(scale)->compose(ts);
00574 }
00575 break;
00576
00577 case EggTransform::CT_matrix3:
00578 {
00579 LMatrix3 m(LCAST(PN_stdfloat, egg_transform->get_component_mat3(i)));
00580 LMatrix4 mat4(m(0, 0), m(0, 1), 0.0, m(0, 2),
00581 m(1, 0), m(1, 1), 0.0, m(1, 2),
00582 0.0, 0.0, 1.0, 0.0,
00583 m(2, 0), m(2, 1), 0.0, m(2, 2));
00584
00585 ts = TransformState::make_mat(mat4)->compose(ts);
00586 }
00587 break;
00588
00589 case EggTransform::CT_matrix4:
00590 {
00591 LMatrix4 mat4(LCAST(PN_stdfloat, egg_transform->get_component_mat4(i)));
00592 ts = TransformState::make_mat(mat4)->compose(ts);
00593 }
00594 break;
00595
00596 case EggTransform::CT_invalid:
00597 nassertr(false, ts);
00598 break;
00599 }
00600 }
00601
00602 if (ts->components_given()) {
00603 return ts;
00604 }
00605
00606
00607
00608
00609
00610
00611
00612 TransformStates::iterator tsi = _transform_states.insert(TransformStates::value_type(ts->get_mat(), ts)).first;
00613
00614 return (*tsi).second;
00615 }
00616
00617
00618
00619
00620
00621
00622
00623
00624 void EggLoader::
00625 show_normals(EggVertexPool *vertex_pool, GeomNode *geom_node) {
00626 PT(GeomPrimitive) primitive = new GeomLines(Geom::UH_static);
00627 CPT(GeomVertexFormat) format = GeomVertexFormat::get_v3cp();
00628 PT(GeomVertexData) vertex_data =
00629 new GeomVertexData(vertex_pool->get_name(), format, Geom::UH_static);
00630
00631 GeomVertexWriter vertex(vertex_data, InternalName::get_vertex());
00632 GeomVertexWriter color(vertex_data, InternalName::get_color());
00633
00634 EggVertexPool::const_iterator vi;
00635 for (vi = vertex_pool->begin(); vi != vertex_pool->end(); ++vi) {
00636 EggVertex *vert = (*vi);
00637 LPoint3d pos = vert->get_pos3();
00638
00639 if (vert->has_normal()) {
00640 vertex.add_data3d(pos);
00641 vertex.add_data3d(pos + vert->get_normal() * egg_normal_scale);
00642 color.add_data4(1.0f, 0.0f, 0.0f, 1.0f);
00643 color.add_data4(1.0f, 0.0f, 0.0f, 1.0f);
00644 primitive->add_next_vertices(2);
00645 primitive->close_primitive();
00646 }
00647
00648
00649
00650 EggVertex::const_uv_iterator uvi;
00651 for (uvi = vert->uv_begin(); uvi != vert->uv_end(); ++uvi) {
00652 EggVertexUV *uv_obj = (*uvi);
00653 if (uv_obj->has_tangent()) {
00654 vertex.add_data3d(pos);
00655 vertex.add_data3d(pos + uv_obj->get_tangent() * egg_normal_scale);
00656 color.add_data4(0.0f, 1.0f, 0.0f, 1.0f);
00657 color.add_data4(0.0f, 1.0f, 0.0f, 1.0f);
00658 primitive->add_next_vertices(2);
00659 primitive->close_primitive();
00660 }
00661 if (uv_obj->has_binormal()) {
00662 vertex.add_data3d(pos);
00663 vertex.add_data3d(pos + uv_obj->get_binormal() * egg_normal_scale);
00664 color.add_data4(0.0f, 0.0f, 1.0f, 1.0f);
00665 color.add_data4(0.0f, 0.0f, 1.0f, 1.0f);
00666 primitive->add_next_vertices(2);
00667 primitive->close_primitive();
00668 }
00669 }
00670 }
00671
00672 PT(Geom) geom = new Geom(vertex_data);
00673 geom->add_primitive(primitive);
00674 geom_node->add_geom(geom);
00675 }
00676
00677
00678
00679
00680
00681
00682 void EggLoader::
00683 make_nurbs_curve(EggNurbsCurve *egg_curve, PandaNode *parent,
00684 const LMatrix4d &mat) {
00685 if (egg_load_old_curves) {
00686
00687 make_old_nurbs_curve(egg_curve, parent, mat);
00688 return;
00689 }
00690
00691 assert(parent != NULL);
00692 assert(!parent->is_geom_node());
00693
00694 PT(NurbsCurveEvaluator) nurbs = ::make_nurbs_curve(egg_curve, mat);
00695 if (nurbs == (NurbsCurveEvaluator *)NULL) {
00696 _error = true;
00697 return;
00698 }
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719 PT(RopeNode) rope = new RopeNode(egg_curve->get_name());
00720 rope->set_curve(nurbs);
00721
00722
00723 if (egg_curve->get_subdiv() != 0) {
00724 int subdiv_per_segment =
00725 (int)((egg_curve->get_subdiv() + 0.5) / nurbs->get_num_segments());
00726 rope->set_num_subdiv(max(subdiv_per_segment, 1));
00727 }
00728
00729 const EggRenderState *render_state;
00730 DCAST_INTO_V(render_state, egg_curve->get_user_data(EggRenderState::get_class_type()));
00731 if (render_state->_hidden && egg_suppress_hidden) {
00732
00733 return;
00734 }
00735
00736 rope->set_state(render_state->_state);
00737 rope->set_uv_mode(RopeNode::UV_parametric);
00738
00739 if (egg_curve->has_vertex_color()) {
00740
00741 rope->set_use_vertex_color(true);
00742 } else if (egg_curve->has_color()) {
00743
00744 rope->set_attrib(ColorAttrib::make_flat(egg_curve->get_color()));
00745 }
00746
00747 parent->add_child(rope);
00748 }
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758 void EggLoader::
00759 make_old_nurbs_curve(EggNurbsCurve *egg_curve, PandaNode *parent,
00760 const LMatrix4d &mat) {
00761 assert(parent != NULL);
00762 assert(!parent->is_geom_node());
00763
00764 PT(ParametricCurve) curve;
00765 curve = new NurbsCurve;
00766
00767 NurbsCurveInterface *nurbs = curve->get_nurbs_interface();
00768 nassertv(nurbs != (NurbsCurveInterface *)NULL);
00769
00770 if (egg_curve->get_order() < 1 || egg_curve->get_order() > 4) {
00771 egg2pg_cat.error()
00772 << "Invalid NURBSCurve order for " << egg_curve->get_name() << ": "
00773 << egg_curve->get_order() << "\n";
00774 _error = true;
00775 return;
00776 }
00777
00778 nurbs->set_order(egg_curve->get_order());
00779
00780 EggPrimitive::const_iterator pi;
00781 for (pi = egg_curve->begin(); pi != egg_curve->end(); ++pi) {
00782 nurbs->append_cv(LCAST(PN_stdfloat, (*pi)->get_pos4() * mat));
00783 }
00784
00785 int num_knots = egg_curve->get_num_knots();
00786 if (num_knots != nurbs->get_num_knots()) {
00787 egg2pg_cat.error()
00788 << "Invalid NURBSCurve number of knots for "
00789 << egg_curve->get_name() << ": got " << num_knots
00790 << " knots, expected " << nurbs->get_num_knots() << "\n";
00791 _error = true;
00792 return;
00793 }
00794
00795 for (int i = 0; i < num_knots; i++) {
00796 nurbs->set_knot(i, egg_curve->get_knot(i));
00797 }
00798
00799 switch (egg_curve->get_curve_type()) {
00800 case EggCurve::CT_xyz:
00801 curve->set_curve_type(PCT_XYZ);
00802 break;
00803
00804 case EggCurve::CT_hpr:
00805 curve->set_curve_type(PCT_HPR);
00806 break;
00807
00808 case EggCurve::CT_t:
00809 curve->set_curve_type(PCT_T);
00810 break;
00811
00812 default:
00813 break;
00814 }
00815 curve->set_name(egg_curve->get_name());
00816
00817 if (!curve->recompute()) {
00818 egg2pg_cat.error()
00819 << "Invalid NURBSCurve " << egg_curve->get_name() << "\n";
00820 _error = true;
00821 return;
00822 }
00823
00824 parent->add_child(curve);
00825 }
00826
00827
00828
00829
00830
00831
00832 void EggLoader::
00833 make_nurbs_surface(EggNurbsSurface *egg_surface, PandaNode *parent,
00834 const LMatrix4d &mat) {
00835 assert(parent != NULL);
00836 assert(!parent->is_geom_node());
00837
00838 PT(NurbsSurfaceEvaluator) nurbs = ::make_nurbs_surface(egg_surface, mat);
00839 if (nurbs == (NurbsSurfaceEvaluator *)NULL) {
00840 _error = true;
00841 return;
00842 }
00843
00844 PT(SheetNode) sheet = new SheetNode(egg_surface->get_name());
00845 sheet->set_surface(nurbs);
00846
00847
00848 if (egg_surface->get_u_subdiv() != 0) {
00849 int u_subdiv_per_segment =
00850 (int)((egg_surface->get_u_subdiv() + 0.5) / nurbs->get_num_u_segments());
00851 sheet->set_num_u_subdiv(max(u_subdiv_per_segment, 1));
00852 }
00853 if (egg_surface->get_v_subdiv() != 0) {
00854 int v_subdiv_per_segment =
00855 (int)((egg_surface->get_v_subdiv() + 0.5) / nurbs->get_num_v_segments());
00856 sheet->set_num_v_subdiv(max(v_subdiv_per_segment, 1));
00857 }
00858
00859 const EggRenderState *render_state;
00860 DCAST_INTO_V(render_state, egg_surface->get_user_data(EggRenderState::get_class_type()));
00861 if (render_state->_hidden && egg_suppress_hidden) {
00862
00863 return;
00864 }
00865
00866 sheet->set_state(render_state->_state);
00867
00868 if (egg_surface->has_vertex_color()) {
00869
00870 sheet->set_use_vertex_color(true);
00871 } else if (egg_surface->has_color()) {
00872
00873 sheet->set_attrib(ColorAttrib::make_flat(egg_surface->get_color()));
00874 }
00875
00876 parent->add_child(sheet);
00877 }
00878
00879
00880
00881
00882
00883
00884 void EggLoader::
00885 load_textures() {
00886
00887 EggTextureCollection tc;
00888 tc.find_used_textures(_data);
00889
00890 EggTextureCollection::iterator ti;
00891 for (ti = tc.begin(); ti != tc.end(); ++ti) {
00892 PT_EggTexture egg_tex = (*ti);
00893
00894 TextureDef def;
00895 if (load_texture(def, egg_tex)) {
00896
00897
00898 _textures[egg_tex] = def;
00899 }
00900 }
00901 }
00902
00903
00904
00905
00906
00907
00908
00909 bool EggLoader::
00910 load_texture(TextureDef &def, EggTexture *egg_tex) {
00911
00912
00913 int wanted_channels = 0;
00914 bool wanted_alpha = false;
00915 switch (egg_tex->get_format()) {
00916 case EggTexture::F_red:
00917 case EggTexture::F_green:
00918 case EggTexture::F_blue:
00919 case EggTexture::F_alpha:
00920 case EggTexture::F_luminance:
00921 wanted_channels = 1;
00922 wanted_alpha = false;
00923 break;
00924
00925 case EggTexture::F_luminance_alpha:
00926 case EggTexture::F_luminance_alphamask:
00927 wanted_channels = 2;
00928 wanted_alpha = true;
00929 break;
00930
00931 case EggTexture::F_rgb:
00932 case EggTexture::F_rgb12:
00933 case EggTexture::F_rgb8:
00934 case EggTexture::F_rgb5:
00935 case EggTexture::F_rgb332:
00936 wanted_channels = 3;
00937 wanted_alpha = false;
00938 break;
00939
00940 case EggTexture::F_rgba:
00941 case EggTexture::F_rgbm:
00942 case EggTexture::F_rgba12:
00943 case EggTexture::F_rgba8:
00944 case EggTexture::F_rgba4:
00945 case EggTexture::F_rgba5:
00946 wanted_channels = 4;
00947 wanted_alpha = true;
00948 break;
00949
00950 case EggTexture::F_unspecified:
00951 wanted_alpha = egg_tex->has_alpha_filename();
00952 }
00953
00954
00955
00956
00957
00958 if (_record != (BamCacheRecord *)NULL) {
00959 _record->add_dependent_file(egg_tex->get_fullpath());
00960 if (egg_tex->has_alpha_filename() && wanted_alpha) {
00961 _record->add_dependent_file(egg_tex->get_alpha_fullpath());
00962 }
00963 }
00964
00965
00966 LoaderOptions options;
00967 if (egg_preload_simple_textures) {
00968 options.set_texture_flags(options.get_texture_flags() | LoaderOptions::TF_preload_simple);
00969 }
00970
00971 if (!egg_ignore_filters && !egg_ignore_mipmaps) {
00972 switch (egg_tex->get_minfilter()) {
00973 case EggTexture::FT_nearest:
00974 case EggTexture::FT_linear:
00975 case EggTexture::FT_unspecified:
00976 break;
00977
00978 case EggTexture::FT_nearest_mipmap_nearest:
00979 case EggTexture::FT_linear_mipmap_nearest:
00980 case EggTexture::FT_nearest_mipmap_linear:
00981 case EggTexture::FT_linear_mipmap_linear:
00982 options.set_texture_flags(options.get_texture_flags() | LoaderOptions::TF_generate_mipmaps);
00983 }
00984 }
00985
00986 if (egg_tex->get_multiview()) {
00987 options.set_texture_flags(options.get_texture_flags() | LoaderOptions::TF_multiview);
00988 if (egg_tex->has_num_views()) {
00989 options.set_texture_num_views(egg_tex->get_num_views());
00990 }
00991 }
00992
00993 PT(Texture) tex;
00994 switch (egg_tex->get_texture_type()) {
00995 case EggTexture::TT_unspecified:
00996 case EggTexture::TT_1d_texture:
00997 options.set_texture_flags(options.get_texture_flags() | LoaderOptions::TF_allow_1d);
00998
00999
01000 case EggTexture::TT_2d_texture:
01001 if (egg_tex->has_alpha_filename() && wanted_alpha) {
01002 tex = TexturePool::load_texture(egg_tex->get_fullpath(),
01003 egg_tex->get_alpha_fullpath(),
01004 wanted_channels,
01005 egg_tex->get_alpha_file_channel(),
01006 egg_tex->get_read_mipmaps(), options);
01007 } else {
01008 tex = TexturePool::load_texture(egg_tex->get_fullpath(),
01009 wanted_channels,
01010 egg_tex->get_read_mipmaps(), options);
01011 }
01012 break;
01013
01014 case EggTexture::TT_3d_texture:
01015 tex = TexturePool::load_3d_texture(egg_tex->get_fullpath(),
01016 egg_tex->get_read_mipmaps(), options);
01017 break;
01018
01019 case EggTexture::TT_cube_map:
01020 tex = TexturePool::load_cube_map(egg_tex->get_fullpath(),
01021 egg_tex->get_read_mipmaps(), options);
01022 break;
01023 }
01024
01025 if (tex == (Texture *)NULL) {
01026 return false;
01027 }
01028
01029
01030
01031
01032 tex->set_filename(egg_tex->get_filename());
01033 if (egg_tex->has_alpha_filename() && wanted_alpha) {
01034 tex->set_alpha_filename(egg_tex->get_alpha_filename());
01035 }
01036
01037
01038
01039 TypedReferenceCount *aux = tex->get_aux_data("egg");
01040 if (aux != (TypedReferenceCount *)NULL &&
01041 aux->is_of_type(EggTexture::get_class_type())) {
01042 EggTexture *aux_egg_tex = DCAST(EggTexture, aux);
01043
01044 if (aux_egg_tex->get_alpha_mode() != EggTexture::AM_unspecified) {
01045 egg_tex->set_alpha_mode(aux_egg_tex->get_alpha_mode());
01046 }
01047 if (aux_egg_tex->get_format() != EggTexture::F_unspecified) {
01048 egg_tex->set_format(aux_egg_tex->get_format());
01049 }
01050 if (aux_egg_tex->get_minfilter() != EggTexture::FT_unspecified) {
01051 egg_tex->set_minfilter(aux_egg_tex->get_minfilter());
01052 }
01053 if (aux_egg_tex->get_magfilter() != EggTexture::FT_unspecified) {
01054 egg_tex->set_magfilter(aux_egg_tex->get_magfilter());
01055 }
01056 if (aux_egg_tex->has_anisotropic_degree()) {
01057 egg_tex->set_anisotropic_degree(aux_egg_tex->get_anisotropic_degree());
01058 }
01059 }
01060
01061 apply_texture_attributes(tex, egg_tex);
01062
01063
01064 PT(TextureStage) stage = make_texture_stage(egg_tex);
01065 def._texture = DCAST(TextureAttrib, TextureAttrib::make())->add_on_stage(stage, tex);
01066 def._stage = stage;
01067 def._egg_tex = egg_tex;
01068
01069 return true;
01070 }
01071
01072
01073
01074
01075
01076
01077
01078 void EggLoader::
01079 apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) {
01080 if (egg_tex->get_compression_mode() != EggTexture::CM_default) {
01081 tex->set_compression(convert_compression_mode(egg_tex->get_compression_mode()));
01082 }
01083
01084 EggTexture::WrapMode wrap_u = egg_tex->determine_wrap_u();
01085 EggTexture::WrapMode wrap_v = egg_tex->determine_wrap_v();
01086 EggTexture::WrapMode wrap_w = egg_tex->determine_wrap_w();
01087
01088 if (wrap_u != EggTexture::WM_unspecified) {
01089 tex->set_wrap_u(convert_wrap_mode(wrap_u));
01090 }
01091 if (wrap_v != EggTexture::WM_unspecified) {
01092 tex->set_wrap_v(convert_wrap_mode(wrap_v));
01093 }
01094 if (wrap_w != EggTexture::WM_unspecified) {
01095 tex->set_wrap_w(convert_wrap_mode(wrap_w));
01096 }
01097
01098 if (egg_tex->has_border_color()) {
01099 tex->set_border_color(egg_tex->get_border_color());
01100 }
01101
01102 switch (egg_tex->get_minfilter()) {
01103 case EggTexture::FT_nearest:
01104 tex->set_minfilter(Texture::FT_nearest);
01105 break;
01106
01107 case EggTexture::FT_linear:
01108 if (egg_ignore_filters) {
01109 egg2pg_cat.warning()
01110 << "Ignoring minfilter request\n";
01111 tex->set_minfilter(Texture::FT_nearest);
01112 } else {
01113 tex->set_minfilter(Texture::FT_linear);
01114 }
01115 break;
01116
01117 case EggTexture::FT_nearest_mipmap_nearest:
01118 if (egg_ignore_filters) {
01119 egg2pg_cat.warning()
01120 << "Ignoring minfilter request\n";
01121 tex->set_minfilter(Texture::FT_nearest);
01122 } else if (egg_ignore_mipmaps) {
01123 egg2pg_cat.warning()
01124 << "Ignoring mipmap request\n";
01125 tex->set_minfilter(Texture::FT_nearest);
01126 } else {
01127 tex->set_minfilter(Texture::FT_nearest_mipmap_nearest);
01128 }
01129 break;
01130
01131 case EggTexture::FT_linear_mipmap_nearest:
01132 if (egg_ignore_filters) {
01133 egg2pg_cat.warning()
01134 << "Ignoring minfilter request\n";
01135 tex->set_minfilter(Texture::FT_nearest);
01136 } else if (egg_ignore_mipmaps) {
01137 egg2pg_cat.warning()
01138 << "Ignoring mipmap request\n";
01139 tex->set_minfilter(Texture::FT_linear);
01140 } else {
01141 tex->set_minfilter(Texture::FT_linear_mipmap_nearest);
01142 }
01143 break;
01144
01145 case EggTexture::FT_nearest_mipmap_linear:
01146 if (egg_ignore_filters) {
01147 egg2pg_cat.warning()
01148 << "Ignoring minfilter request\n";
01149 tex->set_minfilter(Texture::FT_nearest);
01150 } else if (egg_ignore_mipmaps) {
01151 egg2pg_cat.warning()
01152 << "Ignoring mipmap request\n";
01153 tex->set_minfilter(Texture::FT_nearest);
01154 } else {
01155 tex->set_minfilter(Texture::FT_nearest_mipmap_linear);
01156 }
01157 break;
01158
01159 case EggTexture::FT_linear_mipmap_linear:
01160 if (egg_ignore_filters) {
01161 egg2pg_cat.warning()
01162 << "Ignoring minfilter request\n";
01163 tex->set_minfilter(Texture::FT_nearest);
01164 } else if (egg_ignore_mipmaps) {
01165 egg2pg_cat.warning()
01166 << "Ignoring mipmap request\n";
01167 tex->set_minfilter(Texture::FT_linear);
01168 } else {
01169 tex->set_minfilter(Texture::FT_linear_mipmap_linear);
01170 }
01171 break;
01172
01173 case EggTexture::FT_unspecified:
01174 break;
01175 }
01176
01177 switch (egg_tex->get_magfilter()) {
01178 case EggTexture::FT_nearest:
01179 case EggTexture::FT_nearest_mipmap_nearest:
01180 case EggTexture::FT_nearest_mipmap_linear:
01181 tex->set_magfilter(Texture::FT_nearest);
01182 break;
01183
01184 case EggTexture::FT_linear:
01185 case EggTexture::FT_linear_mipmap_nearest:
01186 case EggTexture::FT_linear_mipmap_linear:
01187 if (egg_ignore_filters) {
01188 egg2pg_cat.warning()
01189 << "Ignoring magfilter request\n";
01190 tex->set_magfilter(Texture::FT_nearest);
01191 } else {
01192 tex->set_magfilter(Texture::FT_linear);
01193 }
01194 break;
01195
01196 case EggTexture::FT_unspecified:
01197 break;
01198 }
01199
01200 if (egg_tex->has_anisotropic_degree()) {
01201 tex->set_anisotropic_degree(egg_tex->get_anisotropic_degree());
01202 }
01203
01204 if (tex->get_num_components() == 1) {
01205 switch (egg_tex->get_format()) {
01206 case EggTexture::F_red:
01207 tex->set_format(Texture::F_red);
01208 break;
01209 case EggTexture::F_green:
01210 tex->set_format(Texture::F_green);
01211 break;
01212 case EggTexture::F_blue:
01213 tex->set_format(Texture::F_blue);
01214 break;
01215 case EggTexture::F_alpha:
01216 tex->set_format(Texture::F_alpha);
01217 break;
01218 case EggTexture::F_luminance:
01219 tex->set_format(Texture::F_luminance);
01220 break;
01221
01222 case EggTexture::F_unspecified:
01223 break;
01224
01225 default:
01226 egg2pg_cat.warning()
01227 << "Ignoring inappropriate format " << egg_tex->get_format()
01228 << " for 1-component texture " << egg_tex->get_name() << "\n";
01229 }
01230
01231 } else if (tex->get_num_components() == 2) {
01232 switch (egg_tex->get_format()) {
01233 case EggTexture::F_luminance_alpha:
01234 tex->set_format(Texture::F_luminance_alpha);
01235 break;
01236
01237 case EggTexture::F_luminance_alphamask:
01238 tex->set_format(Texture::F_luminance_alphamask);
01239 break;
01240
01241 case EggTexture::F_unspecified:
01242 break;
01243
01244 default:
01245 egg2pg_cat.warning()
01246 << "Ignoring inappropriate format " << egg_tex->get_format()
01247 << " for 2-component texture " << egg_tex->get_name() << "\n";
01248 }
01249
01250 } else if (tex->get_num_components() == 3) {
01251 switch (egg_tex->get_format()) {
01252 case EggTexture::F_rgb:
01253 tex->set_format(Texture::F_rgb);
01254 break;
01255 case EggTexture::F_rgb12:
01256 if (tex->get_component_width() >= 2) {
01257
01258 tex->set_format(Texture::F_rgb12);
01259 } else {
01260 egg2pg_cat.warning()
01261 << "Ignoring inappropriate format " << egg_tex->get_format()
01262 << " for 8-bit texture " << egg_tex->get_name() << "\n";
01263 }
01264 break;
01265 case EggTexture::F_rgb8:
01266 case EggTexture::F_rgba8:
01267
01268
01269
01270 tex->set_format(Texture::F_rgb8);
01271 break;
01272 case EggTexture::F_rgb5:
01273 tex->set_format(Texture::F_rgb5);
01274 break;
01275 case EggTexture::F_rgb332:
01276 tex->set_format(Texture::F_rgb332);
01277 break;
01278
01279 case EggTexture::F_unspecified:
01280 break;
01281
01282 default:
01283 egg2pg_cat.warning()
01284 << "Ignoring inappropriate format " << egg_tex->get_format()
01285 << " for 3-component texture " << egg_tex->get_name() << "\n";
01286 }
01287
01288 } else if (tex->get_num_components() == 4) {
01289 switch (egg_tex->get_format()) {
01290 case EggTexture::F_rgba:
01291 tex->set_format(Texture::F_rgba);
01292 break;
01293 case EggTexture::F_rgbm:
01294 tex->set_format(Texture::F_rgbm);
01295 break;
01296 case EggTexture::F_rgba12:
01297 if (tex->get_component_width() >= 2) {
01298
01299 tex->set_format(Texture::F_rgba12);
01300 } else {
01301 egg2pg_cat.warning()
01302 << "Ignoring inappropriate format " << egg_tex->get_format()
01303 << " for 8-bit texture " << egg_tex->get_name() << "\n";
01304 }
01305 break;
01306 case EggTexture::F_rgba8:
01307 tex->set_format(Texture::F_rgba8);
01308 break;
01309 case EggTexture::F_rgba4:
01310 tex->set_format(Texture::F_rgba4);
01311 break;
01312 case EggTexture::F_rgba5:
01313 tex->set_format(Texture::F_rgba5);
01314 break;
01315
01316 case EggTexture::F_unspecified:
01317 break;
01318
01319 default:
01320 egg2pg_cat.warning()
01321 << "Ignoring inappropriate format " << egg_tex->get_format()
01322 << " for 4-component texture " << egg_tex->get_name() << "\n";
01323 }
01324 }
01325
01326 switch (egg_tex->get_quality_level()) {
01327 case EggTexture::QL_unspecified:
01328 case EggTexture::QL_default:
01329 tex->set_quality_level(Texture::QL_default);
01330 break;
01331
01332 case EggTexture::QL_fastest:
01333 tex->set_quality_level(Texture::QL_fastest);
01334 break;
01335
01336 case EggTexture::QL_normal:
01337 tex->set_quality_level(Texture::QL_normal);
01338 break;
01339
01340 case EggTexture::QL_best:
01341 tex->set_quality_level(Texture::QL_best);
01342 break;
01343 }
01344 }
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354 Texture::CompressionMode EggLoader::
01355 convert_compression_mode(EggTexture::CompressionMode compression_mode) const {
01356 switch (compression_mode) {
01357 case EggTexture::CM_off:
01358 return Texture::CM_off;
01359
01360 case EggTexture::CM_on:
01361 return Texture::CM_on;
01362
01363 case EggTexture::CM_fxt1:
01364 return Texture::CM_fxt1;
01365
01366 case EggTexture::CM_dxt1:
01367 return Texture::CM_dxt1;
01368
01369 case EggTexture::CM_dxt2:
01370 return Texture::CM_dxt2;
01371
01372 case EggTexture::CM_dxt3:
01373 return Texture::CM_dxt3;
01374
01375 case EggTexture::CM_dxt4:
01376 return Texture::CM_dxt4;
01377
01378 case EggTexture::CM_dxt5:
01379 return Texture::CM_dxt5;
01380
01381 case EggTexture::CM_default:
01382 return Texture::CM_default;
01383 }
01384
01385 egg2pg_cat.warning()
01386 << "Unexpected texture compression flag: " << (int)compression_mode << "\n";
01387 return Texture::CM_default;
01388 }
01389
01390
01391
01392
01393
01394
01395
01396
01397 Texture::WrapMode EggLoader::
01398 convert_wrap_mode(EggTexture::WrapMode wrap_mode) const {
01399 switch (wrap_mode) {
01400 case EggTexture::WM_clamp:
01401 return Texture::WM_clamp;
01402
01403 case EggTexture::WM_repeat:
01404 return Texture::WM_repeat;
01405
01406 case EggTexture::WM_mirror:
01407 return Texture::WM_mirror;
01408
01409 case EggTexture::WM_mirror_once:
01410 return Texture::WM_mirror_once;
01411
01412 case EggTexture::WM_border_color:
01413 return Texture::WM_border_color;
01414
01415 case EggTexture::WM_unspecified:
01416 return Texture::WM_repeat;
01417 }
01418
01419 egg2pg_cat.warning()
01420 << "Unexpected texture wrap flag: " << (int)wrap_mode << "\n";
01421 return Texture::WM_repeat;
01422 }
01423
01424
01425
01426
01427
01428
01429
01430 PT(TextureStage) EggLoader::
01431 make_texture_stage(const EggTexture *egg_tex) {
01432
01433
01434
01435
01436 if (!egg_tex->has_stage_name() &&
01437 !egg_tex->has_uv_name() &&
01438 !egg_tex->has_color() &&
01439 (egg_tex->get_env_type() == EggTexture::ET_unspecified ||
01440 egg_tex->get_env_type() == EggTexture::ET_modulate) &&
01441 egg_tex->get_combine_mode(EggTexture::CC_rgb) == EggTexture::CM_unspecified &&
01442 egg_tex->get_combine_mode(EggTexture::CC_alpha) == EggTexture::CM_unspecified &&
01443
01444 !egg_tex->has_priority() &&
01445 egg_tex->get_multitexture_sort() == 0 &&
01446 !egg_tex->get_saved_result()) {
01447 return TextureStage::get_default();
01448 }
01449
01450 PT(TextureStage) stage = new TextureStage(egg_tex->get_stage_name());
01451
01452 switch (egg_tex->get_env_type()) {
01453 case EggTexture::ET_modulate:
01454 stage->set_mode(TextureStage::M_modulate);
01455 break;
01456
01457 case EggTexture::ET_decal:
01458 stage->set_mode(TextureStage::M_decal);
01459 break;
01460
01461 case EggTexture::ET_blend:
01462 stage->set_mode(TextureStage::M_blend);
01463 break;
01464
01465 case EggTexture::ET_replace:
01466 stage->set_mode(TextureStage::M_replace);
01467 break;
01468
01469 case EggTexture::ET_add:
01470 stage->set_mode(TextureStage::M_add);
01471 break;
01472
01473 case EggTexture::ET_blend_color_scale:
01474 stage->set_mode(TextureStage::M_blend_color_scale);
01475 break;
01476
01477 case EggTexture::ET_modulate_glow:
01478 stage->set_mode(TextureStage::M_modulate_glow);
01479 break;
01480
01481 case EggTexture::ET_modulate_gloss:
01482 stage->set_mode(TextureStage::M_modulate_gloss);
01483 break;
01484
01485 case EggTexture::ET_normal:
01486 stage->set_mode(TextureStage::M_normal);
01487 break;
01488
01489 case EggTexture::ET_normal_height:
01490 stage->set_mode(TextureStage::M_normal_height);
01491 break;
01492
01493 case EggTexture::ET_glow:
01494 stage->set_mode(TextureStage::M_glow);
01495 break;
01496
01497 case EggTexture::ET_gloss:
01498 stage->set_mode(TextureStage::M_gloss);
01499 break;
01500
01501 case EggTexture::ET_height:
01502 stage->set_mode(TextureStage::M_height);
01503 break;
01504
01505 case EggTexture::ET_selector:
01506 stage->set_mode(TextureStage::M_selector);
01507 break;
01508
01509 case EggTexture::ET_normal_gloss:
01510 stage->set_mode(TextureStage::M_normal_gloss);
01511 break;
01512
01513 case EggTexture::ET_unspecified:
01514 break;
01515 }
01516
01517 switch (egg_tex->get_combine_mode(EggTexture::CC_rgb)) {
01518 case EggTexture::CM_replace:
01519 stage->set_combine_rgb(get_combine_mode(egg_tex, EggTexture::CC_rgb),
01520 get_combine_source(egg_tex, EggTexture::CC_rgb, 0),
01521 get_combine_operand(egg_tex, EggTexture::CC_rgb, 0));
01522 break;
01523
01524 case EggTexture::CM_modulate:
01525 case EggTexture::CM_add:
01526 case EggTexture::CM_add_signed:
01527 case EggTexture::CM_subtract:
01528 case EggTexture::CM_dot3_rgb:
01529 case EggTexture::CM_dot3_rgba:
01530 stage->set_combine_rgb(get_combine_mode(egg_tex, EggTexture::CC_rgb),
01531 get_combine_source(egg_tex, EggTexture::CC_rgb, 0),
01532 get_combine_operand(egg_tex, EggTexture::CC_rgb, 0),
01533 get_combine_source(egg_tex, EggTexture::CC_rgb, 1),
01534 get_combine_operand(egg_tex, EggTexture::CC_rgb, 1));
01535 break;
01536
01537 case EggTexture::CM_interpolate:
01538 stage->set_combine_rgb(get_combine_mode(egg_tex, EggTexture::CC_rgb),
01539 get_combine_source(egg_tex, EggTexture::CC_rgb, 0),
01540 get_combine_operand(egg_tex, EggTexture::CC_rgb, 0),
01541 get_combine_source(egg_tex, EggTexture::CC_rgb, 1),
01542 get_combine_operand(egg_tex, EggTexture::CC_rgb, 1),
01543 get_combine_source(egg_tex, EggTexture::CC_rgb, 2),
01544 get_combine_operand(egg_tex, EggTexture::CC_rgb, 2));
01545 break;
01546
01547 case EggTexture::CM_unspecified:
01548 break;
01549 }
01550
01551 switch (egg_tex->get_combine_mode(EggTexture::CC_alpha)) {
01552 case EggTexture::CM_replace:
01553 stage->set_combine_alpha(get_combine_mode(egg_tex, EggTexture::CC_alpha),
01554 get_combine_source(egg_tex, EggTexture::CC_alpha, 0),
01555 get_combine_operand(egg_tex, EggTexture::CC_alpha, 0));
01556 break;
01557
01558 case EggTexture::CM_modulate:
01559 case EggTexture::CM_add:
01560 case EggTexture::CM_add_signed:
01561 case EggTexture::CM_subtract:
01562 stage->set_combine_alpha(get_combine_mode(egg_tex, EggTexture::CC_alpha),
01563 get_combine_source(egg_tex, EggTexture::CC_alpha, 0),
01564 get_combine_operand(egg_tex, EggTexture::CC_alpha, 0),
01565 get_combine_source(egg_tex, EggTexture::CC_alpha, 1),
01566 get_combine_operand(egg_tex, EggTexture::CC_alpha, 1));
01567 break;
01568
01569 case EggTexture::CM_interpolate:
01570 stage->set_combine_alpha(get_combine_mode(egg_tex, EggTexture::CC_alpha),
01571 get_combine_source(egg_tex, EggTexture::CC_alpha, 0),
01572 get_combine_operand(egg_tex, EggTexture::CC_alpha, 0),
01573 get_combine_source(egg_tex, EggTexture::CC_alpha, 1),
01574 get_combine_operand(egg_tex, EggTexture::CC_alpha, 1),
01575 get_combine_source(egg_tex, EggTexture::CC_alpha, 2),
01576 get_combine_operand(egg_tex, EggTexture::CC_alpha, 2));
01577 break;
01578
01579 case EggTexture::CM_unspecified:
01580 case EggTexture::CM_dot3_rgb:
01581 case EggTexture::CM_dot3_rgba:
01582 break;
01583 }
01584
01585
01586 if (egg_tex->has_uv_name()) {
01587 PT(InternalName) name =
01588 InternalName::get_texcoord_name(egg_tex->get_uv_name());
01589 stage->set_texcoord_name(name);
01590 }
01591
01592 if (egg_tex->has_rgb_scale()) {
01593 stage->set_rgb_scale(egg_tex->get_rgb_scale());
01594 }
01595
01596 if (egg_tex->has_alpha_scale()) {
01597 stage->set_alpha_scale(egg_tex->get_alpha_scale());
01598 }
01599
01600 stage->set_saved_result(egg_tex->get_saved_result());
01601
01602 stage->set_sort(egg_tex->get_multitexture_sort() * 10);
01603
01604 if (egg_tex->has_priority()) {
01605 stage->set_sort(egg_tex->get_priority());
01606 }
01607
01608 if (egg_tex->has_color()) {
01609 stage->set_color(egg_tex->get_color());
01610 }
01611
01612 return TextureStagePool::get_stage(stage);
01613 }
01614
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624 void EggLoader::
01625 separate_switches(EggNode *egg_node) {
01626 bool parent_has_switch = false;
01627 if (egg_node->is_of_type(EggGroup::get_class_type())) {
01628 EggGroup *egg_group = DCAST(EggGroup, egg_node);
01629 parent_has_switch = egg_group->get_switch_flag();
01630 }
01631
01632 if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
01633 EggGroupNode *egg_group = DCAST(EggGroupNode, egg_node);
01634
01635 EggGroupNode::iterator ci;
01636 ci = egg_group->begin();
01637 while (ci != egg_group->end()) {
01638 EggGroupNode::iterator cnext;
01639 cnext = ci;
01640 ++cnext;
01641
01642 PT(EggNode) child = (*ci);
01643 if (parent_has_switch &&
01644 child->is_of_type(EggPrimitive::get_class_type())) {
01645
01646 PT(EggGroup) new_group = new EggGroup(child->get_name());
01647 egg_group->replace(ci, new_group.p());
01648 new_group->add_child(child);
01649 }
01650
01651 separate_switches(child);
01652
01653 ci = cnext;
01654 }
01655 }
01656 }
01657
01658
01659
01660
01661
01662
01663
01664
01665
01666 void EggLoader::
01667 emulate_bface(EggNode *egg_node) {
01668 if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
01669 EggGroupNode *egg_group = DCAST(EggGroupNode, egg_node);
01670 PT(EggGroupNode) dup_prims = new EggGroupNode;
01671
01672 EggGroupNode::iterator ci;
01673 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
01674 PT(EggNode) child = (*ci);
01675 if (child->is_of_type(EggPolygon::get_class_type())) {
01676 EggPolygon *poly = DCAST(EggPolygon, child);
01677 if (poly->get_bface_flag()) {
01678 poly->set_bface_flag(false);
01679
01680 PT(EggPolygon) dup_poly = new EggPolygon(*poly);
01681 dup_poly->reverse_vertex_ordering();
01682 if (dup_poly->has_normal()) {
01683 dup_poly->set_normal(-dup_poly->get_normal());
01684 }
01685
01686
01687 EggPolygon::iterator vi;
01688 for (vi = dup_poly->begin(); vi != dup_poly->end(); ++vi) {
01689 EggVertex *vertex = (*vi);
01690 if (vertex->has_normal()) {
01691 EggVertex dup_vertex(*vertex);
01692 dup_vertex.set_normal(-dup_vertex.get_normal());
01693 EggVertex *new_vertex = vertex->get_pool()->create_unique_vertex(dup_vertex);
01694 if (new_vertex != vertex) {
01695 new_vertex->copy_grefs_from(*vertex);
01696 dup_poly->replace(vi, new_vertex);
01697 }
01698 }
01699 }
01700 dup_prims->add_child(dup_poly);
01701 }
01702 }
01703
01704 emulate_bface(child);
01705 }
01706
01707
01708
01709 egg_group->steal_children(*dup_prims);
01710 }
01711 }
01712
01713
01714
01715
01716
01717
01718 PandaNode *EggLoader::
01719 make_node(EggNode *egg_node, PandaNode *parent) {
01720 if (egg_node->is_of_type(EggBin::get_class_type())) {
01721 return make_node(DCAST(EggBin, egg_node), parent);
01722 } else if (egg_node->is_of_type(EggGroup::get_class_type())) {
01723 return make_node(DCAST(EggGroup, egg_node), parent);
01724 } else if (egg_node->is_of_type(EggTable::get_class_type())) {
01725 return make_node(DCAST(EggTable, egg_node), parent);
01726 } else if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
01727 return make_node(DCAST(EggGroupNode, egg_node), parent);
01728 }
01729
01730 return (PandaNode *)NULL;
01731 }
01732
01733
01734
01735
01736
01737
01738 PandaNode *EggLoader::
01739 make_node(EggBin *egg_bin, PandaNode *parent) {
01740
01741
01742
01743 switch (egg_bin->get_bin_number()) {
01744 case EggBinner::BN_polyset:
01745 make_polyset(egg_bin, parent, NULL, _dynamic_override, _dynamic_override_char_maker);
01746 return NULL;
01747
01748 case EggBinner::BN_lod:
01749 return make_lod(egg_bin, parent);
01750
01751 case EggBinner::BN_nurbs_surface:
01752 {
01753 nassertr(!egg_bin->empty(), NULL);
01754 EggNode *child = egg_bin->get_first_child();
01755 EggNurbsSurface *egg_nurbs;
01756 DCAST_INTO_R(egg_nurbs, child, NULL);
01757 const LMatrix4d &mat = egg_nurbs->get_vertex_to_node();
01758 make_nurbs_surface(egg_nurbs, parent, mat);
01759 }
01760 return NULL;
01761
01762 case EggBinner::BN_nurbs_curve:
01763 {
01764 nassertr(!egg_bin->empty(), NULL);
01765 EggNode *child = egg_bin->get_first_child();
01766 EggNurbsCurve *egg_nurbs;
01767 DCAST_INTO_R(egg_nurbs, child, NULL);
01768 const LMatrix4d &mat = egg_nurbs->get_vertex_to_node();
01769 make_nurbs_curve(egg_nurbs, parent, mat);
01770 }
01771 return NULL;
01772
01773 case EggBinner::BN_none:
01774 break;
01775 }
01776
01777
01778 return (PandaNode *)NULL;
01779 }
01780
01781
01782
01783
01784
01785
01786 PandaNode *EggLoader::
01787 make_lod(EggBin *egg_bin, PandaNode *parent) {
01788 PT(LODNode) lod_node = LODNode::make_default_lod(egg_bin->get_name());
01789
01790 pvector<LODInstance> instances;
01791
01792 EggGroup::const_iterator ci;
01793 for (ci = egg_bin->begin(); ci != egg_bin->end(); ++ci) {
01794 LODInstance instance(*ci);
01795 instances.push_back(instance);
01796 }
01797
01798
01799
01800 sort(instances.begin(), instances.end());
01801
01802 if (!instances.empty()) {
01803
01804
01805 lod_node->set_center(LCAST(PN_stdfloat, instances[0]._d->_center));
01806 }
01807
01808 for (size_t i = 0; i < instances.size(); i++) {
01809
01810 const LODInstance &instance = instances[i];
01811 make_node(instance._egg_node, lod_node);
01812
01813
01814
01815 nassertr(lod_node->get_center().almost_equal
01816 (LCAST(PN_stdfloat, instance._d->_center), 0.01), NULL);
01817
01818
01819 lod_node->add_switch(instance._d->_switch_in, instance._d->_switch_out);
01820 }
01821
01822 _groups[egg_bin] = lod_node;
01823 return create_group_arc(egg_bin, parent, lod_node);
01824 }
01825
01826
01827
01828
01829
01830
01831 PandaNode *EggLoader::
01832 make_node(EggGroup *egg_group, PandaNode *parent) {
01833 PT(PandaNode) node = NULL;
01834
01835 if (egg_group->get_dart_type() != EggGroup::DT_none) {
01836
01837 bool structured = (egg_group->get_dart_type() == EggGroup::DT_structured);
01838
01839 CharacterMaker char_maker(egg_group, *this, structured);
01840
01841 node = char_maker.make_node();
01842 if(structured) {
01843
01844
01845 _dynamic_override = true;
01846 _dynamic_override_char_maker = &char_maker;
01847 EggGroup::const_iterator ci;
01848 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
01849 make_node(*ci, node);
01850 }
01851 _dynamic_override_char_maker = NULL;
01852 _dynamic_override = false;
01853 }
01854
01855 } else if (egg_group->get_cs_type() != EggGroup::CST_none) {
01856
01857 node = new CollisionNode(egg_group->get_name());
01858
01859 make_collision_solids(egg_group, egg_group, (CollisionNode *)node.p());
01860 if ((egg_group->get_collide_flags() & EggGroup::CF_keep) != 0) {
01861
01862
01863
01864 PandaNode *combined = new PandaNode("");
01865 parent->add_child(combined);
01866 combined->add_child(node);
01867 node = combined;
01868
01869 EggGroup::const_iterator ci;
01870 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
01871 make_node(*ci, combined);
01872 }
01873 }
01874
01875 node = create_group_arc(egg_group, parent, node);
01876 return node;
01877
01878 } else if (egg_group->get_portal_flag()) {
01879
01880
01881
01882 PortalNode *pnode = new PortalNode(egg_group->get_name());
01883 node = pnode;
01884
01885 set_portal_polygon(egg_group, pnode);
01886 if (pnode->get_num_vertices() == 0) {
01887 egg2pg_cat.warning()
01888 << "Portal " << egg_group->get_name() << " has no vertices!\n";
01889 }
01890
01891 } else if (egg_group->get_occluder_flag()) {
01892
01893
01894
01895 OccluderNode *pnode = new OccluderNode(egg_group->get_name());
01896 node = pnode;
01897
01898 set_occluder_polygon(egg_group, pnode);
01899 if (pnode->get_num_vertices() == 0) {
01900 egg2pg_cat.warning()
01901 << "Occluder " << egg_group->get_name() << " has no vertices!\n";
01902 }
01903
01904 } else if (egg_group->get_polylight_flag()) {
01905
01906
01907
01908 LPoint3 center;
01909 LColor color;
01910 PN_stdfloat radius;
01911
01912 if (!make_sphere(egg_group, EggGroup::CF_none, center, radius, color)) {
01913 egg2pg_cat.warning()
01914 << "Polylight " << egg_group->get_name() << " make_sphere failed!\n";
01915 }
01916 PolylightNode *pnode = new PolylightNode(egg_group->get_name());
01917 pnode->set_pos(center);
01918 pnode->set_color(color);
01919 pnode->set_radius(radius);
01920 node = pnode;
01921
01922 } else if (egg_group->get_switch_flag()) {
01923 if (egg_group->get_switch_fps() != 0.0) {
01924
01925 node = new SequenceNode(egg_group->get_name());
01926 ((SequenceNode *)node.p())->set_frame_rate(egg_group->get_switch_fps());
01927 _sequences.insert(node);
01928 } else {
01929
01930 node = new SwitchNode(egg_group->get_name());
01931 }
01932
01933 EggGroup::const_iterator ci;
01934 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
01935 make_node(*ci, node);
01936 }
01937 } else if (egg_group->has_scrolling_uvs()) {
01938 node = new UvScrollNode(egg_group->get_name(), egg_group->get_scroll_u(), egg_group->get_scroll_v(), egg_group->get_scroll_r());
01939
01940 EggGroup::const_iterator ci;
01941 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
01942 make_node(*ci, node);
01943 }
01944
01945 } else if (egg_group->get_model_flag() || egg_group->has_dcs_type()) {
01946
01947 node = new ModelNode(egg_group->get_name());
01948 switch (egg_group->get_dcs_type()) {
01949 case EggGroup::DC_net:
01950 DCAST(ModelNode, node)->set_preserve_transform(ModelNode::PT_net);
01951 break;
01952
01953 case EggGroup::DC_no_touch:
01954 DCAST(ModelNode, node)->set_preserve_transform(ModelNode::PT_no_touch);
01955 break;
01956
01957 case EggGroup::DC_local:
01958 case EggGroup::DC_default:
01959 DCAST(ModelNode, node)->set_preserve_transform(ModelNode::PT_local);
01960 break;
01961
01962 case EggGroup::DC_none:
01963 case EggGroup::DC_unspecified:
01964 break;
01965 }
01966
01967 EggGroup::const_iterator ci;
01968 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
01969 make_node(*ci, node);
01970 }
01971
01972 } else {
01973
01974
01975
01976
01977 bool all_polysets = false;
01978 bool any_hidden = false;
01979
01980
01981
01982 if (!egg_group->determine_decal()) {
01983 check_for_polysets(egg_group, all_polysets, any_hidden);
01984 }
01985
01986 if (all_polysets && !any_hidden) {
01987 node = new GeomNode(egg_group->get_name());
01988 } else {
01989 node = new PandaNode(egg_group->get_name());
01990 }
01991
01992 EggGroup::const_iterator ci;
01993 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
01994 make_node(*ci, node);
01995 }
01996 }
01997
01998 if (node == (PandaNode *)NULL) {
01999 return NULL;
02000 }
02001
02002
02003 int num_group_refs = egg_group->get_num_group_refs();
02004 for (int gri = 0; gri < num_group_refs; ++gri) {
02005 EggGroup *group_ref = egg_group->get_group_ref(gri);
02006 Groups::const_iterator gi = _groups.find(group_ref);
02007 if (gi != _groups.end()) {
02008 PandaNode *node_ref = (*gi).second;
02009 node->add_child(node_ref);
02010 }
02011 }
02012
02013 _groups[egg_group] = node;
02014 return create_group_arc(egg_group, parent, node);
02015 }
02016
02017
02018
02019
02020
02021
02022
02023
02024
02025 PandaNode *EggLoader::
02026 create_group_arc(EggGroup *egg_group, PandaNode *parent, PandaNode *node) {
02027 parent->add_child(node);
02028
02029
02030 if (egg_group->has_transform()) {
02031 CPT(TransformState) transform = make_transform(egg_group);
02032 node->set_transform(transform);
02033 node->set_prev_transform(transform);
02034 }
02035
02036
02037 switch (egg_group->get_billboard_type()) {
02038 case EggGroup::BT_point_camera_relative:
02039 node->set_effect(BillboardEffect::make_point_eye());
02040 break;
02041
02042 case EggGroup::BT_point_world_relative:
02043 node->set_effect(BillboardEffect::make_point_world());
02044 break;
02045
02046 case EggGroup::BT_axis:
02047 node->set_effect(BillboardEffect::make_axis());
02048 break;
02049
02050 case EggGroup::BT_none:
02051 break;
02052 }
02053
02054 if (egg_group->get_decal_flag()) {
02055 if (egg_ignore_decals) {
02056 egg2pg_cat.error()
02057 << "Ignoring decal flag on " << egg_group->get_name() << "\n";
02058 _error = true;
02059 }
02060
02061
02062
02063
02064
02065 _decals.insert(node);
02066 }
02067
02068
02069 EggGroup::TagData::const_iterator ti;
02070 for (ti = egg_group->tag_begin(); ti != egg_group->tag_end(); ++ti) {
02071 node->set_tag((*ti).first, (*ti).second);
02072 }
02073
02074 if (egg_group->get_blend_mode() != EggGroup::BM_unspecified &&
02075 egg_group->get_blend_mode() != EggGroup::BM_none) {
02076
02077 ColorBlendAttrib::Mode mode = get_color_blend_mode(egg_group->get_blend_mode());
02078 ColorBlendAttrib::Operand a = get_color_blend_operand(egg_group->get_blend_operand_a());
02079 ColorBlendAttrib::Operand b = get_color_blend_operand(egg_group->get_blend_operand_b());
02080 LColor color = egg_group->get_blend_color();
02081 node->set_attrib(ColorBlendAttrib::make(mode, a, b, color));
02082 }
02083
02084
02085
02086
02087 DeferredNodeProperty def;
02088 if (egg_group->has_collide_mask()) {
02089 def._from_collide_mask = egg_group->get_collide_mask();
02090 def._into_collide_mask = egg_group->get_collide_mask();
02091 def._flags |=
02092 DeferredNodeProperty::F_has_from_collide_mask |
02093 DeferredNodeProperty::F_has_into_collide_mask;
02094 }
02095 if (egg_group->has_from_collide_mask()) {
02096 def._from_collide_mask = egg_group->get_from_collide_mask();
02097 def._flags |= DeferredNodeProperty::F_has_from_collide_mask;
02098 }
02099 if (egg_group->has_into_collide_mask()) {
02100 def._into_collide_mask = egg_group->get_into_collide_mask();
02101 def._flags |= DeferredNodeProperty::F_has_into_collide_mask;
02102 }
02103
02104 if (def._flags != 0) {
02105 _deferred_nodes[node] = def;
02106 }
02107
02108 return node;
02109 }
02110
02111
02112
02113
02114
02115
02116 PandaNode *EggLoader::
02117 make_node(EggTable *egg_table, PandaNode *parent) {
02118 if (egg_table->get_table_type() != EggTable::TT_bundle) {
02119
02120
02121 return make_node(DCAST(EggGroupNode, egg_table), parent);
02122 }
02123
02124
02125
02126 AnimBundleMaker bundle_maker(egg_table);
02127 AnimBundleNode *node = bundle_maker.make_node();
02128 parent->add_child(node);
02129 return node;
02130 }
02131
02132
02133
02134
02135
02136
02137
02138 PandaNode *EggLoader::
02139 make_node(EggGroupNode *egg_group, PandaNode *parent) {
02140 PandaNode *node = new PandaNode(egg_group->get_name());
02141
02142 EggGroupNode::const_iterator ci;
02143 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
02144 make_node(*ci, node);
02145 }
02146
02147 parent->add_child(node);
02148 return node;
02149 }
02150
02151
02152
02153
02154
02155
02156
02157
02158 void EggLoader::
02159 check_for_polysets(EggGroup *egg_group, bool &all_polysets, bool &any_hidden) {
02160 all_polysets = (!egg_group->empty());
02161 any_hidden = false;
02162
02163 EggGroup::const_iterator ci;
02164 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
02165 if ((*ci)->is_of_type(EggBin::get_class_type())) {
02166 EggBin *egg_bin = DCAST(EggBin, (*ci));
02167 if (egg_bin->get_bin_number() == EggBinner::BN_polyset) {
02168
02169
02170
02171 EggGroup::const_iterator bci = egg_bin->begin();
02172 nassertv(bci != egg_bin->end());
02173 const EggPrimitive *first_prim;
02174 DCAST_INTO_V(first_prim, (*bci));
02175 const EggRenderState *render_state;
02176 DCAST_INTO_V(render_state, first_prim->get_user_data(EggRenderState::get_class_type()));
02177
02178 if (render_state->_hidden) {
02179 any_hidden = true;
02180 }
02181 } else {
02182 all_polysets = false;
02183 return;
02184 }
02185 } else if ((*ci)->is_of_type(EggGroup::get_class_type())) {
02186
02187
02188
02189 all_polysets = false;
02190 return;
02191 }
02192 }
02193 }
02194
02195
02196
02197
02198
02199
02200
02201
02202
02203 PT(GeomVertexData) EggLoader::
02204 make_vertex_data(const EggRenderState *render_state,
02205 EggVertexPool *vertex_pool, EggNode *primitive_home,
02206 const LMatrix4d &transform, TransformBlendTable *blend_table,
02207 bool is_dynamic, CharacterMaker *character_maker,
02208 bool ignore_color) {
02209 VertexPoolTransform vpt;
02210 vpt._vertex_pool = vertex_pool;
02211 vpt._bake_in_uvs = render_state->_bake_in_uvs;
02212 vpt._transform = transform;
02213
02214 VertexPoolData::iterator di;
02215 di = _vertex_pool_data.find(vpt);
02216 if (di != _vertex_pool_data.end()) {
02217 return (*di).second;
02218 }
02219
02220 PT(GeomVertexArrayFormat) array_format = new GeomVertexArrayFormat;
02221 array_format->add_column
02222 (InternalName::get_vertex(), vertex_pool->get_num_dimensions(),
02223 Geom::NT_stdfloat, Geom::C_point);
02224
02225 if (vertex_pool->has_normals()) {
02226 array_format->add_column
02227 (InternalName::get_normal(), 3,
02228 Geom::NT_stdfloat, Geom::C_vector);
02229 }
02230
02231 if (!ignore_color) {
02232 array_format->add_column
02233 (InternalName::get_color(), 1,
02234 Geom::NT_packed_dabc, Geom::C_color);
02235 }
02236
02237 vector_string uv_names, uvw_names, tbn_names;
02238 vertex_pool->get_uv_names(uv_names, uvw_names, tbn_names);
02239 vector_string::const_iterator ni;
02240 for (ni = uv_names.begin(); ni != uv_names.end(); ++ni) {
02241 string name = (*ni);
02242
02243 PT(InternalName) iname = InternalName::get_texcoord_name(name);
02244
02245 if (find(uvw_names.begin(), uvw_names.end(), name) != uvw_names.end()) {
02246
02247 array_format->add_column
02248 (iname, 3, Geom::NT_stdfloat, Geom::C_texcoord);
02249 } else {
02250 array_format->add_column
02251 (iname, 2, Geom::NT_stdfloat, Geom::C_texcoord);
02252 }
02253 }
02254 for (ni = tbn_names.begin(); ni != tbn_names.end(); ++ni) {
02255 string name = (*ni);
02256
02257 PT(InternalName) iname_t = InternalName::get_tangent_name(name);
02258 PT(InternalName) iname_b = InternalName::get_binormal_name(name);
02259
02260 array_format->add_column
02261 (iname_t, 3, Geom::NT_stdfloat, Geom::C_vector);
02262 array_format->add_column
02263 (iname_b, 3, Geom::NT_stdfloat, Geom::C_vector);
02264 }
02265
02266 vector_string aux_names;
02267 vertex_pool->get_aux_names(aux_names);
02268 for (ni = aux_names.begin(); ni != aux_names.end(); ++ni) {
02269 string name = (*ni);
02270 PT(InternalName) iname = InternalName::make(name);
02271 array_format->add_column
02272 (iname, 4, Geom::NT_stdfloat, Geom::C_other);
02273 }
02274
02275 PT(GeomVertexFormat) temp_format = new GeomVertexFormat(array_format);
02276
02277 PT(SliderTable) slider_table;
02278 string name = _data->get_egg_filename().get_basename_wo_extension();
02279
02280 if (is_dynamic) {
02281
02282
02283
02284
02285
02286
02287
02288 GeomVertexAnimationSpec animation;
02289 animation.set_panda();
02290 temp_format->set_animation(animation);
02291
02292 PT(GeomVertexArrayFormat) anim_array_format = new GeomVertexArrayFormat;
02293 anim_array_format->add_column
02294 (InternalName::get_transform_blend(), 1,
02295 Geom::NT_uint16, Geom::C_index);
02296 temp_format->add_array(anim_array_format);
02297
02298 pmap<string, BitArray> slider_names;
02299 EggVertexPool::const_iterator vi;
02300 for (vi = vertex_pool->begin(); vi != vertex_pool->end(); ++vi) {
02301 EggVertex *vertex = (*vi);
02302
02303 EggMorphVertexList::const_iterator mvi;
02304 for (mvi = vertex->_dxyzs.begin(); mvi != vertex->_dxyzs.end(); ++mvi) {
02305 slider_names[(*mvi).get_name()].set_bit(vertex->get_index());
02306 record_morph(anim_array_format, character_maker, (*mvi).get_name(),
02307 InternalName::get_vertex(), 3);
02308 }
02309 if (vertex->has_normal()) {
02310 EggMorphNormalList::const_iterator mni;
02311 for (mni = vertex->_dnormals.begin(); mni != vertex->_dnormals.end(); ++mni) {
02312 slider_names[(*mni).get_name()].set_bit(vertex->get_index());
02313 record_morph(anim_array_format, character_maker, (*mni).get_name(),
02314 InternalName::get_normal(), 3);
02315 }
02316 }
02317 if (!ignore_color && vertex->has_color()) {
02318 EggMorphColorList::const_iterator mci;
02319 for (mci = vertex->_drgbas.begin(); mci != vertex->_drgbas.end(); ++mci) {
02320 slider_names[(*mci).get_name()].set_bit(vertex->get_index());
02321 record_morph(anim_array_format, character_maker, (*mci).get_name(),
02322 InternalName::get_color(), 4);
02323 }
02324 }
02325 EggVertex::const_uv_iterator uvi;
02326 for (uvi = vertex->uv_begin(); uvi != vertex->uv_end(); ++uvi) {
02327 EggVertexUV *egg_uv = (*uvi);
02328 string name = egg_uv->get_name();
02329 bool has_w = (find(uvw_names.begin(), uvw_names.end(), name) != uvw_names.end());
02330 PT(InternalName) iname = InternalName::get_texcoord_name(name);
02331
02332 EggMorphTexCoordList::const_iterator mti;
02333 for (mti = egg_uv->_duvs.begin(); mti != egg_uv->_duvs.end(); ++mti) {
02334 slider_names[(*mti).get_name()].set_bit(vertex->get_index());
02335 record_morph(anim_array_format, character_maker, (*mti).get_name(),
02336 iname, has_w ? 3 : 2);
02337 }
02338 }
02339 }
02340
02341 if (!slider_names.empty()) {
02342
02343
02344 slider_table = new SliderTable;
02345
02346 pmap<string, BitArray>::iterator si;
02347 for (si = slider_names.begin(); si != slider_names.end(); ++si) {
02348 PT(VertexSlider) slider = character_maker->egg_to_slider((*si).first);
02349 slider_table->add_slider(slider, (*si).second);
02350 }
02351 }
02352
02353
02354
02355 name = character_maker->get_name();
02356 }
02357
02358 temp_format->maybe_align_columns_for_animation();
02359
02360 CPT(GeomVertexFormat) format =
02361 GeomVertexFormat::register_format(temp_format);
02362
02363
02364
02365
02366
02367
02368 PT(GeomVertexData) vertex_data =
02369 new GeomVertexData(name, format, Geom::UH_static);
02370 vertex_data->reserve_num_rows(vertex_pool->size());
02371
02372 vertex_data->set_transform_blend_table(blend_table);
02373 if (slider_table != (SliderTable *)NULL) {
02374 vertex_data->set_slider_table(SliderTable::register_table(slider_table));
02375 }
02376
02377
02378 EggVertexPool::const_iterator vi;
02379 for (vi = vertex_pool->begin(); vi != vertex_pool->end(); ++vi) {
02380 GeomVertexWriter gvw(vertex_data);
02381 EggVertex *vertex = (*vi);
02382 gvw.set_row(vertex->get_index());
02383
02384 gvw.set_column(InternalName::get_vertex());
02385 gvw.add_data4d(vertex->get_pos4() * transform);
02386
02387 if (is_dynamic) {
02388 EggMorphVertexList::const_iterator mvi;
02389 for (mvi = vertex->_dxyzs.begin(); mvi != vertex->_dxyzs.end(); ++mvi) {
02390 const EggMorphVertex &morph = (*mvi);
02391 CPT(InternalName) delta_name =
02392 InternalName::get_morph(InternalName::get_vertex(), morph.get_name());
02393 gvw.set_column(delta_name);
02394 gvw.add_data3d(morph.get_offset() * transform);
02395 }
02396 }
02397
02398 if (vertex->has_normal()) {
02399 gvw.set_column(InternalName::get_normal());
02400 LNormald orig_normal = vertex->get_normal();
02401 LNormald transformed_normal = normalize(orig_normal * transform);
02402 gvw.add_data3d(transformed_normal);
02403
02404 if (is_dynamic) {
02405 EggMorphNormalList::const_iterator mni;
02406 for (mni = vertex->_dnormals.begin(); mni != vertex->_dnormals.end(); ++mni) {
02407 const EggMorphNormal &morph = (*mni);
02408 CPT(InternalName) delta_name =
02409 InternalName::get_morph(InternalName::get_normal(), morph.get_name());
02410 gvw.set_column(delta_name);
02411 LNormald morphed_normal = orig_normal + morph.get_offset();
02412 LNormald transformed_morphed_normal = normalize(morphed_normal * transform);
02413 LVector3d delta = transformed_morphed_normal - transformed_normal;
02414 gvw.add_data3d(delta);
02415 }
02416 }
02417 }
02418
02419 if (!ignore_color && vertex->has_color()) {
02420 gvw.set_column(InternalName::get_color());
02421 gvw.add_data4(vertex->get_color());
02422
02423 if (is_dynamic) {
02424 EggMorphColorList::const_iterator mci;
02425 for (mci = vertex->_drgbas.begin(); mci != vertex->_drgbas.end(); ++mci) {
02426 const EggMorphColor &morph = (*mci);
02427 CPT(InternalName) delta_name =
02428 InternalName::get_morph(InternalName::get_color(), morph.get_name());
02429 gvw.set_column(delta_name);
02430 gvw.add_data4(morph.get_offset());
02431 }
02432 }
02433 }
02434
02435 EggVertex::const_uv_iterator uvi;
02436 for (uvi = vertex->uv_begin(); uvi != vertex->uv_end(); ++uvi) {
02437 EggVertexUV *egg_uv = (*uvi);
02438 LTexCoord3d orig_uvw = egg_uv->get_uvw();
02439 LTexCoord3d uvw = egg_uv->get_uvw();
02440
02441 string name = egg_uv->get_name();
02442 PT(InternalName) iname = InternalName::get_texcoord_name(name);
02443 gvw.set_column(iname);
02444
02445 BakeInUVs::const_iterator buv = render_state->_bake_in_uvs.find(iname);
02446 if (buv != render_state->_bake_in_uvs.end()) {
02447
02448 uvw = uvw * (*buv).second->get_transform3d();
02449 }
02450
02451 gvw.set_data3d(uvw);
02452
02453 if (is_dynamic) {
02454 EggMorphTexCoordList::const_iterator mti;
02455 for (mti = egg_uv->_duvs.begin(); mti != egg_uv->_duvs.end(); ++mti) {
02456 const EggMorphTexCoord &morph = (*mti);
02457 CPT(InternalName) delta_name =
02458 InternalName::get_morph(iname, morph.get_name());
02459 gvw.set_column(delta_name);
02460 LTexCoord3d duvw = morph.get_offset();
02461 if (buv != render_state->_bake_in_uvs.end()) {
02462 LTexCoord3d new_uvw = orig_uvw + duvw;
02463 duvw = (new_uvw * (*buv).second->get_transform3d()) - uvw;
02464 }
02465
02466 gvw.add_data3d(duvw);
02467 }
02468 }
02469
02470
02471 if (egg_uv->has_tangent() && egg_uv->has_binormal()) {
02472 PT(InternalName) iname = InternalName::get_tangent_name(name);
02473 gvw.set_column(iname);
02474 if (gvw.has_column()) {
02475 LVector3d tangent = egg_uv->get_tangent();
02476 LVector3d binormal = egg_uv->get_binormal();
02477 gvw.add_data3d(tangent);
02478 gvw.set_column(InternalName::get_binormal_name(name));
02479 gvw.add_data3d(binormal);
02480 }
02481 }
02482 }
02483
02484 EggVertex::const_aux_iterator auxi;
02485 for (auxi = vertex->aux_begin(); auxi != vertex->aux_end(); ++auxi) {
02486 EggVertexAux *egg_aux = (*auxi);
02487 LVecBase4d aux = egg_aux->get_aux();
02488
02489 string name = egg_aux->get_name();
02490 PT(InternalName) iname = InternalName::make(name);
02491 gvw.set_column(iname);
02492
02493 gvw.set_data4d(aux);
02494 }
02495
02496 if (is_dynamic) {
02497 int table_index = vertex->get_external_index();
02498 gvw.set_column(InternalName::get_transform_blend());
02499 gvw.set_data1i(table_index);
02500 }
02501 }
02502
02503 bool inserted = _vertex_pool_data.insert
02504 (VertexPoolData::value_type(vpt, vertex_data)).second;
02505 nassertr(inserted, vertex_data);
02506
02507 Thread::consider_yield();
02508 return vertex_data;
02509 }
02510
02511
02512
02513
02514
02515
02516 PT(TransformBlendTable) EggLoader::
02517 make_blend_table(EggVertexPool *vertex_pool, EggNode *primitive_home,
02518 CharacterMaker *character_maker) {
02519 PT(TransformBlendTable) blend_table;
02520 blend_table = new TransformBlendTable;
02521 blend_table->set_rows(SparseArray::lower_on(vertex_pool->size()));
02522
02523 EggVertexPool::const_iterator vi;
02524 for (vi = vertex_pool->begin(); vi != vertex_pool->end(); ++vi) {
02525 EggVertex *vertex = (*vi);
02526
02527
02528 TransformBlend blend;
02529 if (vertex->gref_size() == 0) {
02530
02531
02532 PT(VertexTransform) vt = character_maker->egg_to_transform(primitive_home);
02533 nassertr(vt != (VertexTransform *)NULL, NULL);
02534 blend.add_transform(vt, 1.0f);
02535 } else {
02536
02537
02538 double quantize = egg_vertex_membership_quantize;
02539 EggVertex::GroupRef::const_iterator gri;
02540 for (gri = vertex->gref_begin(); gri != vertex->gref_end(); ++gri) {
02541 EggGroup *egg_joint = (*gri);
02542 double membership = egg_joint->get_vertex_membership(vertex);
02543 if (quantize != 0.0) {
02544 membership = cfloor(membership / quantize + 0.5) * quantize;
02545 }
02546
02547 PT(VertexTransform) vt = character_maker->egg_to_transform(egg_joint);
02548 nassertr(vt != (VertexTransform *)NULL, NULL);
02549 blend.add_transform(vt, membership);
02550 }
02551 }
02552 if (egg_vertex_max_num_joints >= 0) {
02553 blend.limit_transforms(egg_vertex_max_num_joints);
02554 }
02555 blend.normalize_weights();
02556
02557 int table_index = blend_table->add_blend(blend);
02558
02559
02560
02561 vertex->set_external_index(table_index);
02562 }
02563
02564 return blend_table;
02565 }
02566
02567
02568
02569
02570
02571
02572 void EggLoader::
02573 record_morph(GeomVertexArrayFormat *array_format,
02574 CharacterMaker *character_maker,
02575 const string &morph_name, InternalName *column_name,
02576 int num_components) {
02577 PT(InternalName) delta_name =
02578 InternalName::get_morph(column_name, morph_name);
02579 if (!array_format->has_column(delta_name)) {
02580 array_format->add_column
02581 (delta_name, num_components,
02582 Geom::NT_stdfloat, Geom::C_morph_delta);
02583 }
02584 }
02585
02586
02587
02588
02589
02590
02591
02592 void EggLoader::
02593 make_primitive(const EggRenderState *render_state, EggPrimitive *egg_prim,
02594 EggLoader::UniquePrimitives &unique_primitives,
02595 EggLoader::Primitives &primitives,
02596 bool has_overall_color, const LColor &overall_color) {
02597 PT(GeomPrimitive) primitive;
02598 if (egg_prim->is_of_type(EggPolygon::get_class_type())) {
02599 if (egg_prim->size() == 3) {
02600 primitive = new GeomTriangles(Geom::UH_static);
02601 }
02602
02603 } else if (egg_prim->is_of_type(EggTriangleStrip::get_class_type())) {
02604 primitive = new GeomTristrips(Geom::UH_static);
02605
02606 } else if (egg_prim->is_of_type(EggTriangleFan::get_class_type())) {
02607 primitive = new GeomTrifans(Geom::UH_static);
02608
02609 } else if (egg_prim->is_of_type(EggLine::get_class_type())) {
02610 if (egg_prim->size() == 2) {
02611 primitive = new GeomLines(Geom::UH_static);
02612 } else {
02613 primitive = new GeomLinestrips(Geom::UH_static);
02614 }
02615
02616 } else if (egg_prim->is_of_type(EggPoint::get_class_type())) {
02617 primitive = new GeomPoints(Geom::UH_static);
02618 }
02619
02620 if (primitive == (GeomPrimitive *)NULL) {
02621
02622 egg2pg_cat.warning()
02623 << "Ignoring " << egg_prim->get_type() << "\n";
02624 return;
02625 }
02626
02627 if (render_state->_flat_shaded) {
02628 primitive->set_shade_model(GeomPrimitive::SM_flat_first_vertex);
02629
02630 } else if (egg_prim->get_shading() == EggPrimitive::S_overall) {
02631 primitive->set_shade_model(GeomPrimitive::SM_uniform);
02632
02633 } else {
02634 primitive->set_shade_model(GeomPrimitive::SM_smooth);
02635 }
02636
02637
02638
02639 PrimitiveUnifier pu(primitive);
02640 pair<UniquePrimitives::iterator, bool> result =
02641 unique_primitives.insert(UniquePrimitives::value_type(pu, primitive));
02642
02643 if (result.second) {
02644
02645 primitives.push_back(primitive);
02646
02647 if (egg2pg_cat.is_debug()) {
02648 egg2pg_cat.debug()
02649 << "First primitive of type " << primitive->get_type()
02650 << ": " << primitive << "\n";
02651 }
02652 }
02653
02654 GeomPrimitive *orig_prim = (*result.first).second;
02655
02656
02657
02658 if (orig_prim->get_num_vertices() + egg_prim->size() <= (unsigned int)egg_max_indices) {
02659 primitive = orig_prim;
02660
02661 } else if (orig_prim != primitive) {
02662
02663
02664 (*result.first).second = primitive;
02665
02666 if (egg2pg_cat.is_debug()) {
02667 egg2pg_cat.debug()
02668 << "Next primitive of type " << primitive->get_type()
02669 << ": " << primitive << "\n";
02670 }
02671 primitives.push_back(primitive);
02672 }
02673
02674
02675 EggPrimitive::const_iterator vi;
02676 for (vi = egg_prim->begin(); vi != egg_prim->end(); ++vi) {
02677 primitive->add_vertex((*vi)->get_index());
02678 }
02679 primitive->close_primitive();
02680 }
02681
02682
02683
02684
02685
02686
02687
02688 void EggLoader::
02689 set_portal_polygon(EggGroup *egg_group, PortalNode *pnode) {
02690 pnode->clear_vertices();
02691
02692 PT(EggPolygon) poly = find_first_polygon(egg_group);
02693 if (poly != (EggPolygon *)NULL) {
02694 LMatrix4d mat = poly->get_vertex_to_node();
02695
02696 EggPolygon::const_iterator vi;
02697 for (vi = poly->begin(); vi != poly->end(); ++vi) {
02698 LVertexd vert = (*vi)->get_pos3() * mat;
02699 pnode->add_vertex(LCAST(PN_stdfloat, vert));
02700 }
02701 }
02702 }
02703
02704
02705
02706
02707
02708
02709
02710 void EggLoader::
02711 set_occluder_polygon(EggGroup *egg_group, OccluderNode *pnode) {
02712 PT(EggPolygon) poly = find_first_polygon(egg_group);
02713 if (poly != (EggPolygon *)NULL) {
02714 if (poly->size() != 4) {
02715 egg2pg_cat.error()
02716 << "Invalid number of vertices for " << egg_group->get_name() << "\n";
02717 } else {
02718 LMatrix4d mat = poly->get_vertex_to_node();
02719
02720 EggPolygon::const_iterator vi;
02721 LPoint3d v0 = (*poly)[0]->get_pos3() * mat;
02722 LPoint3d v1 = (*poly)[1]->get_pos3() * mat;
02723 LPoint3d v2 = (*poly)[2]->get_pos3() * mat;
02724 LPoint3d v3 = (*poly)[3]->get_pos3() * mat;
02725 pnode->set_vertices(LCAST(PN_stdfloat, v0),
02726 LCAST(PN_stdfloat, v1),
02727 LCAST(PN_stdfloat, v2),
02728 LCAST(PN_stdfloat, v3));
02729
02730 if (poly->get_bface_flag()) {
02731 pnode->set_double_sided(true);
02732 }
02733 }
02734 }
02735 }
02736
02737
02738
02739
02740
02741
02742
02743 PT(EggPolygon) EggLoader::
02744 find_first_polygon(EggGroup *egg_group) {
02745
02746 EggGroup::const_iterator ci;
02747 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
02748 if ((*ci)->is_of_type(EggPolygon::get_class_type())) {
02749
02750 return DCAST(EggPolygon, (*ci));
02751 }
02752 }
02753
02754
02755
02756 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
02757 if ((*ci)->is_of_type(EggGroup::get_class_type())) {
02758 EggGroup *child_group = DCAST(EggGroup, *ci);
02759 PT(EggPolygon) found = find_first_polygon(child_group);
02760 if (found != (EggPolygon *)NULL) {
02761 return found;
02762 }
02763 }
02764 }
02765
02766
02767 return NULL;
02768 }
02769
02770
02771
02772
02773
02774
02775
02776
02777
02778 bool EggLoader::
02779 make_sphere(EggGroup *egg_group, EggGroup::CollideFlags flags,
02780 LPoint3 ¢er, PN_stdfloat &radius, LColor &color) {
02781 bool success=false;
02782 EggGroup *geom_group = find_collision_geometry(egg_group, flags);
02783 if (geom_group != (EggGroup *)NULL) {
02784
02785 pset<EggVertex *> vertices;
02786
02787 EggGroup::const_iterator ci;
02788 for (ci = geom_group->begin(); ci != geom_group->end(); ++ci) {
02789 if ((*ci)->is_of_type(EggPrimitive::get_class_type())) {
02790 EggPrimitive *prim = DCAST(EggPrimitive, *ci);
02791 EggPrimitive::const_iterator pi;
02792 for (pi = prim->begin(); pi != prim->end(); ++pi) {
02793 vertices.insert(*pi);
02794 }
02795 }
02796 }
02797
02798
02799 int num_vertices = 0;
02800 LPoint3d d_center(0.0, 0.0, 0.0);
02801 pset<EggVertex *>::const_iterator vi;
02802
02803 for (vi = vertices.begin(); vi != vertices.end(); ++vi) {
02804 EggVertex *vtx = (*vi);
02805 d_center += vtx->get_pos3();
02806 num_vertices++;
02807 }
02808
02809 if (num_vertices > 0) {
02810 d_center /= (double)num_vertices;
02811
02812
02813 LMatrix4d mat = egg_group->get_vertex_to_node();
02814 d_center = d_center * mat;
02815
02816
02817 double radius2 = 0.0;
02818 for (vi = vertices.begin(); vi != vertices.end(); ++vi) {
02819 EggVertex *vtx = (*vi);
02820 LPoint3d p3 = vtx->get_pos3();
02821 LVector3d v = p3 * mat - d_center;
02822 radius2 = max(radius2, v.length_squared());
02823 }
02824
02825 center = LCAST(PN_stdfloat, d_center);
02826 radius = sqrtf(radius2);
02827
02828
02829 vi = vertices.begin();
02830 EggVertex *clr_vtx = (*vi);
02831 color = clr_vtx->get_color();
02832 success = true;
02833 }
02834 }
02835 return success;
02836 }
02837
02838
02839
02840
02841
02842
02843
02844
02845 void EggLoader::
02846 make_collision_solids(EggGroup *start_group, EggGroup *egg_group,
02847 CollisionNode *cnode) {
02848 if (egg_group->get_cs_type() != EggGroup::CST_none) {
02849 start_group = egg_group;
02850 }
02851
02852 switch (start_group->get_cs_type()) {
02853 case EggGroup::CST_none:
02854
02855 return;
02856
02857 case EggGroup::CST_plane:
02858 make_collision_plane(egg_group, cnode, start_group->get_collide_flags());
02859 break;
02860
02861 case EggGroup::CST_polygon:
02862 make_collision_polygon(egg_group, cnode, start_group->get_collide_flags());
02863 break;
02864
02865 case EggGroup::CST_polyset:
02866 make_collision_polyset(egg_group, cnode, start_group->get_collide_flags());
02867 break;
02868
02869 case EggGroup::CST_sphere:
02870 make_collision_sphere(egg_group, cnode, start_group->get_collide_flags());
02871 break;
02872
02873 case EggGroup::CST_inv_sphere:
02874 make_collision_inv_sphere(egg_group, cnode, start_group->get_collide_flags());
02875 break;
02876
02877 case EggGroup::CST_tube:
02878 make_collision_tube(egg_group, cnode, start_group->get_collide_flags());
02879 break;
02880
02881 case EggGroup::CST_floor_mesh:
02882 make_collision_floor_mesh(egg_group, cnode, start_group->get_collide_flags());
02883 break;
02884 }
02885
02886 if ((start_group->get_collide_flags() & EggGroup::CF_descend) != 0) {
02887
02888 EggGroup::const_iterator ci;
02889 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
02890 if ((*ci)->is_of_type(EggGroup::get_class_type())) {
02891 make_collision_solids(start_group, DCAST(EggGroup, *ci), cnode);
02892 }
02893 }
02894 }
02895 }
02896
02897
02898
02899
02900
02901
02902
02903 void EggLoader::
02904 make_collision_plane(EggGroup *egg_group, CollisionNode *cnode,
02905 EggGroup::CollideFlags flags) {
02906 EggGroup *geom_group = find_collision_geometry(egg_group, flags);
02907 if (geom_group != (EggGroup *)NULL) {
02908 EggGroup::const_iterator ci;
02909 for (ci = geom_group->begin(); ci != geom_group->end(); ++ci) {
02910 if ((*ci)->is_of_type(EggPolygon::get_class_type())) {
02911 CollisionPlane *csplane =
02912 create_collision_plane(DCAST(EggPolygon, *ci), egg_group);
02913 if (csplane != (CollisionPlane *)NULL) {
02914 apply_collision_flags(csplane, flags);
02915 cnode->add_solid(csplane);
02916 return;
02917 }
02918 } else if ((*ci)->is_of_type(EggCompositePrimitive::get_class_type())) {
02919 EggCompositePrimitive *comp = DCAST(EggCompositePrimitive, *ci);
02920 PT(EggGroup) temp_group = new EggGroup;
02921 if (comp->triangulate_into(temp_group)) {
02922 make_collision_plane(temp_group, cnode, flags);
02923 return;
02924 }
02925 }
02926 }
02927 }
02928 }
02929
02930
02931
02932
02933
02934
02935
02936
02937
02938 void EggLoader::
02939 make_collision_floor_mesh(EggGroup *egg_group, CollisionNode *cnode,
02940 EggGroup::CollideFlags flags) {
02941
02942 EggGroup *geom_group = find_collision_geometry(egg_group, flags);
02943
02944
02945 if (geom_group != (EggGroup *)NULL) {
02946 create_collision_floor_mesh(cnode, geom_group,flags);
02947 }
02948 }
02949
02950
02951
02952
02953
02954
02955
02956 void EggLoader::
02957 make_collision_polygon(EggGroup *egg_group, CollisionNode *cnode,
02958 EggGroup::CollideFlags flags) {
02959
02960 EggGroup *geom_group = find_collision_geometry(egg_group, flags);
02961 if (geom_group != (EggGroup *)NULL) {
02962 EggGroup::const_iterator ci;
02963 for (ci = geom_group->begin(); ci != geom_group->end(); ++ci) {
02964 if ((*ci)->is_of_type(EggPolygon::get_class_type())) {
02965 create_collision_polygons(cnode, DCAST(EggPolygon, *ci),
02966 egg_group, flags);
02967 } else if ((*ci)->is_of_type(EggCompositePrimitive::get_class_type())) {
02968 EggCompositePrimitive *comp = DCAST(EggCompositePrimitive, *ci);
02969 PT(EggGroup) temp_group = new EggGroup;
02970 if (comp->triangulate_into(temp_group)) {
02971 make_collision_polygon(temp_group, cnode, flags);
02972 return;
02973 }
02974 }
02975 }
02976 }
02977 }
02978
02979
02980
02981
02982
02983
02984
02985
02986 void EggLoader::
02987 make_collision_polyset(EggGroup *egg_group, CollisionNode *cnode,
02988 EggGroup::CollideFlags flags) {
02989 EggGroup *geom_group = find_collision_geometry(egg_group, flags);
02990 if (geom_group != (EggGroup *)NULL) {
02991 EggGroup::const_iterator ci;
02992 for (ci = geom_group->begin(); ci != geom_group->end(); ++ci) {
02993 if ((*ci)->is_of_type(EggPolygon::get_class_type())) {
02994 create_collision_polygons(cnode, DCAST(EggPolygon, *ci),
02995 egg_group, flags);
02996 } else if ((*ci)->is_of_type(EggCompositePrimitive::get_class_type())) {
02997 EggCompositePrimitive *comp = DCAST(EggCompositePrimitive, *ci);
02998 PT(EggGroup) temp_group = new EggGroup;
02999 if (comp->triangulate_into(temp_group)) {
03000 make_collision_polyset(temp_group, cnode, flags);
03001 }
03002 }
03003 }
03004 }
03005 }
03006
03007
03008
03009
03010
03011
03012
03013 void EggLoader::
03014 make_collision_sphere(EggGroup *egg_group, CollisionNode *cnode,
03015 EggGroup::CollideFlags flags) {
03016 LPoint3 center;
03017 PN_stdfloat radius;
03018 LColor dummycolor;
03019 if (make_sphere(egg_group, flags, center, radius, dummycolor)) {
03020 CollisionSphere *cssphere =
03021 new CollisionSphere(center, radius);
03022 apply_collision_flags(cssphere, flags);
03023 cnode->add_solid(cssphere);
03024 }
03025 }
03026
03027
03028
03029
03030
03031
03032
03033 void EggLoader::
03034 make_collision_inv_sphere(EggGroup *egg_group, CollisionNode *cnode,
03035 EggGroup::CollideFlags flags) {
03036 LPoint3 center;
03037 PN_stdfloat radius;
03038 LColor dummycolor;
03039 if (make_sphere(egg_group, flags, center, radius, dummycolor)) {
03040 CollisionInvSphere *cssphere =
03041 new CollisionInvSphere(center, radius);
03042 apply_collision_flags(cssphere, flags);
03043 cnode->add_solid(cssphere);
03044 }
03045 }
03046
03047
03048
03049
03050
03051
03052
03053 void EggLoader::
03054 make_collision_tube(EggGroup *egg_group, CollisionNode *cnode,
03055 EggGroup::CollideFlags flags) {
03056 EggGroup *geom_group = find_collision_geometry(egg_group, flags);
03057 if (geom_group != (EggGroup *)NULL) {
03058
03059 pset<EggVertex *> vertices;
03060
03061 EggGroup::const_iterator ci;
03062 for (ci = geom_group->begin(); ci != geom_group->end(); ++ci) {
03063 if ((*ci)->is_of_type(EggPrimitive::get_class_type())) {
03064 EggPrimitive *prim = DCAST(EggPrimitive, *ci);
03065 EggPrimitive::const_iterator pi;
03066 for (pi = prim->begin(); pi != prim->end(); ++pi) {
03067 vertices.insert(*pi);
03068 }
03069 }
03070 }
03071
03072
03073
03074 size_t num_vertices = vertices.size();
03075 if (num_vertices != 0) {
03076 LMatrix4d mat = egg_group->get_vertex_to_node();
03077 pvector<LPoint3d> vpos;
03078 vpos.reserve(num_vertices);
03079
03080 LPoint3d center(0.0, 0.0, 0.0);
03081 pset<EggVertex *>::const_iterator vi;
03082 for (vi = vertices.begin(); vi != vertices.end(); ++vi) {
03083 EggVertex *vtx = (*vi);
03084 LPoint3d pos = vtx->get_pos3() * mat;
03085 vpos.push_back(pos);
03086 center += pos;
03087 }
03088 center /= (double)num_vertices;
03089
03090
03091
03092
03093 size_t i;
03094 double radius2 = 0.0;
03095 LPoint3d far_a = center;
03096 for (i = 0; i < num_vertices; i++) {
03097 double dist2 = (vpos[i] - center).length_squared();
03098 if (dist2 > radius2) {
03099 radius2 = dist2;
03100 far_a = vpos[i];
03101 }
03102 }
03103
03104
03105
03106
03107 radius2 = 0.0;
03108 LPoint3d far_b = center;
03109 for (i = 0; i < num_vertices; i++) {
03110 double dist2 = (vpos[i] - far_a).length_squared();
03111 if (dist2 > radius2) {
03112 radius2 = dist2;
03113 far_b = vpos[i];
03114 }
03115 }
03116
03117
03118
03119
03120
03121
03122
03123
03124
03125
03126
03127
03128
03129
03130 LPoint3d cap_a_center(0.0, 0.0, 0.0);
03131 LPoint3d cap_b_center(0.0, 0.0, 0.0);
03132 int num_a = 0;
03133 int num_b = 0;
03134
03135
03136
03137 double center_length = (far_a - far_b).length() / 4.0;
03138 double center_length2 = center_length * center_length;
03139
03140 for (i = 0; i < num_vertices; i++) {
03141 double dist2 = (vpos[i] - center).length_squared();
03142 if (dist2 > center_length2) {
03143
03144
03145 double dist_a2 = (vpos[i] - far_a).length_squared();
03146 double dist_b2 = (vpos[i] - far_b).length_squared();
03147 if (dist_a2 < dist_b2) {
03148
03149 cap_a_center += vpos[i];
03150 num_a++;
03151 } else {
03152
03153 cap_b_center += vpos[i];
03154 num_b++;
03155 }
03156 }
03157 }
03158
03159 if (num_a > 0 && num_b > 0) {
03160 cap_a_center /= (double)num_a;
03161 cap_b_center /= (double)num_b;
03162
03163
03164
03165 LVector3d axis = cap_b_center - cap_a_center;
03166 axis.normalize();
03167
03168
03169
03170 if (IS_THRESHOLD_ZERO(axis[0], 0.01)) {
03171 axis[0] = 0.0;
03172 }
03173 if (IS_THRESHOLD_ZERO(axis[1], 0.01)) {
03174 axis[1] = 0.0;
03175 }
03176 if (IS_THRESHOLD_ZERO(axis[2], 0.01)) {
03177 axis[2] = 0.0;
03178 }
03179 axis.normalize();
03180
03181
03182
03183
03184
03185
03186
03187
03188 LMatrix4d mat;
03189 look_at(mat, axis, LVector3d(0.0, 0.0, 1.0), CS_zup_right);
03190 mat.set_row(3, center);
03191 LMatrix4d inv_mat;
03192 inv_mat.invert_from(mat);
03193
03194 for (i = 0; i < num_vertices; i++) {
03195 vpos[i] = vpos[i] * inv_mat;
03196 }
03197
03198 double max_radius2 = 0.0;
03199
03200
03201 for (i = 0; i < num_vertices; i++) {
03202 LVector2d v(vpos[i][0], vpos[i][2]);
03203 double radius2 = v.length_squared();
03204 if (radius2 > max_radius2) {
03205 max_radius2 = radius2;
03206 }
03207 }
03208
03209
03210
03211
03212 double min_y = 0.0;
03213 double max_y = 0.0;
03214
03215 for (i = 0; i < num_vertices; i++) {
03216 LVector2d v(vpos[i][0], vpos[i][2]);
03217 double radius2 = v.length_squared();
03218
03219 if (vpos[i][1] < min_y) {
03220
03221
03222 double factor = sqrt(max_radius2 - radius2);
03223 min_y = min(min_y, vpos[i][1] + factor);
03224
03225 } else if (vpos[i][1] > max_y) {
03226 double factor = sqrt(max_radius2 - radius2);
03227 max_y = max(max_y, vpos[i][1] - factor);
03228 }
03229 }
03230
03231 double length = max_y - min_y;
03232 double radius = sqrt(max_radius2);
03233
03234
03235 LVector3d half = axis * (length / 2.0);
03236 LPoint3d point_a = center - half;
03237 LPoint3d point_b = center + half;
03238
03239 CollisionTube *cstube =
03240 new CollisionTube(LCAST(PN_stdfloat, point_a), LCAST(PN_stdfloat, point_b),
03241 radius);
03242 apply_collision_flags(cstube, flags);
03243 cnode->add_solid(cstube);
03244 }
03245 }
03246 }
03247 }
03248
03249
03250
03251
03252
03253
03254
03255
03256 void EggLoader::
03257 apply_collision_flags(CollisionSolid *solid, EggGroup::CollideFlags flags) {
03258 if ((flags & EggGroup::CF_intangible) != 0) {
03259 solid->set_tangible(false);
03260 }
03261 if ((flags & EggGroup::CF_level) != 0) {
03262 solid->set_effective_normal(LVector3::up());
03263 }
03264 }
03265
03266
03267
03268
03269
03270
03271
03272 EggGroup *EggLoader::
03273 find_collision_geometry(EggGroup *egg_group, EggGroup::CollideFlags flags) {
03274 if ((flags & EggGroup::CF_descend) != 0) {
03275
03276
03277 return egg_group;
03278 }
03279
03280
03281 EggGroup::const_iterator ci;
03282 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
03283 if ((*ci)->is_of_type(EggPolygon::get_class_type())) {
03284
03285 return egg_group;
03286 }
03287 }
03288
03289
03290
03291 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
03292 if ((*ci)->is_of_type(EggGroup::get_class_type())) {
03293 EggGroup *child_group = DCAST(EggGroup, *ci);
03294 if (child_group->get_cs_type() == egg_group->get_cs_type()) {
03295 return child_group;
03296 }
03297 }
03298 }
03299
03300
03301 return NULL;
03302 }
03303
03304
03305
03306
03307
03308
03309
03310 CollisionPlane *EggLoader::
03311 create_collision_plane(EggPolygon *egg_poly, EggGroup *parent_group) {
03312 if (!egg_poly->cleanup()) {
03313 egg2pg_cat.info()
03314 << "Ignoring degenerate collision plane in " << parent_group->get_name()
03315 << "\n";
03316 return NULL;
03317 }
03318
03319 if (!egg_poly->is_planar()) {
03320 egg2pg_cat.warning()
03321 << "Non-planar polygon defining collision plane in "
03322 << parent_group->get_name()
03323 << "\n";
03324 }
03325
03326 LMatrix4d mat = egg_poly->get_vertex_to_node();
03327
03328 pvector<LVertex> vertices;
03329 if (!egg_poly->empty()) {
03330 EggPolygon::const_iterator vi;
03331 vi = egg_poly->begin();
03332
03333 LVertexd vert = (*vi)->get_pos3() * mat;
03334 vertices.push_back(LCAST(PN_stdfloat, vert));
03335
03336 LVertexd last_vert = vert;
03337 ++vi;
03338 while (vi != egg_poly->end()) {
03339 vert = (*vi)->get_pos3() * mat;
03340 if (!vert.almost_equal(last_vert)) {
03341 vertices.push_back(LCAST(PN_stdfloat, vert));
03342 }
03343
03344 last_vert = vert;
03345 ++vi;
03346 }
03347 }
03348
03349 if (vertices.size() < 3) {
03350 return NULL;
03351 }
03352 LPlane plane(vertices[0], vertices[1], vertices[2]);
03353 return new CollisionPlane(plane);
03354 }
03355
03356
03357
03358
03359
03360
03361
03362
03363 void EggLoader::
03364 create_collision_polygons(CollisionNode *cnode, EggPolygon *egg_poly,
03365 EggGroup *parent_group,
03366 EggGroup::CollideFlags flags) {
03367 LMatrix4d mat = egg_poly->get_vertex_to_node();
03368
03369 PT(EggGroup) group = new EggGroup;
03370
03371 if (!egg_poly->triangulate_into(group, false)) {
03372 egg2pg_cat.info()
03373 << "Ignoring degenerate collision polygon in "
03374 << parent_group->get_name()
03375 << "\n";
03376 return;
03377 }
03378
03379 if (group->size() != 1) {
03380 egg2pg_cat.info()
03381 << "Triangulating concave or non-planar collision polygon in "
03382 << parent_group->get_name()
03383 << "\n";
03384 }
03385
03386 EggGroup::iterator ci;
03387 for (ci = group->begin(); ci != group->end(); ++ci) {
03388 EggPolygon *poly = DCAST(EggPolygon, *ci);
03389
03390 pvector<LVertex> vertices;
03391 if (!poly->empty()) {
03392 EggPolygon::const_iterator vi;
03393 vi = poly->begin();
03394
03395 LVertexd vert = (*vi)->get_pos3() * mat;
03396 vertices.push_back(LCAST(PN_stdfloat, vert));
03397
03398 LVertexd last_vert = vert;
03399 ++vi;
03400 while (vi != poly->end()) {
03401 vert = (*vi)->get_pos3() * mat;
03402 if (!vert.almost_equal(last_vert)) {
03403 vertices.push_back(LCAST(PN_stdfloat, vert));
03404 }
03405
03406 last_vert = vert;
03407 ++vi;
03408 }
03409 }
03410
03411 if (vertices.size() >= 3) {
03412 const LVertex *vertices_begin = &vertices[0];
03413 const LVertex *vertices_end = vertices_begin + vertices.size();
03414 PT(CollisionPolygon) cspoly =
03415 new CollisionPolygon(vertices_begin, vertices_end);
03416 if (cspoly->is_valid()) {
03417 apply_collision_flags(cspoly, flags);
03418 cnode->add_solid(cspoly);
03419 }
03420 }
03421 }
03422 }
03423
03424
03425
03426
03427
03428
03429
03430
03431
03432 void EggLoader::
03433 create_collision_floor_mesh(CollisionNode *cnode,
03434 EggGroup *parent_group,
03435 EggGroup::CollideFlags flags) {
03436
03437 PT(EggGroup) group = new EggGroup;
03438 EggVertexPool pool("floorMesh");
03439 pool.local_object();
03440 EggGroup::const_iterator egi;
03441 for (egi = parent_group->begin(); egi != parent_group->end(); ++egi) {
03442 if ((*egi)->is_of_type(EggPolygon::get_class_type())) {
03443 EggPolygon * poly = DCAST(EggPolygon, *egi);
03444 if (!poly->triangulate_into(group, false)) {
03445 egg2pg_cat.info()
03446 << "Ignoring degenerate collision polygon in "
03447 << parent_group->get_name()
03448 << "\n";
03449 return;
03450 }
03451
03452 }
03453 }
03454 if(group->size() == 0) {
03455 egg2pg_cat.info()
03456 << "empty collision solid\n";
03457 return;
03458 }
03459 PT(CollisionFloorMesh) cm = new CollisionFloorMesh;
03460 pvector<CollisionFloorMesh::TriangleIndices> triangles;
03461
03462 EggGroup::iterator ci;
03463 for (ci = group->begin(); ci != group->end(); ++ci) {
03464 EggPolygon *poly = DCAST(EggPolygon, *ci);
03465 if (poly->get_num_vertices() == 3) {
03466 CollisionFloorMesh::TriangleIndices tri;
03467
03468
03469 tri.p1=pool.create_unique_vertex(*poly->get_vertex(0))->get_index();
03470 tri.p2=pool.create_unique_vertex(*poly->get_vertex(1))->get_index();
03471 tri.p3=pool.create_unique_vertex(*poly->get_vertex(2))->get_index();
03472
03473 triangles.push_back(tri);
03474 } else if (poly->get_num_vertices() == 4) {
03475
03476
03477 CollisionFloorMesh::TriangleIndices tri;
03478 CollisionFloorMesh::TriangleIndices tri2;
03479
03480
03481 tri.p1=pool.create_unique_vertex(*poly->get_vertex(0))->get_index();
03482 tri.p2=pool.create_unique_vertex(*poly->get_vertex(1))->get_index();
03483 tri.p3=pool.create_unique_vertex(*poly->get_vertex(2))->get_index();
03484
03485 triangles.push_back(tri);
03486
03487
03488 tri2.p1=tri.p1;
03489 tri2.p2=tri.p3;
03490 tri2.p3=pool.create_unique_vertex(*poly->get_vertex(3))->get_index();
03491
03492
03493 triangles.push_back(tri2);
03494 }
03495 }
03496
03497
03498 PT(CollisionFloorMesh) csfloor = new CollisionFloorMesh;
03499
03500
03501 EggVertexPool::const_iterator vi;
03502 for (vi = pool.begin(); vi != pool.end(); vi++) {
03503 csfloor->add_vertex(LCAST(PN_stdfloat,(*vi)->get_pos3()));
03504 }
03505
03506 pvector<CollisionFloorMesh::TriangleIndices>::iterator ti;
03507
03508 for (ti = triangles.begin(); ti != triangles.end(); ti++) {
03509 CollisionFloorMesh::TriangleIndices triangle = *ti;
03510 csfloor->add_triangle(triangle.p1, triangle.p2, triangle.p3);
03511 }
03512 cnode->add_solid(csfloor);
03513 }
03514
03515
03516
03517
03518
03519
03520
03521
03522
03523 void EggLoader::
03524 apply_deferred_nodes(PandaNode *node, const DeferredNodeProperty &prop) {
03525 DeferredNodeProperty next_prop(prop);
03526
03527
03528 DeferredNodes::const_iterator dni;
03529 dni = _deferred_nodes.find(node);
03530
03531 if (dni != _deferred_nodes.end()) {
03532 const DeferredNodeProperty &def = (*dni).second;
03533 next_prop.compose(def);
03534 }
03535
03536
03537 next_prop.apply_to_node(node);
03538
03539 int num_children = node->get_num_children();
03540 for (int i = 0; i < num_children; i++) {
03541 apply_deferred_nodes(node->get_child(i), next_prop);
03542 }
03543 }
03544
03545
03546
03547
03548
03549
03550
03551
03552
03553
03554
03555
03556 bool EggLoader::
03557 expand_all_object_types(EggNode *egg_node) {
03558 if (egg_node->is_of_type(EggGroup::get_class_type())) {
03559 EggGroup *egg_group = DCAST(EggGroup, egg_node);
03560
03561 if (egg_group->get_num_object_types() != 0) {
03562 pset<string> expanded;
03563 pvector<string> expanded_history;
03564 if (!expand_object_types(egg_group, expanded, expanded_history)) {
03565 return false;
03566 }
03567 }
03568 }
03569
03570
03571
03572 if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
03573 EggGroupNode *egg_group_node = DCAST(EggGroupNode, egg_node);
03574 EggGroupNode::const_iterator ci;
03575 ci = egg_group_node->begin();
03576 while (ci != egg_group_node->end()) {
03577 EggGroupNode::const_iterator cnext = ci;
03578 ++cnext;
03579
03580 if (!expand_all_object_types(*ci)) {
03581
03582 egg_group_node->erase(ci);
03583 }
03584 ci = cnext;
03585 }
03586 }
03587
03588 return true;
03589 }
03590
03591
03592
03593
03594
03595
03596
03597
03598
03599
03600
03601
03602
03603 bool EggLoader::
03604 expand_object_types(EggGroup *egg_group, const pset<string> &expanded,
03605 const pvector<string> &expanded_history) {
03606 int num_object_types = egg_group->get_num_object_types();
03607
03608
03609
03610 vector_string object_types;
03611 int i;
03612 for (i = 0; i < num_object_types; i++) {
03613 object_types.push_back(egg_group->get_object_type(i));
03614 }
03615 egg_group->clear_object_types();
03616
03617 for (i = 0; i < num_object_types; i++) {
03618 string object_type = object_types[i];
03619 pset<string> new_expanded(expanded);
03620
03621
03622 if (!new_expanded.insert(object_type).second) {
03623 egg2pg_cat.error()
03624 << "Cycle in ObjectType expansions:\n";
03625 pvector<string>::const_iterator pi;
03626 for (pi = expanded_history.begin();
03627 pi != expanded_history.end();
03628 ++pi) {
03629 egg2pg_cat.error(false)
03630 << (*pi) << " -> ";
03631 }
03632 egg2pg_cat.error(false) << object_type << "\n";
03633 _error = true;
03634
03635 } else {
03636
03637 pvector<string> new_expanded_history(expanded_history);
03638 new_expanded_history.push_back(object_type);
03639
03640 if (!do_expand_object_type(egg_group, new_expanded,
03641 new_expanded_history, object_type)) {
03642
03643 return false;
03644 }
03645 }
03646 }
03647
03648 return true;
03649 }
03650
03651
03652
03653
03654
03655
03656 bool EggLoader::
03657 do_expand_object_type(EggGroup *egg_group, const pset<string> &expanded,
03658 const pvector<string> &expanded_history,
03659 const string &object_type) {
03660
03661
03662
03663 ConfigVariableString egg_object_type
03664 ("egg-object-type-" + downcase(object_type), "");
03665 string egg_syntax = egg_object_type;
03666
03667 if (!egg_object_type.has_value()) {
03668
03669
03670 if (cmp_nocase_uh(object_type, "barrier") == 0) {
03671 egg_syntax = "<Collide> { Polyset descend }";
03672
03673 } else if (cmp_nocase_uh(object_type, "solidpoly") == 0) {
03674 egg_syntax = "<Collide> { Polyset descend solid }";
03675
03676 } else if (cmp_nocase_uh(object_type, "turnstile") == 0) {
03677 egg_syntax = "<Collide> { Polyset descend turnstile }";
03678
03679 } else if (cmp_nocase_uh(object_type, "sphere") == 0) {
03680 egg_syntax = "<Collide> { Sphere descend }";
03681
03682 } else if (cmp_nocase_uh(object_type, "tube") == 0) {
03683 egg_syntax = "<Collide> { Tube descend }";
03684
03685 } else if (cmp_nocase_uh(object_type, "trigger") == 0) {
03686 egg_syntax = "<Collide> { Polyset descend intangible }";
03687
03688 } else if (cmp_nocase_uh(object_type, "trigger_sphere") == 0) {
03689 egg_syntax = "<Collide> { Sphere descend intangible }";
03690
03691 } else if (cmp_nocase_uh(object_type, "eye_trigger") == 0) {
03692 egg_syntax = "<Collide> { Polyset descend intangible center }";
03693
03694 } else if (cmp_nocase_uh(object_type, "bubble") == 0) {
03695 egg_syntax = "<Collide> { Sphere keep descend }";
03696
03697 } else if (cmp_nocase_uh(object_type, "ghost") == 0) {
03698 egg_syntax = "<Scalar> collide-mask { 0 }";
03699
03700 } else if (cmp_nocase_uh(object_type, "dcs") == 0) {
03701 egg_syntax = "<DCS> { 1 }";
03702
03703 } else if (cmp_nocase_uh(object_type, "model") == 0) {
03704 egg_syntax = "<Model> { 1 }";
03705
03706 } else if (cmp_nocase_uh(object_type, "none") == 0) {
03707
03708 return true;
03709
03710 } else if (cmp_nocase_uh(object_type, "backstage") == 0) {
03711
03712 return false;
03713
03714 } else {
03715 egg2pg_cat.error()
03716 << "Unknown ObjectType " << object_type << "\n";
03717 _error = true;
03718 egg2pg_cat.debug() << "returning true\n";
03719 return true;
03720 }
03721 }
03722
03723 if (!egg_syntax.empty()) {
03724 if (!egg_group->parse_egg(egg_syntax)) {
03725 egg2pg_cat.error()
03726 << "Error while parsing definition for ObjectType "
03727 << object_type << "\n";
03728 _error = true;
03729
03730 } else {
03731
03732
03733 if (egg_group->get_num_object_types() != 0) {
03734 if (!expand_object_types(egg_group, expanded, expanded_history)) {
03735 return false;
03736 }
03737 }
03738 }
03739 }
03740
03741 return true;
03742 }
03743
03744
03745
03746
03747
03748
03749
03750 TextureStage::CombineMode EggLoader::
03751 get_combine_mode(const EggTexture *egg_tex,
03752 EggTexture::CombineChannel channel) {
03753 switch (egg_tex->get_combine_mode(channel)) {
03754 case EggTexture::CM_unspecified:
03755
03756
03757 case EggTexture::CM_modulate:
03758 return TextureStage::CM_modulate;
03759
03760 case EggTexture::CM_replace:
03761 return TextureStage::CM_replace;
03762
03763 case EggTexture::CM_add:
03764 return TextureStage::CM_add;
03765
03766 case EggTexture::CM_add_signed:
03767 return TextureStage::CM_add_signed;
03768
03769 case EggTexture::CM_interpolate:
03770 return TextureStage::CM_interpolate;
03771
03772 case EggTexture::CM_subtract:
03773 return TextureStage::CM_subtract;
03774
03775 case EggTexture::CM_dot3_rgb:
03776 return TextureStage::CM_dot3_rgb;
03777
03778 case EggTexture::CM_dot3_rgba:
03779 return TextureStage::CM_dot3_rgba;
03780 };
03781
03782 return TextureStage::CM_undefined;
03783 }
03784
03785
03786
03787
03788
03789
03790
03791 TextureStage::CombineSource EggLoader::
03792 get_combine_source(const EggTexture *egg_tex,
03793 EggTexture::CombineChannel channel, int n) {
03794 switch (egg_tex->get_combine_source(channel, n)) {
03795 case EggTexture::CS_unspecified:
03796
03797
03798 switch (n) {
03799 case 0:
03800 return TextureStage::CS_previous;
03801 case 1:
03802 return TextureStage::CS_texture;
03803 case 2:
03804 return TextureStage::CS_constant;
03805 }
03806
03807
03808 case EggTexture::CS_texture:
03809 return TextureStage::CS_texture;
03810
03811 case EggTexture::CS_constant:
03812 return TextureStage::CS_constant;
03813
03814 case EggTexture::CS_primary_color:
03815 return TextureStage::CS_primary_color;
03816
03817 case EggTexture::CS_previous:
03818 return TextureStage::CS_previous;
03819
03820 case EggTexture::CS_constant_color_scale:
03821 return TextureStage::CS_constant_color_scale;
03822
03823 case EggTexture::CS_last_saved_result:
03824 return TextureStage::CS_last_saved_result;
03825 };
03826
03827 return TextureStage::CS_undefined;
03828 }
03829
03830
03831
03832
03833
03834
03835
03836 TextureStage::CombineOperand EggLoader::
03837 get_combine_operand(const EggTexture *egg_tex,
03838 EggTexture::CombineChannel channel, int n) {
03839 switch (egg_tex->get_combine_operand(channel, n)) {
03840 case EggTexture::CS_unspecified:
03841 if (channel == EggTexture::CC_rgb) {
03842
03843
03844 return n < 2 ? TextureStage::CO_src_color : TextureStage::CO_src_alpha;
03845 } else {
03846
03847 return TextureStage::CO_src_alpha;
03848 }
03849
03850 case EggTexture::CO_src_color:
03851 return TextureStage::CO_src_color;
03852
03853 case EggTexture::CO_one_minus_src_color:
03854 return TextureStage::CO_one_minus_src_color;
03855
03856 case EggTexture::CO_src_alpha:
03857 return TextureStage::CO_src_alpha;
03858
03859 case EggTexture::CO_one_minus_src_alpha:
03860 return TextureStage::CO_one_minus_src_alpha;
03861 };
03862
03863 return TextureStage::CO_undefined;
03864 }
03865
03866
03867
03868
03869
03870
03871
03872 ColorBlendAttrib::Mode EggLoader::
03873 get_color_blend_mode(EggGroup::BlendMode mode) {
03874 switch (mode) {
03875 case EggGroup::BM_unspecified:
03876 case EggGroup::BM_none:
03877 return ColorBlendAttrib::M_none;
03878 case EggGroup::BM_add:
03879 return ColorBlendAttrib::M_add;
03880 case EggGroup::BM_subtract:
03881 return ColorBlendAttrib::M_subtract;
03882 case EggGroup::BM_inv_subtract:
03883 return ColorBlendAttrib::M_inv_subtract;
03884 case EggGroup::BM_min:
03885 return ColorBlendAttrib::M_min;
03886 case EggGroup::BM_max:
03887 return ColorBlendAttrib::M_max;
03888 }
03889
03890 return ColorBlendAttrib::M_none;
03891 }
03892
03893
03894
03895
03896
03897
03898
03899 ColorBlendAttrib::Operand EggLoader::
03900 get_color_blend_operand(EggGroup::BlendOperand operand) {
03901 switch (operand) {
03902 case EggGroup::BO_zero:
03903 return ColorBlendAttrib::O_zero;
03904 case EggGroup::BO_unspecified:
03905 case EggGroup::BO_one:
03906 return ColorBlendAttrib::O_one;
03907 case EggGroup::BO_incoming_color:
03908 return ColorBlendAttrib::O_incoming_color;
03909 case EggGroup::BO_one_minus_incoming_color:
03910 return ColorBlendAttrib::O_one_minus_incoming_color;
03911 case EggGroup::BO_fbuffer_color:
03912 return ColorBlendAttrib::O_fbuffer_color;
03913 case EggGroup::BO_one_minus_fbuffer_color:
03914 return ColorBlendAttrib::O_one_minus_fbuffer_color;
03915 case EggGroup::BO_incoming_alpha:
03916 return ColorBlendAttrib::O_incoming_alpha;
03917 case EggGroup::BO_one_minus_incoming_alpha:
03918 return ColorBlendAttrib::O_one_minus_incoming_alpha;
03919 case EggGroup::BO_fbuffer_alpha:
03920 return ColorBlendAttrib::O_fbuffer_alpha;
03921 case EggGroup::BO_one_minus_fbuffer_alpha:
03922 return ColorBlendAttrib::O_one_minus_fbuffer_alpha;
03923 case EggGroup::BO_constant_color:
03924 return ColorBlendAttrib::O_constant_color;
03925 case EggGroup::BO_one_minus_constant_color:
03926 return ColorBlendAttrib::O_one_minus_constant_color;
03927 case EggGroup::BO_constant_alpha:
03928 return ColorBlendAttrib::O_constant_alpha;
03929 case EggGroup::BO_one_minus_constant_alpha:
03930 return ColorBlendAttrib::O_one_minus_constant_alpha;
03931 case EggGroup::BO_incoming_color_saturate:
03932 return ColorBlendAttrib::O_incoming_color_saturate;
03933 case EggGroup::BO_color_scale:
03934 return ColorBlendAttrib::O_color_scale;
03935 case EggGroup::BO_one_minus_color_scale:
03936 return ColorBlendAttrib::O_one_minus_color_scale;
03937 case EggGroup::BO_alpha_scale:
03938 return ColorBlendAttrib::O_alpha_scale;
03939 case EggGroup::BO_one_minus_alpha_scale:
03940 return ColorBlendAttrib::O_one_minus_alpha_scale;
03941 }
03942
03943 return ColorBlendAttrib::O_zero;
03944 }
03945
03946
03947
03948
03949
03950
03951 bool EggLoader::VertexPoolTransform::
03952 operator < (const EggLoader::VertexPoolTransform &other) const {
03953 if (_vertex_pool != other._vertex_pool) {
03954 return _vertex_pool < other._vertex_pool;
03955 }
03956 int compare = _transform.compare_to(other._transform, 0.001);
03957 if (compare != 0) {
03958 return compare < 0;
03959 }
03960
03961 if (_bake_in_uvs.size() != other._bake_in_uvs.size()) {
03962 return _bake_in_uvs.size() < other._bake_in_uvs.size();
03963 }
03964
03965 BakeInUVs::const_iterator ai, bi;
03966 ai = _bake_in_uvs.begin();
03967 bi = other._bake_in_uvs.begin();
03968 while (ai != _bake_in_uvs.end()) {
03969 nassertr(bi != other._bake_in_uvs.end(), false);
03970 if ((*ai) != (*bi)) {
03971 return (*ai) < (*bi);
03972 }
03973 ++ai;
03974 ++bi;
03975 }
03976 nassertr(bi == other._bake_in_uvs.end(), false);
03977
03978 return false;
03979 }