Panda3D
 All Classes Functions Variables Enumerations
eggSaver.cxx
1 // Filename: eggSaver.cxx
2 // Created by: drose (19Dec12)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "eggSaver.h"
16 
17 #include "pandaNode.h"
18 #include "workingNodePath.h"
19 #include "nodePath.h"
20 #include "billboardEffect.h"
21 #include "renderEffects.h"
22 #include "transformState.h"
23 #include "colorScaleAttrib.h"
24 #include "colorAttrib.h"
25 #include "materialAttrib.h"
26 #include "textureAttrib.h"
27 #include "cullFaceAttrib.h"
28 #include "transparencyAttrib.h"
29 #include "depthWriteAttrib.h"
30 #include "lodNode.h"
31 #include "switchNode.h"
32 #include "sequenceNode.h"
33 #include "collisionNode.h"
34 #include "collisionPolygon.h"
35 #include "collisionPlane.h"
36 #include "collisionSphere.h"
37 #include "collisionBox.h"
38 #include "collisionInvSphere.h"
39 #include "collisionTube.h"
40 #include "textureStage.h"
41 #include "geomNode.h"
42 #include "geom.h"
43 #include "geomTriangles.h"
44 #include "geomPatches.h"
45 #include "geomPoints.h"
46 #include "geomLines.h"
47 #include "geomVertexReader.h"
48 #include "transformTable.h"
49 #include "modelNode.h"
50 #include "animBundleNode.h"
51 #include "animChannelMatrixXfmTable.h"
52 #include "characterJoint.h"
53 #include "character.h"
54 #include "string_utils.h"
55 #include "bamFile.h"
56 #include "bamCacheRecord.h"
57 #include "eggSAnimData.h"
58 #include "eggXfmAnimData.h"
59 #include "eggXfmSAnim.h"
60 #include "eggGroup.h"
61 #include "eggVertexPool.h"
62 #include "eggVertex.h"
63 #include "eggPrimitive.h"
64 #include "eggPolygon.h"
65 #include "eggPatch.h"
66 #include "eggPoint.h"
67 #include "eggLine.h"
68 #include "eggTexture.h"
69 #include "eggMaterial.h"
70 #include "eggRenderMode.h"
71 #include "eggTable.h"
72 #include "dcast.h"
73 
74 ////////////////////////////////////////////////////////////////////
75 // Function: EggSaver::Constructor
76 // Access: Published
77 // Description:
78 ////////////////////////////////////////////////////////////////////
79 EggSaver::
80 EggSaver(EggData *data) :
81  _data(data)
82 {
83  if (_data == NULL) {
84  _data = new EggData;
85  }
86 }
87 
88 ////////////////////////////////////////////////////////////////////
89 // Function: EggSaver::add_node
90 // Access: Published
91 // Description: Adds the scene graph rooted at the indicated node to
92 // the accumulated egg data within this object. Call
93 // get_egg_data() to retrieve the result.
94 ////////////////////////////////////////////////////////////////////
95 void EggSaver::
97  _vpool = new EggVertexPool(node->get_name());
98  _data->add_child(_vpool);
99 
100  NodePath root(node);
101  convert_node(WorkingNodePath(root), _data, false);
102 
103  // Remove the vertex pool if it has no vertices.
104  if (_vpool->empty()) {
105  _data->remove_child(_vpool);
106  }
107  _vpool = NULL;
108 }
109 
110 ////////////////////////////////////////////////////////////////////
111 // Function: EggSaver::convert_node
112 // Access: Private
113 // Description: Converts the indicated node to the corresponding Egg
114 // constructs, by first determining what kind of node it
115 // is.
116 ////////////////////////////////////////////////////////////////////
117 void EggSaver::
118 convert_node(const WorkingNodePath &node_path, EggGroupNode *egg_parent,
119  bool has_decal) {
120  PandaNode *node = node_path.node();
121  if (node->is_geom_node()) {
122  convert_geom_node(DCAST(GeomNode, node), node_path, egg_parent, has_decal);
123 
124  } else if (node->is_of_type(LODNode::get_class_type())) {
125  convert_lod_node(DCAST(LODNode, node), node_path, egg_parent, has_decal);
126 
127  } else if (node->is_of_type(SequenceNode::get_class_type())) {
128  convert_sequence_node(DCAST(SequenceNode, node), node_path, egg_parent, has_decal);
129 
130  } else if (node->is_of_type(SwitchNode::get_class_type())) {
131  convert_switch_node(DCAST(SwitchNode, node), node_path, egg_parent, has_decal);
132 
133  } else if (node->is_of_type(CollisionNode::get_class_type())) {
134  convert_collision_node(DCAST(CollisionNode, node), node_path, egg_parent, has_decal);
135 
136  } else if (node->is_of_type(AnimBundleNode::get_class_type())) {
137  convert_anim_node(DCAST(AnimBundleNode, node), node_path, egg_parent, has_decal);
138 
139  } else if (node->is_of_type(Character::get_class_type())) {
140  convert_character_node(DCAST(Character, node), node_path, egg_parent, has_decal);
141 
142  } else {
143  // Just a generic node.
144  EggGroup *egg_group = new EggGroup(node->get_name());
145  egg_parent->add_child(egg_group);
146  apply_node_properties(egg_group, node);
147 
148  recurse_nodes(node_path, egg_group, has_decal);
149  }
150 }
151 
152 ////////////////////////////////////////////////////////////////////
153 // Function: EggSaver::convert_lod_node
154 // Access: Private
155 // Description: Converts the indicated LODNode to the corresponding
156 // Egg constructs.
157 ////////////////////////////////////////////////////////////////////
158 void EggSaver::
159 convert_lod_node(LODNode *node, const WorkingNodePath &node_path,
160  EggGroupNode *egg_parent, bool has_decal) {
161  // An LOD node gets converted to an ordinary EggGroup, but we apply
162  // the appropriate switch conditions to each of our children.
163  EggGroup *egg_group = new EggGroup(node->get_name());
164  egg_parent->add_child(egg_group);
165  apply_node_properties(egg_group, node);
166 
167  int num_children = node->get_num_children();
168  int num_switches = node->get_num_switches();
169 
170  num_children = min(num_children, num_switches);
171 
172  for (int i = 0; i < num_children; i++) {
173  PandaNode *child = node->get_child(i);
174 
175  // Convert just this one node to an EggGroup.
176  PT(EggGroup) next_group = new EggGroup;
177  convert_node(WorkingNodePath(node_path, child), next_group, has_decal);
178 
179  if (next_group->size() == 1) {
180  // If we have exactly one child, and that child is an EggGroup,
181  // collapse.
182  EggNode *child_node = *next_group->begin();
183  if (child_node->is_of_type(EggGroup::get_class_type())) {
184  PT(EggGroup) child = DCAST(EggGroup, child_node);
185  next_group->remove_child(child.p());
186  next_group = child;
187  }
188  }
189 
190  // Now set up the switching properties appropriately.
191  PN_stdfloat in = node->get_in(i);
192  PN_stdfloat out = node->get_out(i);
193  LPoint3 center = node->get_center();
194  EggSwitchConditionDistance dist(in, out, LCAST(double, center));
195  next_group->set_lod(dist);
196  egg_group->add_child(next_group.p());
197  }
198 }
199 
200 ////////////////////////////////////////////////////////////////////
201 // Function: EggSaver::convert_sequence_node
202 // Access: Private
203 // Description: Converts the indicated SequenceNode to the corresponding
204 // Egg constructs.
205 ////////////////////////////////////////////////////////////////////
206 void EggSaver::
207 convert_sequence_node(SequenceNode *node, const WorkingNodePath &node_path,
208  EggGroupNode *egg_parent, bool has_decal) {
209  // A sequence node gets converted to an ordinary EggGroup, we only apply
210  // the appropriate switch attributes to turn it into a sequence
211  EggGroup *egg_group = new EggGroup(node->get_name());
212  egg_parent->add_child(egg_group);
213  apply_node_properties(egg_group, node);
214 
215  // turn it into a sequence with the right frame-rate
216  egg_group->set_switch_flag(true);
217  egg_group->set_switch_fps(node->get_frame_rate());
218 
219  int num_children = node->get_num_children();
220 
221  for (int i = 0; i < num_children; i++) {
222  PandaNode *child = node->get_child(i);
223 
224  // Convert just this one node to an EggGroup.
225  PT(EggGroup) next_group = new EggGroup;
226  convert_node(WorkingNodePath(node_path, child), next_group, has_decal);
227 
228  egg_group->add_child(next_group.p());
229  }
230 
231 }
232 
233 ////////////////////////////////////////////////////////////////////
234 // Function: EggSaver::convert_switch_node
235 // Access: Private
236 // Description: Converts the indicated SwitchNode to the corresponding
237 // Egg constructs.
238 ////////////////////////////////////////////////////////////////////
239 void EggSaver::
240 convert_switch_node(SwitchNode *node, const WorkingNodePath &node_path,
241  EggGroupNode *egg_parent, bool has_decal) {
242  // A sequence node gets converted to an ordinary EggGroup, we only apply
243  // the appropriate switch attributes to turn it into a sequence
244  EggGroup *egg_group = new EggGroup(node->get_name());
245  egg_parent->add_child(egg_group);
246  apply_node_properties(egg_group, node);
247 
248  // turn it into a switch..
249  egg_group->set_switch_flag(true);
250 
251  int num_children = node->get_num_children();
252 
253  for (int i = 0; i < num_children; i++) {
254  PandaNode *child = node->get_child(i);
255 
256  // Convert just this one node to an EggGroup.
257  PT(EggGroup) next_group = new EggGroup;
258  convert_node(WorkingNodePath(node_path, child), next_group, has_decal);
259 
260  egg_group->add_child(next_group.p());
261  }
262 }
263 
264 ////////////////////////////////////////////////////////////////////
265 // Function: EggSaver::convert_animGroup_node
266 // Access: Private
267 // Description: Converts the indicated AnimationGroupNodes to the corresponding
268 // Egg constructs.
269 ////////////////////////////////////////////////////////////////////
270 EggGroupNode * EggSaver::convert_animGroup_node(AnimGroup *animGroup, double fps ) {
271  int num_children = animGroup->get_num_children();
272 
273  EggGroupNode *eggNode = NULL;
274  if (animGroup->is_of_type(AnimBundle::get_class_type())) {
275  EggTable *eggTable = new EggTable(animGroup->get_name());
276  eggTable ->set_table_type(EggTable::TT_bundle);
277  eggNode = eggTable;
278  } else if (animGroup->is_of_type(AnimGroup::get_class_type())) {
279  EggTable *eggTable = new EggTable(animGroup->get_name());
280  eggTable ->set_table_type(EggTable::TT_table);
281  eggNode = eggTable;
282  }
283 
284  if (animGroup->is_of_type(AnimChannelMatrixXfmTable::get_class_type())) {
285  AnimChannelMatrixXfmTable *xmfTable = DCAST(AnimChannelMatrixXfmTable, animGroup);
286  EggXfmSAnim *egg_anim = new EggXfmSAnim("xform");
287  egg_anim->set_fps(fps);
288  for (int i = 0; i < num_matrix_components; i++) {
289  string componentName(1, matrix_component_letters[i]);
290  char table_id = matrix_component_letters[i];
291  CPTA_stdfloat table = xmfTable->get_table(table_id);
292 
293  if (xmfTable->has_table(table_id)) {
294  for (unsigned int j = 0; j < table.size(); j++) {
295  egg_anim->add_component_data(componentName, table[(int)j]);
296  }
297  }
298  }
299  eggNode->add_child(egg_anim);
300  }
301  for (int i = 0; i < num_children; i++) {
302  AnimGroup *animChild = animGroup->get_child(i);
303  EggGroupNode *eggChildNode = convert_animGroup_node(animChild, fps);
304  if (eggChildNode!=NULL) {
305  nassertr(eggNode!=NULL, NULL);
306  eggNode->add_child(eggChildNode);
307  }
308  }
309  return eggNode;
310 }
311 
312 ////////////////////////////////////////////////////////////////////
313 // Function: EggSaver::convert_anim_node
314 // Access: Private
315 // Description: Converts the indicated AnimNode to the corresponding
316 // Egg constructs.
317 ////////////////////////////////////////////////////////////////////
318 void EggSaver::
319 convert_anim_node(AnimBundleNode *node, const WorkingNodePath &node_path,
320  EggGroupNode *egg_parent, bool has_decal) {
321 
322  // A sequence node gets converted to an ordinary EggGroup, we only apply
323  // the appropriate switch attributes to turn it into a sequence
324  EggTable *eggTable = new EggTable();
325  //egg_parent->add_child(eggTable);
326  _data->add_child(eggTable);
327 
328  AnimBundle *animBundle = node->get_bundle();
329  // turn it into a switch..
330  //egg_group->set_switch_flag(true);
331 
332  EggGroupNode *eggAnimation = convert_animGroup_node(animBundle, animBundle->get_base_frame_rate());
333  eggTable->add_child(eggAnimation);
334 }
335 
336 ////////////////////////////////////////////////////////////////////
337 // Function: EggSaver::convert_character_bundle
338 // Access: Private
339 // Description: Converts the indicated Character Bundle to the corresponding
340 // Egg joints structure.
341 ////////////////////////////////////////////////////////////////////
342 void EggSaver::
343 convert_character_bundle(PartGroup *bundleNode, EggGroupNode *egg_parent, CharacterJointMap *jointMap) {
344  int num_children = bundleNode->get_num_children();
345 
346  EggGroupNode *joint_group = egg_parent;
347  if (bundleNode->is_of_type(CharacterJoint::get_class_type())) {
348  CharacterJoint *character_joint = DCAST(CharacterJoint, bundleNode);
349 
350  LMatrix4 transformf;
351  character_joint->get_transform(transformf);
352  LMatrix4d transformd(LCAST(double, transformf));
353  EggGroup *joint = new EggGroup(bundleNode->get_name());
354  joint->add_matrix4(transformd);
355  joint->set_group_type(EggGroup::GT_joint);
356  joint_group = joint;
357  egg_parent->add_child(joint_group);
358  if (jointMap!=NULL) {
359  CharacterJointMap::iterator mi = jointMap->find(character_joint);
360  if (mi != jointMap->end()) {
361  pvector<pair<EggVertex*,PN_stdfloat> > &joint_vertices = (*mi).second;
362  pvector<pair<EggVertex*,PN_stdfloat> >::const_iterator vi;
363  for (vi = joint_vertices.begin(); vi != joint_vertices.end(); ++vi) {
364  joint->set_vertex_membership((*vi).first, (*vi).second);
365  }
366  }
367  }
368  }
369 
370  for (int i = 0; i < num_children ; i++) {
371  PartGroup *partGroup= bundleNode->get_child(i);
372  convert_character_bundle(partGroup, joint_group, jointMap);
373  }
374 
375 }
376 
377 ////////////////////////////////////////////////////////////////////
378 // Function: EggSaver::convert_character_node
379 // Access: Private
380 // Description: Converts the indicated Character to the corresponding
381 // Egg constructs.
382 ////////////////////////////////////////////////////////////////////
383 void EggSaver::
384 convert_character_node(Character *node, const WorkingNodePath &node_path,
385  EggGroupNode *egg_parent, bool has_decal) {
386 
387  // A sequence node gets converted to an ordinary EggGroup, we only apply
388  // the appropriate switch attributes to turn it into a sequence
389  EggGroup *egg_group = new EggGroup(node->get_name());
390  egg_group->set_dart_type(EggGroup::DT_default);
391  egg_parent->add_child(egg_group);
392  apply_node_properties(egg_group, node);
393 
394  CharacterJointMap jointMap;
395 
396  // turn it into a switch..
397  //egg_group->set_switch_flag(true);
398 
399  int num_children = node->get_num_children();
400  int num_bundles = node->get_num_bundles();
401 
402  for (int i = 0; i < num_children; i++) {
403  PandaNode *child = node->get_child(i);
404 
405  if (child->is_geom_node()) {
406  convert_geom_node(DCAST(GeomNode, child), WorkingNodePath(node_path, child), egg_group, has_decal, &jointMap);
407  }
408  }
409 
410  for (int i = 0; i < num_bundles ; i++) {
411  PartBundle *bundle= node->get_bundle(i);
412  convert_character_bundle(bundle, egg_group, &jointMap);
413  }
414 
415 }
416 
417 
418 ////////////////////////////////////////////////////////////////////
419 // Function: EggSaver::convert_collision_node
420 // Access: Private
421 // Description: Converts the indicated CollisionNode to the corresponding
422 // Egg constructs.
423 ////////////////////////////////////////////////////////////////////
424 void EggSaver::
425 convert_collision_node(CollisionNode *node, const WorkingNodePath &node_path,
426  EggGroupNode *egg_parent, bool has_decal) {
427  // A sequence node gets converted to an ordinary EggGroup, we only apply
428  // the appropriate switch attributes to turn it into a sequence
429  EggGroup *egg_group = new EggGroup(node->get_name());
430  egg_parent->add_child(egg_group);
431  apply_node_properties(egg_group, node, false);
432 
433  // turn it into a collision node
434  egg_group->set_collide_flags(EggGroup::CF_descend);
435 
436  NodePath np = node_path.get_node_path();
437  CPT(TransformState) net_transform = np.get_net_transform();
438  LMatrix4 net_mat = net_transform->get_mat();
439  LMatrix4 inv = LCAST(PN_stdfloat, egg_parent->get_vertex_frame_inv());
440  net_mat = net_mat * inv;
441 
442  int num_solids = node->get_num_solids();
443 
444  if (num_solids > 0) {
445  // create vertex pool for collisions
446  EggVertexPool *cvpool = new EggVertexPool("vpool-collision");
447  egg_group->add_child(cvpool);
448 
449  // traverse solids
450  for (int i = 0; i < num_solids; i++) {
451  CPT(CollisionSolid) child = node->get_solid(i);
452  if (child->is_of_type(CollisionPolygon::get_class_type())) {
453  egg_group->set_cs_type(EggGroup::CST_polyset);
454 
455  EggPolygon *egg_poly = new EggPolygon;
456  egg_group->add_child(egg_poly);
457 
458  CPT(CollisionPolygon) poly = DCAST(CollisionPolygon, child);
459  int num_points = poly->get_num_points();
460  for (int j = 0; j < num_points; j++) {
461  EggVertex egg_vert;
462  egg_vert.set_pos(LCAST(double, poly->get_point(j) * net_mat));
463  egg_vert.set_normal(LCAST(double, poly->get_normal() * net_mat));
464 
465  EggVertex *new_egg_vert = cvpool->create_unique_vertex(egg_vert);
466  egg_poly->add_vertex(new_egg_vert);
467  }
468 
469  } else if (child->is_of_type(CollisionSphere::get_class_type())) {
470  CPT(CollisionSphere) sphere = DCAST(CollisionSphere, child);
471  LPoint3 center = sphere->get_center();
472  LVector3 offset(sphere->get_radius(), 0, 0);
473 
474  EggGroup *egg_sphere;
475  if (num_solids == 1) {
476  egg_sphere = egg_group;
477  } else {
478  egg_sphere = new EggGroup;
479  egg_sphere->set_collide_flags(EggGroup::CF_descend);
480  egg_group->add_child(egg_sphere);
481  }
482  egg_sphere->set_cs_type(EggGroup::CST_sphere);
483 
484  EggVertex ev1, ev2;
485  ev1.set_pos(LCAST(double, (center + offset) * net_mat));
486  ev2.set_pos(LCAST(double, (center - offset) * net_mat));
487 
488  EggPolygon *egg_poly = new EggPolygon;
489  egg_sphere->add_child(egg_poly);
490 
491  egg_poly->add_vertex(cvpool->create_unique_vertex(ev1));
492  egg_poly->add_vertex(cvpool->create_unique_vertex(ev2));
493 
494  } else if (child->is_of_type(CollisionPlane::get_class_type())) {
495  LPlane plane = DCAST(CollisionPlane, child)->get_plane();
496  LPoint3 origin = plane.get_point();
497  LVector3 normal = plane.get_normal();
498 
499  // Get an arbitrary vector on the plane by taking the cross product
500  // with any vector, as long as it is different.
501  LVector3 vec1;
502  if (abs(normal[2]) > abs(normal[1])) {
503  vec1 = normal.cross(LVector3(0, 1, 0));
504  } else {
505  vec1 = normal.cross(LVector3(0, 0, 1));
506  }
507 
508  // Find a second vector perpendicular to the two.
509  LVector3 vec2 = normal.cross(vec1);
510 
511  EggGroup *egg_plane;
512  if (num_solids == 1) {
513  egg_plane = egg_group;
514  } else {
515  egg_plane = new EggGroup;
516  egg_plane->set_collide_flags(EggGroup::CF_descend);
517  egg_group->add_child(egg_plane);
518  }
519  egg_plane->set_cs_type(EggGroup::CST_plane);
520 
521  EggVertex ev0, ev1, ev2;
522  ev0.set_pos(LCAST(double, origin * net_mat));
523  ev1.set_pos(LCAST(double, (origin + vec1) * net_mat));
524  ev2.set_pos(LCAST(double, (origin + vec2) * net_mat));
525 
526  EggPolygon *egg_poly = new EggPolygon;
527  egg_plane->add_child(egg_poly);
528 
529  egg_poly->add_vertex(cvpool->create_unique_vertex(ev0));
530  egg_poly->add_vertex(cvpool->create_unique_vertex(ev1));
531  egg_poly->add_vertex(cvpool->create_unique_vertex(ev2));
532 
533  } else if (child->is_of_type(CollisionBox::get_class_type())) {
534  nout << "Encountered unhandled collsion type: CollisionBox" << "\n";
535  } else if (child->is_of_type(CollisionInvSphere::get_class_type())) {
536  nout << "Encountered unhandled collsion type: CollisionInvSphere" << "\n";
537  } else if (child->is_of_type(CollisionTube::get_class_type())) {
538  nout << "Encountered unhandled collsion type: CollisionTube" << "\n";
539  } else {
540  nout << "Encountered unknown CollisionSolid" << "\n";
541  }
542  }
543  }
544 
545  // recurse over children - hm. do I need to do this?
546  recurse_nodes(node_path, egg_group, has_decal);
547 }
548 
549 ////////////////////////////////////////////////////////////////////
550 // Function: EggSaver::convert_geom_node
551 // Access: Private
552 // Description: Converts a GeomNode to the corresponding egg
553 // structures.
554 ////////////////////////////////////////////////////////////////////
555 void EggSaver::
556 convert_geom_node(GeomNode *node, const WorkingNodePath &node_path,
557  EggGroupNode *egg_parent, bool has_decal, CharacterJointMap *jointMap) {
558  PT(EggGroup) egg_group = new EggGroup(node->get_name());
559  bool fancy_attributes = apply_node_properties(egg_group, node);
560 
561  if (node->get_effects()->has_decal()) {
562  has_decal = true;
563  }
564 
565  if (has_decal) {
566  egg_group->set_decal_flag(true);
567  }
568 
569  if (fancy_attributes || has_decal || !node->get_name().empty()) {
570  // If we have any fancy attributes on the node, or if we're making
571  // decal geometry, we have to make a special node to hold the
572  // geometry (normally it would just appear within its parent).
573  egg_parent->add_child(egg_group.p());
574  egg_parent = egg_group;
575  }
576 
577  NodePath np = node_path.get_node_path();
578  CPT(RenderState) net_state = np.get_net_state();
579  CPT(TransformState) net_transform = np.get_net_transform();
580  LMatrix4 net_mat = net_transform->get_mat();
581  LMatrix4 inv = LCAST(PN_stdfloat, egg_parent->get_vertex_frame_inv());
582  net_mat = net_mat * inv;
583 
584  // Now get out all the various kinds of geometry.
585  int num_geoms = node->get_num_geoms();
586  for (int i = 0; i < num_geoms; ++i) {
587  CPT(RenderState) geom_state = net_state->compose(node->get_geom_state(i));
588 
589  const Geom *geom = node->get_geom(i);
590  int num_primitives = geom->get_num_primitives();
591  for (int j = 0; j < num_primitives; ++j) {
592  const GeomPrimitive *primitive = geom->get_primitive(j);
593  CPT(GeomPrimitive) simple = primitive->decompose();
594  CPT(GeomVertexData) vdata = geom->get_vertex_data();
595  // vdata = vdata->animate_vertices(true, Thread::get_current_thread());
596  convert_primitive(vdata, simple, geom_state,
597  net_mat, egg_parent, jointMap);
598  }
599  }
600 
601  recurse_nodes(node_path, egg_parent, has_decal);
602 }
603 
604 ////////////////////////////////////////////////////////////////////
605 // Function: EggSaver::convert_primitive
606 // Access: Private
607 // Description:
608 ////////////////////////////////////////////////////////////////////
609 void EggSaver::
610 convert_primitive(const GeomVertexData *vertex_data,
611  const GeomPrimitive *primitive,
612  const RenderState *net_state,
613  const LMatrix4 &net_mat, EggGroupNode *egg_parent,
614  CharacterJointMap *jointMap) {
615  GeomVertexReader reader(vertex_data);
616 
617  // Check for a color scale.
618  LVecBase4 color_scale(1.0f, 1.0f, 1.0f, 1.0f);
619  const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, net_state->get_attrib(ColorScaleAttrib::get_class_type()));
620  if (csa != (const ColorScaleAttrib *)NULL) {
621  color_scale = csa->get_scale();
622  }
623 
624  // Check for a color override.
625  bool has_color_override = false;
626  bool has_color_off = false;
627  LColor color_override;
628  const ColorAttrib *ca = DCAST(ColorAttrib, net_state->get_attrib(ColorAttrib::get_class_type()));
629  if (ca != (const ColorAttrib *)NULL) {
630  if (ca->get_color_type() == ColorAttrib::T_flat) {
631  has_color_override = true;
632  color_override = ca->get_color();
633  color_override.set(color_override[0] * color_scale[0],
634  color_override[1] * color_scale[1],
635  color_override[2] * color_scale[2],
636  color_override[3] * color_scale[3]);
637 
638  } else if (ca->get_color_type() == ColorAttrib::T_off) {
639  has_color_off = true;
640  }
641  }
642 
643  // Check for a material.
644  EggMaterial *egg_mat = (EggMaterial *)NULL;
645  const MaterialAttrib *ma = DCAST(MaterialAttrib, net_state->get_attrib(MaterialAttrib::get_class_type()));
646  if (ma != (const MaterialAttrib *)NULL) {
647  egg_mat = get_egg_material(ma->get_material());
648  }
649 
650  // Check for a texture.
651  EggTexture *egg_tex = (EggTexture *)NULL;
652  const TextureAttrib *ta = DCAST(TextureAttrib, net_state->get_attrib(TextureAttrib::get_class_type()));
653  if (ta != (const TextureAttrib *)NULL) {
654  egg_tex = get_egg_texture(ta->get_texture());
655  }
656 
657  // Check the texture environment
658  if ((ta != (const TextureAttrib *)NULL) && (egg_tex != (const EggTexture *)NULL)) {
659  TextureStage* tex_stage = ta->get_on_stage(0);
660  if (tex_stage != (const TextureStage *)NULL) {
661  switch (tex_stage->get_mode()) {
662  case TextureStage::M_modulate:
663  if (has_color_off == true) {
664  egg_tex->set_env_type(EggTexture::ET_replace);
665  } else {
666  egg_tex->set_env_type(EggTexture::ET_modulate);
667  }
668  break;
669  case TextureStage::M_decal:
670  egg_tex->set_env_type(EggTexture::ET_decal);
671  break;
672  case TextureStage::M_blend:
673  egg_tex->set_env_type(EggTexture::ET_blend);
674  break;
675  case TextureStage::M_replace:
676  egg_tex->set_env_type(EggTexture::ET_replace);
677  break;
678  case TextureStage::M_add:
679  egg_tex->set_env_type(EggTexture::ET_add);
680  break;
681  case TextureStage::M_blend_color_scale:
682  egg_tex->set_env_type(EggTexture::ET_blend_color_scale);
683  break;
684  default:
685  break;
686  }
687  }
688  }
689 
690  // Check the backface flag.
691  bool bface = false;
692  const RenderAttrib *cf_attrib = net_state->get_attrib(CullFaceAttrib::get_class_type());
693  if (cf_attrib != (const RenderAttrib *)NULL) {
694  const CullFaceAttrib *cfa = DCAST(CullFaceAttrib, cf_attrib);
695  if (cfa->get_effective_mode() == CullFaceAttrib::M_cull_none) {
696  bface = true;
697  }
698  }
699 
700  // Check the depth write flag - only needed for AM_blend_no_occlude
701  bool has_depthwrite = false;
702  DepthWriteAttrib::Mode depthwrite = DepthWriteAttrib::M_on;
703  const RenderAttrib *dw_attrib = net_state->get_attrib(DepthWriteAttrib::get_class_type());
704  if (dw_attrib != (const RenderAttrib *)NULL) {
705  const DepthWriteAttrib *dwa = DCAST(DepthWriteAttrib, dw_attrib);
706  depthwrite = dwa->get_mode();
707  has_depthwrite = true;
708  }
709 
710  // Check the transparency flag.
711  bool has_transparency = false;
712  TransparencyAttrib::Mode transparency = TransparencyAttrib::M_none;
713  const RenderAttrib *tr_attrib = net_state->get_attrib(TransparencyAttrib::get_class_type());
714  if (tr_attrib != (const RenderAttrib *)NULL) {
715  const TransparencyAttrib *tra = DCAST(TransparencyAttrib, tr_attrib);
716  transparency = tra->get_mode();
717  has_transparency = true;
718  }
719  if (has_transparency && (egg_tex != (EggTexture *)NULL)) {
720  EggRenderMode::AlphaMode tex_trans = EggRenderMode::AM_unspecified;
721  switch (transparency) {
722  case TransparencyAttrib::M_none:
723  tex_trans = EggRenderMode::AM_off;
724  break;
725  case TransparencyAttrib::M_alpha:
726  if (has_depthwrite && (depthwrite == DepthWriteAttrib::M_off)) {
727  tex_trans = EggRenderMode::AM_blend_no_occlude;
728  has_depthwrite = false;
729  } else {
730  tex_trans = EggRenderMode::AM_blend;
731  }
732  break;
733  case TransparencyAttrib::M_multisample:
734  tex_trans = EggRenderMode::AM_ms;
735  break;
736  case TransparencyAttrib::M_multisample_mask:
737  tex_trans = EggRenderMode::AM_ms_mask;
738  break;
739  case TransparencyAttrib::M_binary:
740  tex_trans = EggRenderMode::AM_binary;
741  break;
742  case TransparencyAttrib::M_dual:
743  tex_trans = EggRenderMode::AM_dual;
744  break;
745  default: // intentional fall-through
746  case TransparencyAttrib::M_notused:
747  break;
748  }
749  if (tex_trans != EggRenderMode::AM_unspecified) {
750  egg_tex->set_alpha_mode(tex_trans);
751  }
752  }
753 
754 
755  LNormal normal;
756  LColor color;
757  CPT(TransformBlendTable) transformBlendTable = vertex_data->get_transform_blend_table();
758 
759  int num_primitives = primitive->get_num_primitives();
760  int num_vertices = primitive->get_num_vertices_per_primitive();
761 
762  EggPrimitive *(*make_func)(void);
763 
764  if (primitive->is_of_type(GeomTriangles::get_class_type())) {
765  make_func = make_egg_polygon;
766  } else if (primitive->is_of_type(GeomPatches::get_class_type())) {
767  make_func = make_egg_patch;
768  } else if (primitive->is_of_type(GeomPoints::get_class_type())) {
769  make_func = make_egg_point;
770  } else if (primitive->is_of_type(GeomLines::get_class_type())) {
771  make_func = make_egg_line;
772  } else {
773  // Huh, an unknown geometry type.
774  return;
775  }
776 
777  for (int i = 0; i < num_primitives; ++i) {
778  PT(EggPrimitive) egg_prim = (*make_func)();
779 
780  egg_parent->add_child(egg_prim);
781 
782  if (egg_mat != (EggMaterial *)NULL) {
783  egg_prim->set_material(egg_mat);
784  }
785  if (egg_tex != (EggTexture *)NULL) {
786  egg_prim->set_texture(egg_tex);
787  }
788 
789  if (bface) {
790  egg_prim->set_bface_flag(true);
791  }
792 
793  for (int j = 0; j < num_vertices; j++) {
794  EggVertex egg_vert;
795 
796  // Get per-vertex properties.
797  reader.set_row(primitive->get_vertex(i * num_vertices + j));
798 
799  reader.set_column(InternalName::get_vertex());
800  LVertex vertex = reader.get_data3();
801  egg_vert.set_pos(LCAST(double, vertex * net_mat));
802 
803  if (vertex_data->has_column(InternalName::get_normal())) {
804  reader.set_column(InternalName::get_normal());
805  LNormal normal = reader.get_data3();
806  egg_vert.set_normal(LCAST(double, normal * net_mat));
807  }
808  if (has_color_override) {
809  egg_vert.set_color(color_override);
810 
811  } else if (!has_color_off) {
812  LColor color(1.0f, 1.0f, 1.0f, 1.0f);
813  if (vertex_data->has_column(InternalName::get_color())) {
814  reader.set_column(InternalName::get_color());
815  color = reader.get_data4();
816  }
817  egg_vert.set_color(LColor(color[0] * color_scale[0],
818  color[1] * color_scale[1],
819  color[2] * color_scale[2],
820  color[3] * color_scale[3]));
821  }
822 
823  if (vertex_data->has_column(InternalName::get_texcoord())) {
824  reader.set_column(InternalName::get_texcoord());
825  LTexCoord uv = reader.get_data2();
826  egg_vert.set_uv(LCAST(double, uv));
827  }
828 
829  EggVertex *new_egg_vert = _vpool->create_unique_vertex(egg_vert);
830 
831  if ((vertex_data->has_column(InternalName::get_transform_blend())) &&
832  (jointMap!=NULL) && (transformBlendTable!=NULL)) {
833  reader.set_column(InternalName::get_transform_blend());
834  int idx = reader.get_data1i();
835  const TransformBlend &blend = transformBlendTable->get_blend(idx);
836  int num_weights = blend.get_num_transforms();
837  for (int k = 0; k < num_weights; ++k) {
838  PN_stdfloat weight = blend.get_weight(k);
839  if (weight!=0) {
840  const VertexTransform *vertex_transform = blend.get_transform(k);
841  if (vertex_transform->is_of_type(JointVertexTransform::get_class_type())) {
842  const JointVertexTransform *joint_vertex_transform = DCAST(const JointVertexTransform, vertex_transform);
843 
844  CharacterJointMap::iterator mi = jointMap->find(joint_vertex_transform->get_joint());
845  if (mi == jointMap->end()) {
846  mi = jointMap->insert(CharacterJointMap::value_type(joint_vertex_transform->get_joint(), pvector<pair<EggVertex*,PN_stdfloat> >())).first;
847  }
848  pvector<pair<EggVertex*,PN_stdfloat> > &joint_vertices = (*mi).second;
849  joint_vertices.push_back(pair<EggVertex*,PN_stdfloat>(new_egg_vert, weight));
850  }
851  }
852  }
853  }
854 
855  egg_prim->add_vertex(new_egg_vert);
856  }
857  }
858 }
859 
860 ////////////////////////////////////////////////////////////////////
861 // Function: EggSaver::recurse_nodes
862 // Access: Private
863 // Description: Converts all the children of the indicated node.
864 ////////////////////////////////////////////////////////////////////
865 void EggSaver::
866 recurse_nodes(const WorkingNodePath &node_path, EggGroupNode *egg_parent,
867  bool has_decal) {
868  PandaNode *node = node_path.node();
869  int num_children = node->get_num_children();
870 
871  for (int i = 0; i < num_children; i++) {
872  PandaNode *child = node->get_child(i);
873  convert_node(WorkingNodePath(node_path, child), egg_parent, has_decal);
874  }
875 }
876 
877 ////////////////////////////////////////////////////////////////////
878 // Function: EggSaver::apply_node_properties
879 // Access: Private
880 // Description: Applies any special properties that might be stored
881 // on the node, like billboarding. Returns true if any
882 // were applied, false otherwise.
883 ////////////////////////////////////////////////////////////////////
884 bool EggSaver::
885 apply_node_properties(EggGroup *egg_group, PandaNode *node, bool allow_backstage) {
886  bool any_applied = false;
887 
888  if (node->is_overall_hidden() && allow_backstage) {
889  // This node is hidden. We'll go ahead and convert it, but we'll
890  // put in the "backstage" flag to mean it's not real geometry.
891  // unless the caller wants to keep it (by setting allow_backstage to false)
892  egg_group->add_object_type("backstage");
893  }
894 
895  if (node->has_tags()) {
896  if (apply_tags(egg_group, node)) {
897  any_applied = true;
898  }
899  }
900 
901  if (node->is_of_type(ModelNode::get_class_type())) {
902  ModelNode *model_node = DCAST(ModelNode, node);
903  switch (model_node->get_preserve_transform()) {
904  case ModelNode::PT_none:
905  case ModelNode::PT_drop_node:
906  break;
907 
908  case ModelNode::PT_net:
909  egg_group->set_dcs_type(EggGroup::DC_net);
910  break;
911 
912  case ModelNode::PT_local:
913  egg_group->set_dcs_type(EggGroup::DC_local);
914  break;
915 
916  case ModelNode::PT_no_touch:
917  egg_group->set_dcs_type(EggGroup::DC_no_touch);
918  break;
919  }
920  }
921 
922  const RenderEffects *effects = node->get_effects();
923  const RenderEffect *effect = effects->get_effect(BillboardEffect::get_class_type());
924  if (effect != (RenderEffect *)NULL) {
925  const BillboardEffect *bbe = DCAST(BillboardEffect, effect);
926  if (bbe->get_axial_rotate()) {
927  egg_group->set_billboard_type(EggGroup::BT_axis);
928  any_applied = true;
929 
930  } else if (bbe->get_eye_relative()) {
931  egg_group->set_billboard_type(EggGroup::BT_point_camera_relative);
932  any_applied = true;
933 
934  } else {
935  egg_group->set_billboard_type(EggGroup::BT_point_world_relative);
936  any_applied = true;
937  }
938  }
939 
940  const TransformState *transform = node->get_transform();
941  if (!transform->is_identity()) {
942  if (transform->has_components()) {
943  // If the transform can be represented componentwise, we prefer
944  // storing it that way in the egg file.
945  const LVecBase3 &scale = transform->get_scale();
946  const LQuaternion &quat = transform->get_quat();
947  const LVecBase3 &pos = transform->get_pos();
948  if (!scale.almost_equal(LVecBase3(1.0f, 1.0f, 1.0f))) {
949  egg_group->add_scale3d(LCAST(double, scale));
950  }
951  if (!quat.is_identity()) {
952  egg_group->add_rotate3d(LCAST(double, quat));
953  }
954  if (!pos.almost_equal(LVecBase3::zero())) {
955  egg_group->add_translate3d(LCAST(double, pos));
956  }
957 
958  } else if (transform->has_mat()) {
959  // Otherwise, we store the raw matrix.
960  const LMatrix4 &mat = transform->get_mat();
961  egg_group->set_transform3d(LCAST(double, mat));
962  }
963  any_applied = true;
964  }
965 
966  return any_applied;
967 }
968 
969 ////////////////////////////////////////////////////////////////////
970 // Function: EggSaver::apply_tags
971 // Access: Private
972 // Description: Applies string tags to the egg file. Returns true if
973 // any were applied, false otherwise.
974 ////////////////////////////////////////////////////////////////////
975 bool EggSaver::
976 apply_tags(EggGroup *egg_group, PandaNode *node) {
977  ostringstream strm;
978  char delimiter = '\n';
979  string delimiter_str(1, delimiter);
980  node->list_tags(strm, delimiter_str);
981 
982  string data = strm.str();
983  if (data.empty()) {
984  return false;
985  }
986 
987  bool any_applied = false;
988 
989  size_t p = 0;
990  size_t q = data.find(delimiter);
991  while (q != string::npos) {
992  string tag = data.substr(p, q);
993  if (apply_tag(egg_group, node, tag)) {
994  any_applied = true;
995  }
996  p = q + 1;
997  q = data.find(delimiter, p);
998  }
999 
1000  string tag = data.substr(p);
1001  if (apply_tag(egg_group, node, tag)) {
1002  any_applied = true;
1003  }
1004 
1005  return any_applied;
1006 }
1007 
1008 ////////////////////////////////////////////////////////////////////
1009 // Function: EggSaver::apply_tag
1010 // Access: Private
1011 // Description: Applies the named string tags to the egg file.
1012 ////////////////////////////////////////////////////////////////////
1013 bool EggSaver::
1014 apply_tag(EggGroup *egg_group, PandaNode *node, const string &tag) {
1015  if (!node->has_tag(tag)) {
1016  return false;
1017  }
1018 
1019  string value = node->get_tag(tag);
1020  egg_group->set_tag(tag, value);
1021  return true;
1022 }
1023 
1024 ////////////////////////////////////////////////////////////////////
1025 // Function: EggSaver::get_egg_material
1026 // Access: Private
1027 // Description: Returns an EggMaterial pointer that corresponds to
1028 // the indicated Material.
1029 ////////////////////////////////////////////////////////////////////
1030 EggMaterial *EggSaver::
1031 get_egg_material(Material *mat) {
1032  if (mat != (Material *)NULL) {
1033  EggMaterial temp(mat->get_name());
1034  if (mat->has_ambient()) {
1035  temp.set_amb(mat->get_ambient());
1036  }
1037 
1038  if (mat->has_diffuse()) {
1039  temp.set_diff(mat->get_diffuse());
1040  }
1041 
1042  if (mat->has_specular()) {
1043  temp.set_spec(mat->get_specular());
1044  }
1045 
1046  if (mat->has_emission()) {
1047  temp.set_emit(mat->get_emission());
1048  }
1049 
1050  temp.set_shininess(mat->get_shininess());
1051  temp.set_local(mat->get_local());
1052 
1053  return _materials.create_unique_material(temp, ~EggMaterial::E_mref_name);
1054  }
1055 
1056  return NULL;
1057 }
1058 
1059 ////////////////////////////////////////////////////////////////////
1060 // Function: EggSaver::get_egg_texture
1061 // Access: Private
1062 // Description: Returns an EggTexture pointer that corresponds to the
1063 // indicated Texture.
1064 ////////////////////////////////////////////////////////////////////
1065 EggTexture *EggSaver::
1066 get_egg_texture(Texture *tex) {
1067  if (tex != (Texture *)NULL) {
1068  if (tex->has_filename()) {
1069  Filename filename = tex->get_filename();
1070  EggTexture temp(filename.get_basename_wo_extension(), filename);
1071  if (tex->has_alpha_filename()) {
1072  Filename alpha = tex->get_alpha_filename();
1073  temp.set_alpha_filename(alpha);
1074  }
1075 
1076  switch (tex->get_minfilter()) {
1077  case SamplerState::FT_nearest:
1078  temp.set_minfilter(EggTexture::FT_nearest);
1079  break;
1080  case SamplerState::FT_linear:
1081  temp.set_minfilter(EggTexture::FT_linear);
1082  break;
1083  case SamplerState::FT_nearest_mipmap_nearest:
1084  temp.set_minfilter(EggTexture::FT_nearest_mipmap_nearest);
1085  break;
1086  case SamplerState::FT_linear_mipmap_nearest:
1087  temp.set_minfilter(EggTexture::FT_linear_mipmap_nearest);
1088  break;
1089  case SamplerState::FT_nearest_mipmap_linear:
1090  temp.set_minfilter(EggTexture::FT_nearest_mipmap_linear);
1091  break;
1092  case SamplerState::FT_linear_mipmap_linear:
1093  temp.set_minfilter(EggTexture::FT_linear_mipmap_linear);
1094  break;
1095 
1096  default:
1097  break;
1098  }
1099 
1100  switch (tex->get_magfilter()) {
1101  case SamplerState::FT_nearest:
1102  temp.set_magfilter(EggTexture::FT_nearest);
1103  break;
1104  case SamplerState::FT_linear:
1105  temp.set_magfilter(EggTexture::FT_linear);
1106  break;
1107 
1108  default:
1109  break;
1110  }
1111 
1112  switch (tex->get_wrap_u()) {
1113  case SamplerState::WM_clamp:
1114  temp.set_wrap_u(EggTexture::WM_clamp);
1115  break;
1116  case SamplerState::WM_repeat:
1117  temp.set_wrap_u(EggTexture::WM_repeat);
1118  break;
1119 
1120  default:
1121  // There are some new wrap options on Texture that aren't yet
1122  // supported in egg.
1123  break;
1124  }
1125 
1126  switch (tex->get_wrap_v()) {
1127  case SamplerState::WM_clamp:
1128  temp.set_wrap_v(EggTexture::WM_clamp);
1129  break;
1130  case SamplerState::WM_repeat:
1131  temp.set_wrap_v(EggTexture::WM_repeat);
1132  break;
1133 
1134  default:
1135  // There are some new wrap options on Texture that aren't yet
1136  // supported in egg.
1137  break;
1138  }
1139 
1140  switch (tex->get_format()) {
1141  case Texture::F_red:
1142  temp.set_format(EggTexture::F_red);
1143  break;
1144  case Texture::F_green:
1145  temp.set_format(EggTexture::F_green);
1146  break;
1147  case Texture::F_blue:
1148  temp.set_format(EggTexture::F_blue);
1149  break;
1150  case Texture::F_alpha:
1151  temp.set_format(EggTexture::F_alpha);
1152  break;
1153  case Texture::F_rgb:
1154  temp.set_format(EggTexture::F_rgb);
1155  break;
1156  case Texture::F_rgb5:
1157  temp.set_format(EggTexture::F_rgb5);
1158  break;
1159  case Texture::F_rgb8:
1160  temp.set_format(EggTexture::F_rgb8);
1161  break;
1162  case Texture::F_rgb12:
1163  temp.set_format(EggTexture::F_rgb12);
1164  break;
1165  case Texture::F_rgb332:
1166  temp.set_format(EggTexture::F_rgb332);
1167  break;
1168  case Texture::F_rgba:
1169  temp.set_format(EggTexture::F_rgba);
1170  break;
1171  case Texture::F_rgbm:
1172  temp.set_format(EggTexture::F_rgbm);
1173  break;
1174  case Texture::F_rgba4:
1175  temp.set_format(EggTexture::F_rgba4);
1176  break;
1177  case Texture::F_rgba5:
1178  temp.set_format(EggTexture::F_rgba5);
1179  break;
1180  case Texture::F_rgba8:
1181  temp.set_format(EggTexture::F_rgba8);
1182  break;
1183  case Texture::F_rgba12:
1184  temp.set_format(EggTexture::F_rgba12);
1185  break;
1186  case Texture::F_luminance:
1187  temp.set_format(EggTexture::F_luminance);
1188  break;
1189  case Texture::F_luminance_alpha:
1190  temp.set_format(EggTexture::F_luminance_alpha);
1191  break;
1192  case Texture::F_luminance_alphamask:
1193  temp.set_format(EggTexture::F_luminance_alphamask);
1194  break;
1195  default:
1196  break;
1197  }
1198 
1199  return _textures.create_unique_texture(temp, ~EggTexture::E_tref_name);
1200  }
1201  }
1202 
1203  return NULL;
1204 }
1205 
1206 ////////////////////////////////////////////////////////////////////
1207 // Function: EggSaver::make_egg_polygon
1208 // Access: Private, Static
1209 // Description: A factory function to make a new EggPolygon instance.
1210 ////////////////////////////////////////////////////////////////////
1211 EggPrimitive *EggSaver::
1212 make_egg_polygon() {
1213  return new EggPolygon;
1214 }
1215 
1216 ////////////////////////////////////////////////////////////////////
1217 // Function: EggSaver::make_egg_patch
1218 // Access: Private, Static
1219 // Description: A factory function to make a new EggPatch instance.
1220 ////////////////////////////////////////////////////////////////////
1221 EggPrimitive *EggSaver::
1222 make_egg_patch() {
1223  return new EggPatch;
1224 }
1225 
1226 ////////////////////////////////////////////////////////////////////
1227 // Function: EggSaver::make_egg_point
1228 // Access: Private, Static
1229 // Description: A factory function to make a new EggPoint instance.
1230 ////////////////////////////////////////////////////////////////////
1231 EggPrimitive *EggSaver::
1232 make_egg_point() {
1233  return new EggPoint;
1234 }
1235 
1236 ////////////////////////////////////////////////////////////////////
1237 // Function: EggSaver::make_egg_line
1238 // Access: Private, Static
1239 // Description: A factory function to make a new EggLine instance.
1240 ////////////////////////////////////////////////////////////////////
1241 EggPrimitive *EggSaver::
1242 make_egg_line() {
1243  return new EggLine;
1244 }
A base class for any of a number of kinds of geometry primitives: polygons, point lights...
Definition: eggPrimitive.h:51
Format get_format() const
Returns the format of the texture, which represents both the semantic meaning of the texels and...
Definition: texture.I:872
PreserveTransform get_preserve_transform() const
Returns the current setting of the preserve_transform flag.
Definition: modelNode.I:76
A basic node of the scene graph or data graph.
Definition: pandaNode.h:72
This is the base class for all three-component vectors and points.
Definition: lvecBase3.h:105
Mode get_mode() const
Return the mode of this stage.
Definition: textureStage.I:206
void add_rotate3d(double angle, const LVector3d &axis)
Appends a 3-d rotation about an arbitrary axis to the current transform.
const LColor & get_ambient() const
Returns the ambient color setting, if it has been set.
Definition: material.I:82
void list_tags(ostream &out, const string &separator="\n") const
Writes a list of all the tag keys assigned to the node to the indicated stream.
Definition: pandaNode.cxx:1505
EggTexture * create_unique_texture(const EggTexture &copy, int eq)
Creates a new texture if there is not already one equivalent (according to eq, see EggTexture::is_equ...
bool is_identity() const
Returns true if this quaternion represents the identity transformation: no rotation.
Definition: lquaternion.h:829
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:4716
A line segment, or a series of connected line segments, defined by a &lt;Line&gt; entry.
Definition: eggLine.h:27
This is the base class for a number of render attributes (other than transform) that may be set on sc...
Definition: renderAttrib.h:60
bool has_ambient() const
Returns true if the ambient color has been explicitly set for this material, false otherwise...
Definition: material.I:70
bool has_specular() const
Returns true if the specular color has been explicitly set for this material, false otherwise...
Definition: material.I:144
An animated character, with skeleton-morph animation and either soft-skinned or hard-skinned vertices...
Definition: character.h:41
Indicates which, if any, material should be applied to geometry.
void set_pos(double pos)
Sets the vertex position.
Definition: eggVertex.I:54
Enables or disables writing to the depth buffer.
SamplerState::WrapMode get_wrap_v() const
Returns the wrap mode of the texture in the V direction.
Definition: texture.I:1103
void add_component_data(const string &component_name, double value)
Adds a new row to the named component (one of matrix_component_letters) of the table.
bool has_table(char table_id) const
Returns true if the indicated subtable has been assigned.
This is the root of an AnimChannel hierarchy.
Definition: animBundle.h:31
A base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:51
The abstract base class for all things that can collide with other things in the world, and all the things they can collide with (except geometry).
void get_transform(LMatrix4 &transform) const
Copies the joint&#39;s current transform into the indicated matrix.
This controls the enabling of transparency.
const CharacterJoint * get_joint() const
Returns the joint for which this object returns the transform.
Defines a texture map that may be applied to geometry.
Definition: eggTexture.h:33
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:75
void get_blend(LMatrix4 &result, Thread *current_thread) const
Returns the current value of the blend, based on the current value of all of the nested transform obj...
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:63
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
Definition: geomPrimitive.h:63
Material * get_material() const
If the MaterialAttrib is not an &#39;off&#39; MaterialAttrib, returns the material that is associated...
A node that automatically cycles through rendering each one of its children according to its frame ra...
Definition: sequenceNode.h:29
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
Definition: lvector3.h:100
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
Definition: lpoint3.h:99
Type get_color_type() const
Returns the type of color specified by this ColorAttrib.
Definition: colorAttrib.I:46
This is the base class for a number of special render effects that may be set on scene graph nodes to...
Definition: renderEffect.h:56
A spherical collision volume or object.
PN_stdfloat get_shininess() const
Returns the shininess exponent of the material.
Definition: material.I:217
This is the primary interface into all the egg data, and the root of the egg file structure...
Definition: eggData.h:41
Indicates that geometry at this node should automatically rotate to face the camera, or any other arbitrary node.
static const LVecBase3f & zero()
Returns a zero-length vector.
Definition: lvecBase3.h:381
This is a class designed to support low-overhead traversals of the complete scene graph...
bool has_alpha_filename() const
Returns true if the alpha_filename has been set and is available.
Definition: texture.I:561
TextureStage * get_on_stage(int n) const
Returns the nth stage turned on by the attribute, sorted in render order.
Converts the scene graph beginning at the indicated node into an EggData structure, for writing to an egg file.
Definition: eggSaver.h:56
bool has_emission() const
Returns true if the emission color has been explicitly set for this material, false otherwise...
Definition: material.I:181
A single point, or a collection of points as defined by a single &lt;PointLight&gt; entry.
Definition: eggPoint.h:27
const LColor & get_emission() const
Returns the emission color setting, if it has been set.
Definition: material.I:193
Indicates the set of TextureStages and their associated Textures that should be applied to (or remove...
Definition: textureAttrib.h:34
Indicates which faces should be culled based on their vertex ordering.
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:39
PandaNode * node() const
Returns the node traversed to so far.
Mode get_mode() const
Returns the depth write mode.
bool has_tags() const
Returns true if the node has any tags (or any Python tags) at all, false if it has none...
Definition: pandaNode.I:469
The main glue of the egg hierarchy, this corresponds to the &lt;Group&gt;, &lt;Instance&gt;, and &lt;Joint&gt; type nod...
Definition: eggGroup.h:36
int get_num_switches() const
Returns the number of switch ranges added to the LODNode.
Definition: lodNode.I:117
Mode get_effective_mode() const
Returns the effective culling mode.
void set_transform3d(const LMatrix4d &mat)
Sets the overall transform as a 4x4 matrix.
Definition: eggTransform.I:222
bool has_tag(const string &key, Thread *current_thread=Thread::get_current_thread()) const
Returns true if a value has been defined on this node for the particular key (even if that value is t...
Definition: pandaNode.I:455
const RenderEffect * get_effect(int n) const
Returns the nth effect in the state.
This is the base class for AnimChannel and AnimBundle.
Definition: animGroup.h:36
This node is placed at key points within the scene graph to indicate the roots of &quot;models&quot;: subtrees ...
Definition: modelNode.h:34
string get_tag(const string &key, Thread *current_thread=Thread::get_current_thread()) const
Retrieves the user-defined value that was previously set on this node for the particular key...
Definition: pandaNode.I:437
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
This is an abstract base class that holds a pointer to some transform, computed in some arbitrary way...
NodePath get_node_path() const
Constructs and returns an actual NodePath that represents the same path we have just traversed...
const LColor & get_color() const
If the type is T_flat or T_off, this returns the color that will be applied to geometry.
Definition: colorAttrib.I:58
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:451
A single &quot;patch&quot;, a special primitive to be rendered only with a tessellation shader.
Definition: eggPatch.h:27
const VertexTransform * get_transform(int n) const
Returns the nth transform stored in the blend object.
A Level-of-Detail node.
Definition: lodNode.h:31
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal...
Definition: eggVertex.h:41
int get_num_children(Thread *current_thread=Thread::get_current_thread()) const
Returns the number of child nodes this node has.
Definition: pandaNode.I:68
This corresponds to an &lt;Xfm$Anim_S$&gt; entry, which is a collection of up to nine &lt;S$Anim&gt; entries that...
Definition: eggXfmSAnim.h:33
void set_vertex_membership(EggVertex *vert, double membership)
Explicitly sets the net membership of the indicated vertex in this group to the given value...
Definition: eggGroup.cxx:773
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
const LVecBase4 & get_scale() const
Returns the scale to be applied to colors.
A container for geometry primitives.
Definition: geom.h:58
void set_alpha_mode(AlphaMode mode)
Specifies precisely how the transparency for this geometry should be achieved, or if it should be use...
const LColor & get_specular() const
Returns the specular color setting, if it has been set.
Definition: material.I:156
bool get_eye_relative() const
Returns true if this billboard interprets the up vector relative to the camera, or false if it is rel...
CPTA_stdfloat get_table(char table_id) const
Returns a pointer to the indicated subtable&#39;s data, if it exists, or NULL if it does not...
int get_num_transforms() const
Returns the number of transforms stored in the blend object.
bool get_axial_rotate() const
Returns true if this billboard rotates only around the axis of the up vector, or false if it rotates ...
A single polygon.
Definition: eggPolygon.h:26
Defines the way an object appears in the presence of lighting.
Definition: material.h:34
void add_translate3d(const LVector3d &translate)
Appends a 3-d translation operation to the current transform.
Applies a scale to colors in the scene graph and on vertices.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:53
SamplerState::FilterType get_magfilter() const
Returns the filter mode of the texture for magnification.
Definition: texture.I:1157
This defines a single entry in a TransformBlendTable.
void set_tag(const string &key, const string &value)
Associates a user-defined value with a user-defined key which is stored on the node.
Definition: eggGroup.I:883
This corresponds to a.
Definition: eggTable.h:31
This is a specialization on VertexTransform that returns the transform necessary to move vertices as ...
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
string get_basename_wo_extension() const
Returns the basename part of the filename, without the file extension.
Definition: filename.I:460
bool has_diffuse() const
Returns true if the diffuse color has been explicitly set for this material, false otherwise...
Definition: material.I:107
Mode get_mode() const
Returns the transparency mode.
PandaNode * get_child(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the nth child node of this node.
Definition: pandaNode.I:82
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
PartGroup * get_child(int n) const
Returns the nth child of the group.
Definition: partGroup.cxx:122
double get_base_frame_rate() const
Returns the ideal number of frames per second of the animation, when it is running at normal speed...
Definition: animBundle.I:47
This is the base quaternion class.
Definition: lquaternion.h:96
This is the root of a MovingPart hierarchy.
Definition: partBundle.h:49
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
bool almost_equal(const LVecBase3f &other, float threshold) const
Returns true if two vectors are memberwise equal within a specified tolerance.
Definition: lvecBase3.h:1264
bool has_filename() const
Returns true if the filename has been set and is available.
Definition: texture.I:536
A base class for things that may be directly added into the egg hierarchy.
Definition: eggNode.h:38
This represents one joint of the character&#39;s animation, containing an animating transform matrix...
A node in the scene graph that can hold any number of CollisionSolids.
Definition: collisionNode.h:33
PN_stdfloat get_weight(const VertexTransform *transform) const
Returns the weight associated with the indicated transform, or 0 if there is no entry for the transfo...
void add_scale3d(const LVecBase3d &scale)
Appends a possibly non-uniform scale to the current transform.
Defines a series of disconnected triangles.
Definition: geomTriangles.h:25
EggMaterial * create_unique_material(const EggMaterial &copy, int eq)
Creates a new material if there is not already one equivalent (according to eq, see EggMaterial::is_e...
This structure collects together the different combinations of transforms and blend amounts used by a...
An animation channel that issues a matrix each frame, read from a table such as might have been read ...
Indicates what color should be applied to renderable geometry.
Definition: colorAttrib.h:30
int get_num_children() const
Returns the number of child nodes of the group.
Definition: partGroup.cxx:111
SamplerState::WrapMode get_wrap_u() const
Returns the wrap mode of the texture in the U direction.
Definition: texture.I:1087
This is a two-component point in space.
Definition: lpoint2.h:92
bool get_local() const
Returns the local viewer flag.
Definition: material.I:242
SamplerState::FilterType get_minfilter() const
Returns the filter mode of the texture for minification.
Definition: texture.I:1139
virtual bool is_geom_node() const
A simple downcast check.
Definition: pandaNode.cxx:2486
This is a node that contains a pointer to an AnimBundle.
AnimGroup * get_child(int n) const
Returns the nth child of the group.
Definition: animGroup.cxx:115
Defines the properties of a named stage of the multitexture pipeline.
Definition: textureStage.h:38
void add_matrix4(const LMatrix4d &mat)
Appends an arbitrary 4x4 matrix to the current transform.
Definition: eggTransform.I:149
const LColor & get_diffuse() const
Returns the diffuse color setting, if it has been set.
Definition: material.I:119
void set_uv(const LTexCoordd &texCoord)
Replaces the unnamed UV coordinate pair on the vertex with the indicated value.
Definition: eggVertex.I:239
EggVertex * create_unique_vertex(const EggVertex &copy)
Creates a new vertex in the pool that is a copy of the indicated one and returns it.
void add_node(PandaNode *node)
Adds the scene graph rooted at the indicated node to the accumulated egg data within this object...
Definition: eggSaver.cxx:96
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:165
A collection of vertices.
Definition: eggVertexPool.h:46
EggVertex * add_vertex(EggVertex *vertex)
Adds the indicated vertex to the end of the primitive&#39;s list of vertices, and returns it...
This represents a unique collection of RenderEffect objects that correspond to a particular renderabl...
Definition: renderEffects.h:46
A SwitchCondition that switches the levels-of-detail based on distance from the camera&#39;s eyepoint...
A node that holds Geom objects, renderable pieces of geometry.
Definition: geomNode.h:37
const Filename & get_alpha_filename() const
Returns the alpha_filename that has been set.
Definition: texture.I:575
A node that renders only one of its children, according to the user&#39;s indication. ...
Definition: switchNode.h:27
Texture * get_texture() const
If the TextureAttrib is not an &#39;off&#39; TextureAttrib, returns the base-level texture that is associated...
Definition: textureAttrib.I:76
Similar to PointerToArray, except that its contents may not be modified.
const Filename & get_filename() const
Returns the filename that has been set.
Definition: texture.I:549
bool is_overall_hidden() const
Returns true if the node has been hidden to all cameras by clearing its overall bit.
Definition: pandaNode.I:524
This is the base class for PartRoot and MovingPart.
Definition: partGroup.h:45