Panda3D
softNodeDesc.cxx
1 // Filename: softNodeDesc.cxx
2 // Created by: masad (03Oct03)
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 "softNodeDesc.h"
16 #include "config_softegg.h"
17 #include "eggGroup.h"
18 #include "eggXfmSAnim.h"
19 #include "eggSAnimData.h"
20 #include "softToEggConverter.h"
21 #include "dcast.h"
22 
23 TypeHandle SoftNodeDesc::_type_handle;
24 
25 ////////////////////////////////////////////////////////////////////
26 // Function: SoftNodeDesc::Constructor
27 // Access: Public
28 // Description:
29 ////////////////////////////////////////////////////////////////////
30 SoftNodeDesc::
31 SoftNodeDesc(SoftNodeDesc *parent, const string &name) :
32  Namable(name),
33  _parent(parent)
34 {
35  _model = (SAA_Elem *)NULL;
36  _egg_group = (EggGroup *)NULL;
37  _egg_table = (EggTable *)NULL;
38  _anim = (EggXfmSAnim *)NULL;
39  _joint_type = JT_none;
40 
41  // Add ourselves to our parent.
42  if (_parent != (SoftNodeDesc *)NULL) {
43  softegg_cat.spam() << "parent name " << _parent->get_name();
44  _parent->_children.push_back(this);
45  }
46 
47  // set the _parentJoint to Null
48  _parentJoint = NULL;
49 
50  fullname = NULL;
51 
52  numTexLoc = 0;
53  numTexGlb = 0;
54 
55  uScale = NULL;
56  vScale = NULL;
57  uOffset = NULL;
58  vOffset = NULL;
59 
60  valid;
61  uv_swap;
62  // SAA_Boolean visible;
63  numTexTri = NULL;
64  textures = NULL;
65  materials = NULL;
66  triangles = NULL;
67  gtype = SAA_GEOM_ORIGINAL;
68 }
69 
70 ////////////////////////////////////////////////////////////////////
71 // Function: SoftNodeDesc::Destructor
72 // Access: Public
73 // Description:
74 ////////////////////////////////////////////////////////////////////
75 SoftNodeDesc::
76 ~SoftNodeDesc() {
77  // I think it is a mistake to try to delete this. This was one
78  // member of an entire array allocated at once; you can't delete
79  // individual elements of an array.
80 
81  // Screw cleanup, anyway--we'll just let the array leak.
82  /*
83  if (_model != (SAA_Elem *)NULL) {
84  delete _model;
85  }
86  */
87 }
88 
89 ////////////////////////////////////////////////////////////////////
90 // Function: SoftNodeDesc::set_model
91 // Access: Public
92 // Description: Indicates an associated between the SoftNodeDesc and
93 // some SAA_Elem instance.
94 ////////////////////////////////////////////////////////////////////
95 void SoftNodeDesc::
96 set_model(SAA_Elem *model) {
97  _model = model;
98 }
99 
100 ////////////////////////////////////////////////////////////////////
101 // Function: SoftNodeDesc::set_parent
102 // Access: Public
103 // Description: Sometimes, parent is not known at node creation
104 // As soon as it is known, set the parent
105 ////////////////////////////////////////////////////////////////////
106 void SoftNodeDesc::
108  if (_parent) {
109  softegg_cat.spam() << endl;
110  /*
111  softegg_cat.spam() << " expected _parent to be null!?\n";
112  if (_parent == parent)
113  softegg_cat.spam() << " parent already set\n";
114  else {
115  softegg_cat.spam() << " current parent " << _parent->get_name() << " new parent "
116  << parent << endl;
117  }
118  */
119  return;
120  }
121  _parent = parent;
122  softegg_cat.spam() << " set parent to " << _parent->get_name() << endl;
123 
124  // Add ourselves to our parent.
125  _parent->_children.push_back(this);
126 }
127 
128 ////////////////////////////////////////////////////////////////////
129 // Function: SoftNodeDesc::set_parent
130 // Access: Public
131 // Description: Sometimes, parent is not known at node creation
132 // As soon as it is known, set the parent
133 ////////////////////////////////////////////////////////////////////
134 void SoftNodeDesc::
136  if (_parent)
137  softegg_cat.spam() << " current parent " << _parent->get_name();
138 
139  _parent = parent;
140 
141  if (_parent)
142  softegg_cat.spam() << " new parent " << _parent->get_name() << endl;
143 
144  // Add ourselves to our parent.
145  _parent->_children.push_back(this);
146 }
147 
148 ////////////////////////////////////////////////////////////////////
149 // Function: SoftNodeDesc::has_model
150 // Access: Public
151 // Description: Returns true if a Soft dag path has been associated
152 // with this node, false otherwise.
153 ////////////////////////////////////////////////////////////////////
154 bool SoftNodeDesc::
155 has_model() const {
156  return (_model != (SAA_Elem *)NULL);
157 }
158 
159 ////////////////////////////////////////////////////////////////////
160 // Function: SoftNodeDesc::get_model
161 // Access: Public
162 // Description: Returns the SAA_Elem * associated with this node. It
163 // is an error to call this unless has_model()
164 // returned true.
165 ////////////////////////////////////////////////////////////////////
166 SAA_Elem *SoftNodeDesc::
167 get_model() const {
168  nassertr(_model != (SAA_Elem *)NULL, _model);
169  return _model;
170 }
171 
172 ////////////////////////////////////////////////////////////////////
173 // Function: SoftNodeDesc::is_joint
174 // Access: Private
175 // Description: Returns true if the node should be treated as a joint
176 // by the converter.
177 ////////////////////////////////////////////////////////////////////
178 bool SoftNodeDesc::
179 is_joint() const {
180  // return _joint_type == JT_joint || _joint_type == JT_pseudo_joint;
181  return _joint_type == JT_joint;
182 }
183 
184 ////////////////////////////////////////////////////////////////////
185 // Function: SoftNodeDesc::is_junk
186 // Access: Private
187 // Description: Returns true if the node should be treated as a junk
188 // by the converter.
189 ////////////////////////////////////////////////////////////////////
190 bool SoftNodeDesc::
191 is_junk() const {
192  return _joint_type == JT_junk;
193 }
194 
195 ////////////////////////////////////////////////////////////////////
196 // Function: SoftNodeDesc::set_joint
197 // Access: Private
198 // Description: sets the _joint_type to JT_joint
199 ////////////////////////////////////////////////////////////////////
200 void SoftNodeDesc::
202  _joint_type = JT_joint;
203 }
204 ////////////////////////////////////////////////////////////////////
205 // Function: SoftNodeDesc::is_joint_parent
206 // Access: Private
207 // Description: Returns true if the node is the parent or ancestor of
208 // a joint.
209 ////////////////////////////////////////////////////////////////////
210 bool SoftNodeDesc::
212  return _joint_type == JT_joint_parent;
213 }
214 
215 ////////////////////////////////////////////////////////////////////
216 // Function: SoftNodeDesc::clear_egg
217 // Access: Private
218 // Description: Recursively clears the egg pointers from this node
219 // and all children.
220 ////////////////////////////////////////////////////////////////////
221 void SoftNodeDesc::
222 clear_egg() {
223  _egg_group = (EggGroup *)NULL;
224  _egg_table = (EggTable *)NULL;
225  _anim = (EggXfmSAnim *)NULL;
226 
227  Children::const_iterator ci;
228  for (ci = _children.begin(); ci != _children.end(); ++ci) {
229  SoftNodeDesc *child = (*ci);
230  child->clear_egg();
231  }
232 }
233 
234 ////////////////////////////////////////////////////////////////////
235 // Function: SoftNodeDesc::mark_joint_parent
236 // Access: Private
237 // Description: Indicates that this node has at least one child that
238 // is a joint or a pseudo-joint.
239 ////////////////////////////////////////////////////////////////////
240 void SoftNodeDesc::
241 mark_joint_parent() {
242  if (_joint_type == JT_none) {
243  _joint_type = JT_joint_parent;
244  softegg_cat.spam() << " marked parent " << get_name();
245  }
246  else
247  softegg_cat.spam() << " ?parent " << get_name() << " joint type " << _joint_type;
248 
249  if (_parent != (SoftNodeDesc *)NULL) {
250  _parent->mark_joint_parent();
251  }
252  softegg_cat.spam() << endl;
253 }
254 
255 ////////////////////////////////////////////////////////////////////
256 // Function: SoftNodeDesc::check_joint_parent
257 // Access: Private
258 // Description: Walks the hierarchy, if a node is joint, make
259 // sure all its parents are marked JT_joint_parent
260 ////////////////////////////////////////////////////////////////////
261 void SoftNodeDesc::
262 check_joint_parent() {
263  Children::const_iterator ci;
264  for (ci = _children.begin(); ci != _children.end(); ++ci) {
265  SoftNodeDesc *child = (*ci);
266  if (child->is_joint()) {
267  softegg_cat.spam() << "child " << child->get_name();
268  mark_joint_parent();
269  }
270  child->check_joint_parent();
271  }
272 }
273 
274 ///////////////////////////////////////////////////////////////////////
275 // Function: SoftNodeTree::check_junk
276 // Access: Public
277 // Description: check to see if this is a branch we don't want to
278 // descend - this will prevent creating geometry for
279 // animation control structures
280 ///////////////////////////////////////////////////////////////////////
281 void SoftNodeDesc::
282 check_junk(bool parent_junk) {
283  const char *name = get_name().c_str();
284 
285  if (parent_junk) {
286  _joint_type = JT_junk;
287  softegg_cat.spam() << "junk node " << get_name() << endl;
288  }
289  if ( (strstr(name, "con-") != NULL) ||
290  (strstr(name, "con_") != NULL) ||
291  (strstr(name, "fly_") != NULL) ||
292  (strstr(name, "fly-") != NULL) ||
293  (strstr(name, "camRIG") != NULL) ||
294  (strstr(name, "cam_rig") != NULL) ||
295  (strstr(name, "bars") != NULL) )
296  {
297  _joint_type = JT_junk;
298  softegg_cat.spam() << "junk node " << get_name() << endl;
299  parent_junk = true;
300  Children::const_iterator ci;
301  for (ci = _children.begin(); ci != _children.end(); ++ci) {
302  SoftNodeDesc *child = (*ci);
303  softegg_cat.spam() << child->get_name() << ",";
304  }
305  softegg_cat.spam() << endl;
306  }
307  Children::const_iterator ci;
308  for (ci = _children.begin(); ci != _children.end(); ++ci) {
309  SoftNodeDesc *child = (*ci);
310  child->check_junk(parent_junk);
311  }
312 }
313 
314 ///////////////////////////////////////////////////////////////////////
315 // Function: SoftNodeTree::is_partial
316 // Access: Public
317 // Description: check to see if this is a selected branch we want to
318 // descend - this will prevent creating geometry for
319 // other parts
320 ///////////////////////////////////////////////////////////////////////
321 bool SoftNodeDesc::
322 is_partial(char *search_prefix) {
323  const char *name = fullname;
324 
325  // if no search prefix then return false
326  if (!search_prefix)
327  return false;
328  // if name is search_prefix, return false
329  if (strstr(name, search_prefix) != NULL) {
330  softegg_cat.debug() << "matched " << name << " ";
331  return false;
332  }
333  // if name is not search_prefix, look in its parent
334  if (strstr(name, search_prefix) == NULL) {
335  softegg_cat.debug() << "node " << name << " ";
336  if (_parent)
337  return _parent->is_partial(search_prefix);
338  }
339  // neither name nor its parent is search_prefix
340  return true;
341 }
342 
343 ///////////////////////////////////////////////////////////////////////
344 // Function: SoftNodeTree::set_parentJoint
345 // Access: Public
346 // Description: Go through the ancestors and figure out who is the
347 // immediate _parentJoint of this node
348 ///////////////////////////////////////////////////////////////////////
349 void SoftNodeDesc::
350 set_parentJoint(SAA_Scene *scene, SoftNodeDesc *lastJoint) {
351  if (is_junk())
352  return;
353  //set its parent joint to the lastJoint
354  _parentJoint = lastJoint;
355  softegg_cat.spam() << get_name() << ": parent joint set to :" << lastJoint;
356  if (lastJoint)
357  softegg_cat.spam() << "(" << lastJoint->get_name() << ")";
358  softegg_cat.spam() << endl;
359 
360  // is this node a joint?
361  SAA_Boolean isSkeleton = false;
362  if (has_model())
363  SAA_modelIsSkeleton( scene, get_model(), &isSkeleton );
364 
365  // if already a joint or name has "joint" in it
366  const char *name = get_name().c_str();
367  if (is_joint() || isSkeleton || strstr(name, "joint") != NULL) {
368  lastJoint = this;
369  }
370  if ( _parentJoint && strstr( _parentJoint->get_name().c_str(), "scale" ) != NULL ) {
371  // make sure _parentJoint didn't have the name "joint" in it
372  if (strstr(_parentJoint->get_name().c_str(), "joint") == NULL) {
373  _parentJoint = NULL;
374  // _parentJoint = lastJoint = NULL;
375  softegg_cat.spam() << "scale joint flag set!\n";
376  }
377  }
378 
379  // look in the children
380  Children::const_iterator ci;
381  for (ci = _children.begin(); ci != _children.end(); ++ci) {
382  SoftNodeDesc *child = (*ci);
383  child->set_parentJoint(scene, lastJoint);
384  }
385 }
386 
387 ////////////////////////////////////////////////////////////////////
388 // Function: SoftNodeDesc::check_pseudo_joints
389 // Access: Private
390 // Description: Walks the hierarchy, looking for non-joint nodes that
391 // are both children and parents of a joint. These
392 // nodes are deemed to be pseudo joints, since the
393 // converter must treat them as joints.
394 ////////////////////////////////////////////////////////////////////
395 void SoftNodeDesc::
396 check_pseudo_joints(bool joint_above) {
397  if (_joint_type == JT_joint_parent && joint_above) {
398  // This is one such node: it is the parent of a joint
399  // (JT_joint_parent is set), and it is the child of a joint
400  // (joint_above is set).
401  _joint_type = JT_pseudo_joint;
402  softegg_cat.debug() << "pseudo " << get_name() << " case1\n";
403  }
404 
405  if (_joint_type == JT_joint) {
406  // If this node is itself a joint, then joint_above is true for
407  // all child nodes.
408  joint_above = true;
409  }
410 
411  // Don't bother traversing further if _joint_type is none or junk, since
412  // that means this node has no joint children.
413  if (_joint_type != JT_none && _joint_type != JT_junk) {
414 
415  bool any_joints = false;
416  Children::const_iterator ci;
417  for (ci = _children.begin(); ci != _children.end(); ++ci) {
418  SoftNodeDesc *child = (*ci);
419  child->check_pseudo_joints(joint_above);
420  if (child->is_joint()) {
421  softegg_cat.spam() << get_name() << " any_joint true by " << child->get_name() << endl;
422  any_joints = true;
423  }
424  }
425 
426  // If any children qualify as joints, then any sibling nodes that
427  // are parents of joints are also elevated to joints.
428  if (any_joints) {
429  bool all_joints = true;
430  for (ci = _children.begin(); ci != _children.end(); ++ci) {
431  SoftNodeDesc *child = (*ci);
432  if (child->_joint_type == JT_joint_parent) {
433  child->_joint_type = JT_pseudo_joint;
434  softegg_cat.debug() << "pseudo " << child->get_name() << " case2 by parent " << get_name() << "\n";
435  } else if (child->_joint_type == JT_none || child->_joint_type == JT_junk) {
436  all_joints = false;
437  }
438  }
439 
440  if (all_joints || any_joints) {
441  // Finally, if all children or at least one is a joint, then we are too.
442  if (_joint_type == JT_joint_parent) {
443  _joint_type = JT_pseudo_joint;
444  softegg_cat.debug() << "pseudo " << get_name() << " case3\n";
445  }
446  }
447  }
448  }
449  else
450  softegg_cat.spam() << "found null joint " << get_name() << endl;
451 }
452 
453 ////////////////////////////////////////////////////////////////////
454 // Function: SoftToEggConverter::get_transform
455 // Access: Private
456 // Description: Extracts the transform on the indicated Soft node,
457 // and applies it to the corresponding Egg node.
458 ////////////////////////////////////////////////////////////////////
459 void SoftNodeDesc::
460 get_transform(SAA_Scene *scene, EggGroup *egg_group, bool global) {
461  // Get the model's matrix
462  int scale_joint = 0;
463 
464  if (!global && _parentJoint && !stec.flatten && !scale_joint) {
465 
466  SAA_modelGetMatrix( scene, get_model(), SAA_COORDSYS_LOCAL, matrix );
467  softegg_cat.debug() << get_name() << " using local matrix :parent ";
468 
469  } else {
470 
471  SAA_modelGetMatrix( scene, get_model(), SAA_COORDSYS_GLOBAL, matrix );
472  softegg_cat.debug() << get_name() << " using global matrix :parent ";
473 
474  }
475 
476  if (_parentJoint && !stec.flatten)
477  softegg_cat.debug() << _parentJoint->get_name() << endl;
478  else
479  softegg_cat.debug() << _parentJoint << endl;
480 
481 
482  softegg_cat.spam() << "model matrix = " << matrix[0][0] << " " << matrix[0][1] << " " << matrix[0][2] << " " << matrix[0][3] << "\n";
483  softegg_cat.spam() << "model matrix = " << matrix[1][0] << " " << matrix[1][1] << " " << matrix[1][2] << " " << matrix[1][3] << "\n";
484  softegg_cat.spam() << "model matrix = " << matrix[2][0] << " " << matrix[2][1] << " " << matrix[2][2] << " " << matrix[2][3] << "\n";
485  softegg_cat.spam() << "model matrix = " << matrix[3][0] << " " << matrix[3][1] << " " << matrix[3][2] << " " << matrix[3][3] << "\n";
486 
487  if (!global && is_joint()) {
488  LMatrix4d m4d(matrix[0][0], matrix[0][1], matrix[0][2], matrix[0][3],
489  matrix[1][0], matrix[1][1], matrix[1][2], matrix[1][3],
490  matrix[2][0], matrix[2][1], matrix[2][2], matrix[2][3],
491  matrix[3][0], matrix[3][1], matrix[3][2], matrix[3][3]);
492  if (!m4d.almost_equal(LMatrix4d::ident_mat(), 0.0001)) {
493  egg_group->set_transform3d(m4d);
494  softegg_cat.spam() << "set transform in egg_group\n";
495  }
496  }
497  return;
498 }
499 
500 ////////////////////////////////////////////////////////////////////
501 // Function: SoftNodeDesc::get_joint_transform
502 // Access: Private
503 // Description: Extracts the transform on the indicated Soft node,
504 // as appropriate for a joint in an animated character,
505 // and applies it to the indicated node. This is
506 // different from get_transform() in that it does not
507 // respect the _transform_type flag, and it does not
508 // consider the relative transforms within the egg file.
509 // more added functionality: now fills in components of
510 // anim (EffXfmSAnim) class (masad).
511 ////////////////////////////////////////////////////////////////////
512 void SoftNodeDesc::
513 get_joint_transform(SAA_Scene *scene, EggGroup *egg_group, EggXfmSAnim *anim, bool global) {
514  // SI_Error result;
515  SAA_Elem *skeletonPart = _model;
516  const char *name = get_name().c_str();
517 
518  if ( skeletonPart != NULL ) {
519  PN_stdfloat i,j,k;
520  PN_stdfloat h,p,r;
521  PN_stdfloat x,y,z;
522  int scale_joint = 0;
523 
524  softegg_cat.spam() << "\n\nanimating child " << name << endl;
525 
526  if (_parentJoint && !stec.flatten && !scale_joint ) {
527  softegg_cat.debug() << "using local matrix\n";
528 
529  //get SAA orientation
530  SAA_modelGetRotation( scene, skeletonPart, SAA_COORDSYS_LOCAL,
531  &p, &h, &r );
532 
533  //get SAA translation
534  SAA_modelGetTranslation( scene, skeletonPart, SAA_COORDSYS_LOCAL,
535  &x, &y, &z );
536 
537  //get SAA scaling
538  SAA_modelGetScaling( scene, skeletonPart, SAA_COORDSYS_LOCAL,
539  &i, &j, &k );
540  } else {
541  softegg_cat.debug() << " using global matrix\n";
542 
543  //get SAA orientation
544  SAA_modelGetRotation( scene, skeletonPart, SAA_COORDSYS_GLOBAL,
545  &p, &h, &r );
546 
547  //get SAA translation
548  SAA_modelGetTranslation( scene, skeletonPart, SAA_COORDSYS_GLOBAL,
549  &x, &y, &z );
550 
551  //get SAA scaling
552  SAA_modelGetScaling( scene, skeletonPart, SAA_COORDSYS_GLOBAL,
553  &i, &j, &k );
554  }
555 
556  softegg_cat.spam() << "\nanim data: " << i << " " << j << " " << k << endl;
557  softegg_cat.spam() << "\t" << p << " " << h << " " << r << endl;
558  softegg_cat.spam() << "\t" << x << " " << y << " " << z << endl;
559 
560  // Encode the component multiplication ordering in the egg file.
561  // SoftImage always uses this order, regardless of the setting of
562  // temp-hpr-fix.
563  anim->set_order("sphrt");
564 
565  // Add each component by their names
566  anim->add_component_data("i", i);
567  anim->add_component_data("j", j);
568  anim->add_component_data("k", k);
569  anim->add_component_data("p", p);
570  anim->add_component_data("h", h);
571  anim->add_component_data("r", r);
572  anim->add_component_data("x", x);
573  anim->add_component_data("y", y);
574  anim->add_component_data("z", z);
575  }
576  else {
577  softegg_cat.debug() << "Cannot build anim table - no skeleton\n";
578  }
579 }
580 
581 ////////////////////////////////////////////////////////////////////
582 // Function: SoftNodeDesc::load_poly_model
583 // Access: Private
584 // Description: Converts the indicated Soft polyset to a bunch of
585 // EggPolygons and parents them to the indicated egg
586 // group.
587 ////////////////////////////////////////////////////////////////////
588 void SoftNodeDesc::
589 load_poly_model(SAA_Scene *scene, SAA_ModelType type) {
590  SI_Error result;
591  const char *name = get_name().c_str();
592 
593  int i;
594  int id = 0;
595 
596  // if making a pose - get deformed geometry
597  if ( stec.make_pose )
598  gtype = SAA_GEOM_DEFORMED;
599 
600  // If the model is a PATCH in soft, set its step before tesselating
601  else if ( type == SAA_MPTCH )
602  SAA_patchSetStep( scene, _model, stec.nurbs_step, stec.nurbs_step );
603 
604  // Get the number of triangles
605  result = SAA_modelGetNbTriangles( scene, _model, gtype, id, &numTri);
606  softegg_cat.spam() << "triangles: " << numTri << "\n";
607 
608  if ( result != SI_SUCCESS ) {
609  softegg_cat.spam() << "Error: couldn't get number of triangles!\n";
610  softegg_cat.debug() << "\tbailing on model: " << name << "\n";
611  return;
612  }
613 
614  // check to see if surface is also skeleton...
615  SAA_Boolean isSkeleton = FALSE;
616 
617  SAA_modelIsSkeleton( scene, _model, &isSkeleton );
618 
619  // check to see if this surface is used as a skeleton
620  // or is animated via constraint only ( these nodes are
621  // tagged by the animator with the keyword "joint"
622  // somewhere in the nodes name)
623  softegg_cat.spam() << "is Skeleton? " << isSkeleton << "\n";
624 
625  /*************************************************************************************/
626 
627  // model is not a null and has no triangles!
628  if ( !numTri ) {
629  softegg_cat.spam() << "no triangles!\n";
630  }
631  else {
632  // allocate array of triangles
633  triangles = (SAA_SubElem *) new SAA_SubElem[numTri];
634  if (!triangles) {
635  softegg_cat.info() << "Not enough Memory for triangles...\n";
636  exit(1);
637  }
638  // triangulate model and read the triangles into array
639  SAA_modelGetTriangles( scene, _model, gtype, id, numTri, triangles );
640  softegg_cat.spam() << "got triangles\n";
641 
642  /***********************************************************************************/
643 
644  // allocate array of materials (Asad: it gives a warning if try to get one triangle
645  // at a time...investigate later
646  // read each triangle's material into array
647  materials = (SAA_Elem*) new SAA_Elem[numTri];
648  SAA_triangleGetMaterials( scene, _model, numTri, triangles, materials );
649  if (!materials) {
650  softegg_cat.info() << "Not enough Memory for materials...\n";
651  exit(1);
652  }
653  softegg_cat.spam() << "got materials\n";
654 
655  /***********************************************************************************/
656 
657  // allocate array of textures per triangle
658  numTexTri = new int[numTri];
659  const void *relinfo;
660 
661  // find out how many local textures per triangle
662  for (i = 0; i < numTri; i++) {
663  result = SAA_materialRelationGetT2DLocNbElements( scene, &materials[i], FALSE,
664  &relinfo, &numTexTri[i] );
665  // polytex
666  if ( result == SI_SUCCESS )
667  numTexLoc += numTexTri[i];
668  }
669 
670  // don't need this anymore...
671  //free( numTexTri );
672 
673  // get local textures if present
674  if ( numTexLoc ) {
675  softegg_cat.spam() << "numTexLoc = " << numTexLoc << endl;
676 
677  // allocate arrays of texture info
678  uScale = new PN_stdfloat[numTri];
679  vScale = new PN_stdfloat[numTri];
680  uOffset = new PN_stdfloat[numTri];
681  vOffset = new PN_stdfloat[numTri];
682  texNameArray = new char *[numTri];
683  uRepeat = new int[numTri];
684  vRepeat = new int[numTri];
685 
686  // ASSUME only one texture per material
687  textures = new SAA_Elem[numTri];
688 
689  for ( i = 0; i < numTri; i++ ) {
690  // and read all referenced local textures into array
691  SAA_materialRelationGetT2DLocElements( scene, &materials[i],
692  TEX_PER_MAT , &textures[i] );
693 
694  // initialize the array value
695  texNameArray[i] = NULL;
696  // initialize the repeats
697  uRepeat[i] = vRepeat[i] = 0;
698 
699  // see if this triangle has texture info
700  if (numTexTri[i] == 0)
701  continue;
702 
703  // check to see if texture is present
704  result = SAA_elementIsValid( scene, &textures[i], &valid );
705 
706  if ( result != SI_SUCCESS )
707  softegg_cat.spam() << "SAA_elementIsValid failed!!!!\n";
708 
709  // texture present - get the name and uv info
710  if ( valid ) {
711  // according to drose, we don't need to convert .pic files to .rgb,
712  // panda can now read the .pic files.
713  texNameArray[i] = stec.GetTextureName(scene, &textures[i]);
714 
715  softegg_cat.spam() << " tritex[" << i << "] named: " << texNameArray[i] << endl;
716 
717  SAA_texture2DGetUVSwap( scene, &textures[i], &uv_swap );
718 
719  if ( uv_swap == TRUE )
720  softegg_cat.spam() << " swapping u and v...\n" ;
721 
722  SAA_texture2DGetUScale( scene, &textures[i], &uScale[i] );
723  SAA_texture2DGetVScale( scene, &textures[i], &vScale[i] );
724  SAA_texture2DGetUOffset( scene, &textures[i], &uOffset[i] );
725  SAA_texture2DGetVOffset( scene, &textures[i], &vOffset[i] );
726 
727  softegg_cat.spam() << "tritex[" << i << "] uScale: " << uScale[i] << " vScale: " << vScale[i] << endl;
728  softegg_cat.spam() << " uOffset: " << uOffset[i] << " vOffset: " << vOffset[i] << endl;
729 
730  SAA_texture2DGetRepeats( scene, &textures[i], &uRepeat[i], &vRepeat[i] );
731  softegg_cat.spam() << "uRepeat = " << uRepeat[i] << ", vRepeat = " << vRepeat[i] << endl;
732  }
733  else {
734  softegg_cat.spam() << "Invalid texture...\n";
735  softegg_cat.spam() << " tritex[" << i << "] named: (null)\n";
736  }
737  }
738  }
739  else { // if no local textures, try to get global textures
740  SAA_modelRelationGetT2DGlbNbElements( scene, _model,
741  FALSE, &relinfo, &numTexGlb );
742  if ( numTexGlb ) {
743  // ASSUME only one texture per model
744  textures = new SAA_Elem;
745  // get the referenced texture
746  SAA_modelRelationGetT2DGlbElements( scene, _model,
747  TEX_PER_MAT, textures );
748  softegg_cat.spam() << "numTexGlb = " << numTexGlb << endl;
749  // check to see if texture is present
750  SAA_elementIsValid( scene, textures, &valid );
751  if ( valid ) { // texture present - get the name and uv info
752  SAA_texture2DGetUVSwap( scene, textures, &uv_swap );
753 
754  if ( uv_swap == TRUE )
755  softegg_cat.spam() << " swapping u and v...\n";
756 
757  // according to drose, we don't need to convert .pic files to .rgb,
758  // panda can now read the .pic files.
759  texNameArray = new char *[1];
760  *texNameArray = stec.GetTextureName(scene, textures);
761 
762  uRepeat = new int;
763  vRepeat = new int;
764 
765  softegg_cat.spam() << " global tex named: " << *texNameArray << endl;
766 
767  // allocate arrays of texture info
768  uScale = new PN_stdfloat;
769  vScale = new PN_stdfloat;
770  uOffset = new PN_stdfloat;
771  vOffset = new PN_stdfloat;
772 
773  SAA_texture2DGetUScale( scene, textures, uScale );
774  SAA_texture2DGetVScale( scene, textures, vScale );
775  SAA_texture2DGetUOffset( scene, textures, uOffset );
776  SAA_texture2DGetVOffset( scene, textures, vOffset );
777 
778  softegg_cat.spam() << " global tex uScale: " << *uScale << " vScale: " << *vScale << endl;
779  softegg_cat.spam() << " uOffset: " << *uOffset << " vOffset: " << *vOffset << endl;
780 
781  SAA_texture2DGetRepeats( scene, textures, uRepeat, vRepeat );
782  softegg_cat.spam() << "uRepeat = " << *uRepeat << ", vRepeat = " << *vRepeat << endl;
783  }
784  else {
785  softegg_cat.spam() << "Invalid Texture...\n";
786  }
787  }
788  }
789  }
790  softegg_cat.spam() << "got textures" << endl;
791 }
792 
793 ////////////////////////////////////////////////////////////////////
794 // Function: SoftNodeDesc::load_nurbs_model
795 // Access: Private
796 // Description: Converts the indicated Soft polyset to a bunch of
797 // EggPolygons and parents them to the indicated egg
798 // group.
799 ////////////////////////////////////////////////////////////////////
800 void SoftNodeDesc::
801 load_nurbs_model(SAA_Scene *scene, SAA_ModelType type) {
802  SI_Error result;
803  const char *name = get_name().c_str();
804 
805  // if making a pose - get deformed geometry
806  if ( stec.make_pose )
807  gtype = SAA_GEOM_DEFORMED;
808 
809  // If the model is a NURBS in soft, set its step before tesselating
810  if ( type == SAA_MNSRF )
811  SAA_nurbsSurfaceSetStep( scene, _model, stec.nurbs_step, stec.nurbs_step );
812 
813  // get the materials
814  /***********************************************************************************/
815  const void *relinfo;
816 
817  SAA_modelRelationGetMatNbElements( scene, get_model(), FALSE, &relinfo,
818  &numNurbMats );
819 
820  softegg_cat.spam() << "nurbs surf has " << numNurbMats << " materials\n";
821 
822  if ( numNurbMats ) {
823  materials = new SAA_Elem[numNurbMats];
824  if (!materials) {
825  softegg_cat.info() << "Out Of Memory on allocating materials\n";
826  exit(1);
827  }
828 
829  SAA_modelRelationGetMatElements( scene, get_model(), relinfo,
830  numNurbMats, materials );
831 
832  softegg_cat.spam() << "got materials\n";
833 
834  // get the textures
835  /***********************************************************************************/
836  numNurbTexLoc = 0;
837  numNurbTexGlb = 0;
838 
839  // find out how many local textures per NURBS surface
840  // ASSUME it only has one material
841  SAA_materialRelationGetT2DLocNbElements( scene, &materials[0], FALSE, &relinfo, &numNurbTexLoc );
842 
843  // if present, get local textures
844  if ( numNurbTexLoc ) {
845  softegg_cat.spam() << name << " had " << numNurbTexLoc << " local tex\n";
846  nassertv(numNurbTexLoc == 1);
847 
848  textures = new SAA_Elem[numNurbTexLoc];
849 
850  // get the referenced texture
851  SAA_materialRelationGetT2DLocElements( scene, &materials[0], TEX_PER_MAT, &textures[0] );
852 
853  }
854  // if no locals, try to get globals
855  else {
856  SAA_modelRelationGetT2DGlbNbElements( scene, get_model(), FALSE, &relinfo, &numNurbTexGlb );
857 
858  if ( numNurbTexGlb ) {
859  softegg_cat.spam() << name << " had " << numNurbTexGlb << " global tex\n";
860  nassertv(numNurbTexGlb == 1);
861 
862  textures = new SAA_Elem[numNurbTexGlb];
863 
864  // get the referenced texture
865  SAA_modelRelationGetT2DGlbElements( scene, get_model(), TEX_PER_MAT, &textures[0] );
866  }
867  }
868 
869  if ( numNurbTexLoc || numNurbTexGlb) {
870 
871  // allocate the texture name array
872  texNameArray = new char *[1];
873  // allocate arrays of texture info
874  uScale = new PN_stdfloat;
875  vScale = new PN_stdfloat;
876  uOffset = new PN_stdfloat;
877  vOffset = new PN_stdfloat;
878  uRepeat = new int;
879  vRepeat = new int;
880 
881  // check to see if texture is present
882  result = SAA_elementIsValid( scene, &textures[0], &valid );
883 
884  if ( result != SI_SUCCESS )
885  softegg_cat.spam() << "SAA_elementIsValid failed!!!!\n";
886 
887  // texture present - get the name and uv info
888  if ( valid ) {
889  // according to drose, we don't need to convert .pic files to .rgb,
890  // panda can now read the .pic files.
891  texNameArray[0] = stec.GetTextureName(scene, &textures[0]);
892 
893  softegg_cat.spam() << " tritex[0] named: " << texNameArray[0] << endl;
894 
895  SAA_texture2DGetUVSwap( scene, &textures[0], &uv_swap );
896 
897  if ( uv_swap == TRUE )
898  softegg_cat.spam() << " swapping u and v...\n" ;
899 
900  SAA_texture2DGetUScale( scene, &textures[0], uScale );
901  SAA_texture2DGetVScale( scene, &textures[0], vScale );
902  SAA_texture2DGetUOffset( scene, &textures[0], uOffset );
903  SAA_texture2DGetVOffset( scene, &textures[0], vOffset );
904 
905  softegg_cat.spam() << "tritex[0] uScale: " << *uScale << " vScale: " << *vScale << endl;
906  softegg_cat.spam() << " uOffset: " << *uOffset << " vOffset: " << *vOffset << endl;
907 
908  SAA_texture2DGetRepeats( scene, &textures[0], uRepeat, vRepeat );
909  softegg_cat.spam() << "uRepeat = " << *uRepeat << ", vRepeat = " << *vRepeat << endl;
910  }
911  else {
912  softegg_cat.spam() << "Invalid texture...\n";
913  softegg_cat.spam() << " tritex[0] named: (null)\n";
914  }
915  }
916 
917  softegg_cat.spam() << "got textures\n";
918  }
919 }
920 
921 ////////////////////////////////////////////////////////////////////
922 // Function: find_shape_vert
923 // Access: Public
924 // Description: given a vertex, find its corresponding shape vertex
925 // and return its index.
926 ////////////////////////////////////////////////////////////////////
927 int SoftNodeDesc::
928 find_shape_vert(LPoint3d p3d, SAA_DVector *vertices, int numVert) {
929  int i, found = 0;
930 
931  for (i = 0; i < numVert && !found ; i++) {
932  if ((p3d[0] == vertices[i].x) &&
933  (p3d[1] == vertices[i].y) &&
934  (p3d[2] == vertices[i].z)) {
935  found = 1;
936  softegg_cat.spam() << "found shape vert at index " << i << endl;
937  }
938  }
939 
940  if (!found )
941  i = -1;
942  else
943  i--;
944 
945  return i;
946 }
947 
948 ////////////////////////////////////////////////////////////////////
949 // Function: make_vertex_offsets
950 // Access: Public
951 // Description: Given a scene, a model , the vertices of its original
952 // shape and its name find the difference between the
953 // geometry of its key shapes and the models original
954 // geometry and add morph vertices to the egg data to
955 // reflect these changes.
956 ////////////////////////////////////////////////////////////////////
957 void SoftNodeDesc::
958 make_vertex_offsets(int numShapes) {
959  int i, j;
960  int offset;
961  int numCV;
962  char tableName[_MAX_PATH];
963  SAA_DVector *shapeVerts = NULL;
964  SAA_DVector *uniqueVerts = NULL;
965  SAA_Elem *model = get_model();
966  SAA_Scene *scene = &stec.scene;
967 
968  EggVertexPool *vpool = NULL;
969  string vpool_name = get_name() + ".verts";
970  EggNode *t = stec._tree.get_egg_root()->find_child(vpool_name);
971  if (t)
972  DCAST_INTO_V(vpool, t);
973 
974  int numOrigVert = (int) vpool->size();
976 
977  if ((type == SAA_MNSRF) && stec.make_nurbs)
978  SAA_nurbsSurfaceSetStep( scene, model, stec.nurbs_step, stec.nurbs_step );
979 
980  SAA_modelGetNbVertices( scene, model, &numCV );
981 
982  // get the shape verts
983  uniqueVerts = new SAA_DVector[numCV];
984  SAA_modelGetVertices( scene, model, SAA_GEOM_ORIGINAL, 0,
985  numCV, uniqueVerts );
986 
987  softegg_cat.spam() << numCV << " CV's\n";
988 
989  for ( i = 0; i < numCV; i++ )
990  // convert vertices to global
991  _VCT_X_MAT( uniqueVerts[i], uniqueVerts[i], matrix);
992  softegg_cat.spam() << "uniqueVerts[" << i << "] = " << uniqueVerts[i].x << " " << uniqueVerts[i].y
993  << " " << uniqueVerts[i].z << " " << uniqueVerts[i].w << endl;
994 
995  // iterate through for each key shape (except original)
996  for ( i = 1; i < numShapes; i++ ) {
997 
998  sprintf(tableName, "%s.%d", get_name().c_str(), i);
999 
1000  softegg_cat.spam() << "\nMaking geometry offsets for " << tableName << "...\n";
1001 
1002  if ((type == SAA_MNSRF) && stec.make_nurbs)
1003  softegg_cat.spam() << "calculating NURBS morphs...\n";
1004  else
1005  softegg_cat.spam() << "calculating triangle morphs...\n";
1006 
1007  // get the shape verts
1008  shapeVerts = new SAA_DVector[numCV];
1009  SAA_modelGetVertices( scene, model, SAA_GEOM_SHAPE, i+1, numCV, shapeVerts );
1010 
1011  for ( j=0; j < numCV; j++ ) {
1012  // convert vertices to global
1013  _VCT_X_MAT( shapeVerts[j], shapeVerts[j], matrix);
1014 
1015  softegg_cat.spam() << "shapeVerts[" << j << "] = " << shapeVerts[j].x << " "
1016  << shapeVerts[j].y << " " << shapeVerts[j].z << endl;
1017  }
1018  softegg_cat.spam() << endl;
1019 
1020  // for every original vertex, compare to the corresponding
1021  // key shape vertex and see if a vertex offset is needed
1022  j = 0;
1023  for (vi = vpool->begin(); vi != vpool->end(); ++vi, ++j) {
1024 
1025  double dx, dy, dz;
1026  EggVertex *vert = (*vi);
1027  LPoint3d p3d = vert->get_pos3();
1028 
1029  softegg_cat.spam() << "oVert[" << j << "] = " << p3d[0] << " " << p3d[1] << " " << p3d[2] << endl;
1030  if ((type == SAA_MNSRF) && stec.make_nurbs) {
1031  dx = shapeVerts[j].x - p3d[0];
1032  dy = shapeVerts[j].y - p3d[1];
1033  dz = shapeVerts[j].z - p3d[2];
1034 
1035  softegg_cat.spam() << "global shapeVerts[" << j << "] = " << shapeVerts[j].x << " "
1036  << shapeVerts[j].y << " " << shapeVerts[j].z << " " << shapeVerts[j].w << endl;
1037  }
1038  else {
1039  // we need to map from original vertices
1040  // to triangle shape vertices here
1041  offset = find_shape_vert(p3d, uniqueVerts, numCV);
1042 
1043  dx = shapeVerts[offset].x - p3d[0];
1044  dy = shapeVerts[offset].y - p3d[1];
1045  dz = shapeVerts[offset].z - p3d[2];
1046 
1047  softegg_cat.spam() << "global shapeVerts[" << offset << "] = " << shapeVerts[offset].x << " "
1048  << shapeVerts[offset].y << " " << shapeVerts[offset].z << endl;
1049  }
1050 
1051  softegg_cat.spam() << j << ": dx = " << dx << ", dy = " << dy << ", dz = " << dz << endl;
1052 
1053  // if change isn't negligible, make a morph vertex entry
1054  double total = fabs(dx)+fabs(dy)+fabs(dz);
1055  if ( total > 0.00001 ) {
1056  if ( vpool != NULL ) {
1057  // create offset
1058  LVector3d p(dx, dy, dz);
1059  EggMorphVertex *dxyz = new EggMorphVertex(tableName, p);
1060  // add the offset to the vertex
1061  vert->_dxyzs.insert(*dxyz);
1062  }
1063  else
1064  softegg_cat.spam() << "Error: couldn't find vertex pool " << vpool_name << endl;
1065 
1066  } // if total
1067  } //for j
1068  } //for i
1069 }
1070 
1071 ////////////////////////////////////////////////////////////////////
1072 // Function: make_morph_table
1073 // Access: Public
1074 // Description: Given a scene, a model, a name and a frame time,
1075 // determine what type of shape interpolation is
1076 // used and call the appropriate function to extract
1077 // the shape weight info for this frame...
1078 ////////////////////////////////////////////////////////////////////
1079 void SoftNodeDesc::
1080 make_morph_table( PN_stdfloat time ) {
1081  int numShapes;
1082  SAA_Elem *model = NULL;
1083  SAA_AnimInterpType type;
1084  SAA_Scene *scene = &stec.scene;
1085 
1086  if (has_model())
1087  model = get_model();
1088  else
1089  return;
1090 
1091  // Get the number of key shapes
1092  SAA_modelGetNbShapes( scene, model, &numShapes );
1093 
1094  if ( numShapes <= 0 ) {
1095  return;
1096  }
1097 
1098  stec.has_morph = true;
1099 
1100  softegg_cat.spam() << "make_morph_table: " << get_name() << " : num shapes: " << numShapes << endl;
1101 
1102  SAA_modelGetShapeInterpolation( scene, model, &type );
1103 
1104  if ( type == SAA_ANIM_LINEAR || type == SAA_ANIM_CARDINAL ) {
1105  softegg_cat.spam() << "linear morph" << endl;
1106  make_linear_morph_table( numShapes, time );
1107  }
1108  else { // must be weighted...
1109  // check first for expressions
1110  softegg_cat.spam() << "expression morph" << endl;
1111  make_expression_morph_table( numShapes, time );
1112  }
1113 }
1114 
1115 ////////////////////////////////////////////////////////////////////
1116 // Function: make_linear_morph_table
1117 // Access: Public
1118 // Description: Given a scene, a model, its name, and the time,
1119 // get the shape fcurve for the model and determine
1120 // the shape weights for the given time and use them
1121 // to populate the morph table.
1122 ////////////////////////////////////////////////////////////////////
1123 void SoftNodeDesc::
1124 make_linear_morph_table(int numShapes, PN_stdfloat time) {
1125  int i;
1126  PN_stdfloat curveVal;
1127  char tableName[_MAX_PATH];
1128  SAA_Elem fcurve;
1129  //SAnimTable *thisTable;
1130  EggSAnimData *anim;
1131  SAA_Elem *model = get_model();
1132  SAA_Scene *scene = &stec.scene;
1133 
1134  softegg_cat.spam() << "linear interp, getting fcurve\n";
1135 
1136  SAA_modelFcurveGetShape( scene, model, &fcurve );
1137 
1138  SAA_fcurveEval( scene, &fcurve, time, &curveVal );
1139 
1140  softegg_cat.spam() << "at time " << time << ", fcurve for " << get_name() << " = " << curveVal << endl;
1141 
1142  PN_stdfloat nextVal = 0.0f;
1143 
1144  // populate morph table values for this frame
1145  for ( i = 1; i < numShapes; i++ ) {
1146  // derive table name from the model name
1147  sprintf(tableName, "%s.%d", get_name().c_str(), i);
1148 
1149  softegg_cat.spam() << "Linear: looking for table '" << tableName << "'\n";
1150 
1151  //find the morph table associated with this key shape
1152  anim = stec.find_morph_table(tableName);
1153 
1154  if ( anim != NULL ) {
1155  if ( i == (int)curveVal ) {
1156  if ( curveVal - i == 0 ) {
1157  anim->add_data(1.0f );
1158  softegg_cat.spam() << "adding element 1.0f\n";
1159  }
1160  else {
1161  anim->add_data(1.0f - (curveVal - i));
1162  nextVal = curveVal - i;
1163  softegg_cat.spam() << "adding element " << 1.0f - (curveVal - i) << endl;
1164  }
1165  }
1166  else {
1167  if ( nextVal ) {
1168  anim->add_data(nextVal );
1169  nextVal = 0.0f;
1170  softegg_cat.spam() << "adding element " << nextVal << endl;
1171  }
1172  else {
1173  anim->add_data(0.0f);
1174  softegg_cat.spam() << "adding element 0.0f\n";
1175  }
1176  }
1177 
1178  softegg_cat.spam() <<" to '" << tableName << "'\n";
1179  }
1180  else
1181  softegg_cat.spam() << i << " : Couldn't find table '" << tableName << "'\n";
1182  }
1183 }
1184 
1185 ////////////////////////////////////////////////////////////////////
1186 // Function: make_weighted_morph_table
1187 // Access: Public
1188 // Description: Given a scene, a model, a list of all models in the
1189 // scene, the number of models in the scece, the number
1190 // of key shapes for this model, the name of the model
1191 // and the current time, determine what method of
1192 // controlling the shape weights is used and call the
1193 // appropriate routine.
1194 ////////////////////////////////////////////////////////////////////
1195 void SoftNodeDesc::
1196 make_weighted_morph_table(int numShapes, PN_stdfloat time) {
1197  PN_stdfloat curveVal;
1198  SI_Error result;
1199  char tableName[_MAX_PATH];
1200  SAA_Elem *weightCurves;
1201  //SAnimTable *thisTable;
1202  EggSAnimData *anim;
1203  SAA_Elem *model = get_model();
1204  SAA_Scene *scene = &stec.scene;
1205 
1206  // allocate array of weight curves (one for each shape)
1207  weightCurves = new SAA_Elem[numShapes];
1208 
1209  result = SAA_modelFcurveGetShapeWeights(scene, model, numShapes, weightCurves);
1210 
1211  if ( result == SI_SUCCESS ) {
1212  for ( int i = 1; i < numShapes; i++ ) {
1213  SAA_fcurveEval( scene, &weightCurves[i], time, &curveVal );
1214 
1215  // make sure soft gave us a reasonable number
1216  //if (!isNum(curveVal))
1217  //curveVal = 0.0f;
1218 
1219  softegg_cat.spam() << "at time " << time << ", weightCurve[" << i << "] for " << get_name() << " = " << curveVal << endl;
1220 
1221  // derive table name from the model name
1222  sprintf(tableName, "%s.%d", get_name().c_str(), i);
1223 
1224  // find and populate shape table
1225  softegg_cat.spam() << "Weight: looking for table '" << tableName << "'\n";
1226 
1227  //find the morph table associated with this key shape
1228  anim = stec.find_morph_table(tableName);
1229 
1230  if ( anim != NULL ) {
1231  anim->add_data(curveVal);
1232  softegg_cat.spam() << "adding element " << curveVal << endl;
1233  }
1234  else
1235  softegg_cat.spam() << i << " : Couldn't find table '" << tableName << "'\n";
1236  }
1237  }
1238 }
1239 
1240 ////////////////////////////////////////////////////////////////////
1241 // Function: make_expression_morph_table
1242 // Access: Public
1243 // Description: Given a scene, a model and its number of key shapes
1244 // generate a morph table describing transitions btwn
1245 // the key shapes by evaluating the positions of the
1246 // controlling sliders.
1247 ////////////////////////////////////////////////////////////////////
1248 void SoftNodeDesc::
1249 make_expression_morph_table(int numShapes, PN_stdfloat time)
1250 {
1251  //int j;
1252  int numExp;
1253  char *track;
1254  //PN_stdfloat expVal;
1255  //PN_stdfloat sliderVal;
1256  //char *tableName;
1257  //char *sliderName;
1258  //SAnimTable *thisTable;
1259  SAA_Elem *expressions;
1260  SI_Error result;
1261 
1262  SAA_Elem *model = get_model();
1263  SAA_Scene *scene = &stec.scene;
1264 
1265  // populate morph table values for this frame
1266 
1267  // compose track name
1268  track = NULL;
1269 
1270  // find how many expressions for this shape
1271  SAA_elementGetNbExpressions( scene, model, track, FALSE, &numExp );
1272 
1273  softegg_cat.spam() << get_name() << " has " << numExp << " RHS expressions\n";
1274 
1275  if ( numExp ) {
1276  // get the expressions for this shape
1277  expressions = new SAA_Elem[numExp];
1278  softegg_cat.spam() << "getting " << numExp << " RHS expressions...\n";
1279 
1280  result = SAA_elementGetExpressions( scene, model, track, FALSE,
1281  numExp, expressions );
1282  /*
1283  if ( !result ) {
1284  for ( j = 1; j < numExp; j++ ) {
1285  if ( verbose >= 2 )
1286  {
1287  // debug see what we got
1288  int numvars;
1289 
1290  SAA_expressionGetNbVars( scene, &expressions[j], &numvars );
1291 
1292  int *varnamelen;
1293  int *varstrlen;
1294  int expstrlen;
1295 
1296  varnamelen = (int *)malloc(sizeof(int)*numvars);
1297  varstrlen = (int *)malloc(sizeof(int)*numvars);
1298 
1299  SAA_expressionGetStringLengths( scene, &expressions[j],
1300  numvars, varnamelen, varstrlen, &expstrlen );
1301 
1302  int *varnamesizes;
1303  int *varstrsizes;
1304 
1305  varnamesizes = (int *)malloc(sizeof(int)*numvars);
1306  varstrsizes = (int *)malloc(sizeof(int)*numvars);
1307 
1308  for ( int k = 0; k < numvars; k++ )
1309  {
1310  varnamesizes[k] = varnamelen[k] + 1;
1311  varstrsizes[k] = varstrlen[k] + 1;
1312  }
1313 
1314  int expstrsize = expstrlen + 1;
1315 
1316  char **varnames;
1317  char **varstrs;
1318 
1319  varnames = (char **)malloc(sizeof(char *)*numvars);
1320  varstrs = (char **)malloc(sizeof(char *)*numvars);
1321 
1322  for ( k = 0; k < numvars; k++ )
1323  {
1324  varnames[k] = (char *)malloc(sizeof(char)*
1325  varnamesizes[k]);
1326 
1327  varstrs[k] = (char *)malloc(sizeof(char)*
1328  varstrsizes[k]);
1329  }
1330 
1331  char *expstr = (char *)malloc(sizeof(char)* expstrsize );
1332 
1333  SAA_expressionGetStrings( scene, &expressions[j], numvars,
1334  varnamesizes, varstrsizes, expstrsize, varnames,
1335  varstrs, expstr );
1336 
1337  if ( verbose >= 2 )
1338  {
1339  fprintf( outStream, "expression = '%s'\n", expstr );
1340  fprintf( outStream, "has %d variables\n", numvars );
1341  }
1342  } //if verbose
1343 
1344  if ( verbose >= 2 )
1345  fprintf( outStream, "evaling expression...\n" );
1346 
1347  SAA_expressionEval( scene, &expressions[j], time, &expVal );
1348 
1349  if ( verbose >= 2 )
1350  fprintf( outStream, "time %f: exp val %f\n",
1351  time, expVal );
1352 
1353  // derive table name from the model name
1354  tableName = MakeTableName( name, j );
1355 
1356  if ( verbose >= 2 )
1357  fprintf( outStream, "Exp: looking for table '%s'\n",
1358  tableName );
1359 
1360  //find the morph table associated with this key shape
1361  anim = (SAnimTable *)
1362  (morphRoot->FindDescendent( tableName ));
1363 
1364  if ( anim != NULL )
1365  {
1366  anim->AddElement( expVal );
1367  if ( verbose >= 1 )
1368  fprintf( outStream, "%d: adding element %f to %s\n",
1369  j, expVal, tableName );
1370  fflush( outStream );
1371  }
1372  else
1373  {
1374  fprintf( outStream, "%d: Couldn't find table '%s'", j,
1375  tableName );
1376 
1377  fprintf( outStream, " for value %f\n", expVal );
1378  }
1379  }
1380  }
1381  else
1382  fprintf( outStream, "couldn't get expressions!!!\n" );
1383  */
1384  }
1385  else {
1386  softegg_cat.spam() << "weighted morph" << endl;
1387  // no expression, use weight curves
1388  make_weighted_morph_table(numShapes, time );
1389  }
1390 }
1391 
1392 //
1393 //
1394 //
This is an iterator adaptor that converts any iterator that returns a pair (e.g.
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:4716
bool has_model() const
Returns true if a Soft dag path has been associated with this node, false otherwise.
void get_joint_transform(SAA_Scene *scene, EggGroup *egg_group, EggXfmSAnim *anim, bool global)
Extracts the transform on the indicated Soft node, as appropriate for a joint in an animated characte...
void add_data(double value)
Adds a single element to the table.
Definition: eggAnimData.I:116
bool almost_equal(const LMatrix4d &other, double threshold) const
Returns true if two matrices are memberwise equal within a specified tolerance.
Definition: lmatrix.cxx:2058
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.
void force_set_parent(SoftNodeDesc *parent)
Sometimes, parent is not known at node creation As soon as it is known, set the parent.
void make_linear_morph_table(int numShapes, PN_stdfloat time)
Given a scene, a model, its name, and the time, get the shape fcurve for the model and determine the ...
void make_expression_morph_table(int numShapes, PN_stdfloat time)
Given a scene, a model and its number of key shapes generate a morph table describing transitions btw...
pair< iterator, bool > insert(const MorphType &value)
This is similar to the insert() interface for sets, except it does not guarantee that the resulting l...
Definition: eggMorphList.I:193
Corresponding to an <S$Anim> entry, this stores a single column of numbers, for instance for a morph ...
Definition: eggSAnimData.h:28
SAA_Elem * get_model() const
Returns the SAA_Elem * associated with this node.
LVertexd get_pos3() const
Valid if get_num_dimensions() returns 3 or 4.
Definition: eggVertex.I:160
A single <Dxyz> or <Duv> or some such entry.
Definition: eggMorph.h:33
size_type size() const
Returns the number of vertices in the pool.
iterator end() const
Returns an iterator that can be used to traverse through all the vertices in the pool.
iterator begin() const
Returns an iterator that can be used to traverse through all the vertices in the pool.
char * GetTextureName(SAA_Scene *scene, SAA_Elem *texture)
Given a texture element, return texture name with given tex_path.
EggSAnimData * find_morph_table(char *name)
Given a tablename, it either creates a new eggSAnimData structure (if doesn&#39;t exist) or locates it...
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition: eggGroup.h:36
void set_transform3d(const LMatrix4d &mat)
Sets the overall transform as a 4x4 matrix.
Definition: eggTransform.I:222
A base class for all things which can have a name.
Definition: namable.h:29
bool is_joint_parent() const
Returns true if the node is the parent or ancestor of a joint.
bool is_partial(char *search_prefix)
check to see if this is a selected branch we want to descend - this will prevent creating geometry fo...
static const LMatrix4d & ident_mat()
Returns an identity matrix.
Definition: lmatrix.h:5168
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal...
Definition: eggVertex.h:41
This corresponds to an <Xfm$Anim_S$> entry, which is a collection of up to nine <S$Anim> entries that...
Definition: eggXfmSAnim.h:33
void make_vertex_offsets(int numShapes)
Given a scene, a model , the vertices of its original shape and its name find the difference between ...
Describes a single instance of a node aka element in the Soft scene graph, relating it to the corresp...
Definition: softNodeDesc.h:46
void set_joint()
sets the _joint_type to JT_joint
void make_weighted_morph_table(int numShapes, PN_stdfloat time)
Given a scene, a model, a list of all models in the scene, the number of models in the scece...
This corresponds to a.
Definition: eggTable.h:31
void load_nurbs_model(SAA_Scene *scene, SAA_ModelType type)
Converts the indicated Soft polyset to a bunch of EggPolygons and parents them to the indicated egg g...
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
Definition: lvector3.h:760
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
Definition: lpoint3.h:544
void set_parent(SoftNodeDesc *parent)
Sometimes, parent is not known at node creation As soon as it is known, set the parent.
A base class for things that may be directly added into the egg hierarchy.
Definition: eggNode.h:38
int find_shape_vert(LPoint3d p3d, SAA_DVector *vertices, int numVert)
given a vertex, find its corresponding shape vertex and return its index.
void get_transform(SAA_Scene *scene, EggGroup *egg_group, bool global)
Extracts the transform on the indicated Soft node, and applies it to the corresponding Egg node...
EggNode * find_child(const string &name) const
Returns the child of this node whose name is the indicated string, or NULL if there is no child of th...
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
void set_model(SAA_Elem *model)
Indicates an associated between the SoftNodeDesc and some SAA_Elem instance.
bool is_joint() const
Returns true if the node should be treated as a joint by the converter.
A collection of vertices.
Definition: eggVertexPool.h:46
void load_poly_model(SAA_Scene *scene, SAA_ModelType type)
Converts the indicated Soft polyset to a bunch of EggPolygons and parents them to the indicated egg g...
void make_morph_table(PN_stdfloat time)
Given a scene, a model, a name and a frame time, determine what type of shape interpolation is used a...
bool is_junk() const
Returns true if the node should be treated as a junk by the converter.