Bläddra i källkod

Merge branch 'master' into cmake

Sam Edwards 7 år sedan
förälder
incheckning
58c065d970
98 ändrade filer med 560 tillägg och 10989 borttagningar
  1. 4 1
      direct/src/interval/FunctionInterval.py
  2. 0 20
      doc/INSTALLING-PLUGINS.TXT
  3. 0 183
      doc/InstallerNotes
  4. 8 0
      dtool/src/dtoolbase/dtoolbase.cxx
  5. 2 0
      dtool/src/dtoolbase/dtoolbase.h
  6. 9 0
      dtool/src/dtoolbase/dtoolbase_cc.h
  7. 10 10
      dtool/src/dtoolutil/textEncoder.I
  8. 10 10
      dtool/src/dtoolutil/textEncoder.h
  9. 6 1
      dtool/src/dtoolutil/textEncoder_ext.cxx
  10. 1 1
      dtool/src/dtoolutil/unicodeLatinMap.cxx
  11. 5 5
      dtool/src/dtoolutil/unicodeLatinMap.h
  12. 9 1
      dtool/src/interrogatedb/py_panda.cxx
  13. 1 1
      dtool/src/parser-inc/Python.h
  14. 0 20
      dtool/src/prc/notifyCategory.I
  15. 2 2
      dtool/src/prc/notifyCategory.h
  16. 0 12
      dtool/src/prc/notifyCategoryProxy.I
  17. 2 2
      dtool/src/prc/notifyCategoryProxy.h
  18. 36 46
      makepanda/makepanda.py
  19. 0 20
      makepanda/makepanda.vcproj
  20. 2 2
      panda/src/chan/animControl.cxx
  21. 3 1
      panda/src/chan/animControl.h
  22. 7 0
      panda/src/chan/partBundle.cxx
  23. 1 1
      panda/src/collide/collisionTraverser.cxx
  24. 5 5
      panda/src/display/graphicsEngine.cxx
  25. 13 13
      panda/src/display/graphicsOutput.cxx
  26. 1 0
      panda/src/display/graphicsOutput.h
  27. 14 28
      panda/src/display/graphicsPipeSelection.cxx
  28. 47 39
      panda/src/display/graphicsStateGuardian.cxx
  29. 0 1
      panda/src/display/p3display_composite2.cxx
  30. 3 5
      panda/src/distort/projectionScreen.cxx
  31. 5 5
      panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx
  32. 1 1
      panda/src/gles2gsg/gles2gsg.h
  33. 1 1
      panda/src/glesgsg/glesgsg.h
  34. 11 9
      panda/src/glstuff/glCgShaderContext_src.cxx
  35. 9 0
      panda/src/glstuff/glGraphicsBuffer_src.cxx
  36. 3 0
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  37. 23 2
      panda/src/gobj/geom.cxx
  38. 2 0
      panda/src/gobj/geom.h
  39. 3 1
      panda/src/gobj/geomVertexArrayData.I
  40. 16 3
      panda/src/gobj/geomVertexData.I
  41. 18 5
      panda/src/gobj/geomVertexData.cxx
  42. 2 2
      panda/src/gobj/preparedGraphicsObjects.cxx
  43. 1 1
      panda/src/gobj/textureReloadRequest.cxx
  44. 1 1
      panda/src/grutil/multitexReducer.cxx
  45. 1 1
      panda/src/net/connection.cxx
  46. 3 0
      panda/src/pgraph/cullTraverserData.cxx
  47. 2 3
      panda/src/pgraph/geomNode.cxx
  48. 4 1
      panda/src/pgraph/renderAttrib.cxx
  49. 3 0
      panda/src/pgraph/renderState.cxx
  50. 3 0
      panda/src/pgraph/transformState.cxx
  51. 0 8
      panda/src/pipeline/blockerSimple.I
  52. 2 2
      panda/src/pipeline/blockerSimple.h
  53. 3 0
      panda/src/pipeline/config_pipeline.cxx
  54. 9 10
      panda/src/pipeline/contextSwitch_longjmp_src.c
  55. 14 15
      panda/src/pipeline/contextSwitch_posix_src.c
  56. 6 7
      panda/src/pipeline/contextSwitch_ucontext_src.c
  57. 9 10
      panda/src/pipeline/contextSwitch_windows_src.c
  58. 3 0
      panda/src/pipeline/cycleData.h
  59. 25 13
      panda/src/pipeline/cycleDataLockedReader.I
  60. 37 14
      panda/src/pipeline/cycleDataLockedStageReader.I
  61. 40 17
      panda/src/pipeline/cycleDataStageWriter.I
  62. 1 1
      panda/src/pipeline/pythonThread.cxx
  63. 0 8
      panda/src/pipeline/threadSimpleImpl.I
  64. 11 3
      panda/src/pipeline/threadSimpleImpl.cxx
  65. 1 1
      panda/src/pipeline/threadSimpleImpl.h
  66. 5 13
      panda/src/pipeline/threadSimpleManager.cxx
  67. 1 1
      panda/src/text/textNode.cxx
  68. 5 5
      panda/src/wgldisplay/wglGraphicsStateGuardian.cxx
  69. 19 3
      panda/src/windisplay/winGraphicsWindow.cxx
  70. 2 0
      pandatool/src/eggcharbase/eggBackPointer.cxx
  71. 1 0
      pandatool/src/eggcharbase/eggCharacterDb.h
  72. 2 0
      pandatool/src/eggcharbase/eggJointData.cxx
  73. 2 1
      pandatool/src/eggcharbase/eggJointNodePointer.cxx
  74. 2 0
      pandatool/src/eggcharbase/eggMatrixTablePointer.cxx
  75. 1 0
      pandatool/src/palettizer/paletteGroup.cxx
  76. 0 55
      pandatool/src/softegg/config_softegg.cxx
  77. 0 28
      pandatool/src/softegg/config_softegg.h
  78. 0 4751
      pandatool/src/softegg/soft2Egg.c
  79. 0 44
      pandatool/src/softegg/softEggGroupUserData.I
  80. 0 16
      pandatool/src/softegg/softEggGroupUserData.cxx
  81. 0 53
      pandatool/src/softegg/softEggGroupUserData.h
  82. 0 1310
      pandatool/src/softegg/softNodeDesc.cxx
  83. 0 159
      pandatool/src/softegg/softNodeDesc.h
  84. 0 561
      pandatool/src/softegg/softNodeTree.cxx
  85. 0 78
      pandatool/src/softegg/softNodeTree.h
  86. 0 2122
      pandatool/src/softegg/softToEggConverter.cxx
  87. 0 179
      pandatool/src/softegg/softToEggConverter.h
  88. 0 588
      pandatool/src/softprogs/softCVS.cxx
  89. 0 70
      pandatool/src/softprogs/softCVS.h
  90. 0 291
      pandatool/src/softprogs/softFilename.cxx
  91. 0 73
      pandatool/src/softprogs/softFilename.h
  92. 1 0
      pandatool/src/xfileegg/xFileMaterial.cxx
  93. 2 0
      pandatool/src/xfileegg/xFileMesh.cxx
  94. 2 0
      pandatool/src/xfileegg/xFileMesh.h
  95. 1 0
      pandatool/src/xfileegg/xFileToEggConverter.cxx
  96. 25 12
      tests/display/test_glsl_shader.py
  97. 8 1
      tests/event/test_futures.py
  98. 7 0
      tests/text/test_textnode.py

+ 4 - 1
direct/src/interval/FunctionInterval.py

@@ -77,7 +77,10 @@ class FunctionInterval(Interval.Interval):
 
     @staticmethod
     def makeUniqueName(func, suffix = ''):
-        name = 'Func-%s-%d' % (getattr(func, '__name__', str(func)), FunctionInterval.functionIntervalNum)
+        func_name = getattr(func, '__name__', None)
+        if func_name is None:
+            func_name = str(func)
+        name = 'Func-%s-%d' % (func_name, FunctionInterval.functionIntervalNum)
         FunctionInterval.functionIntervalNum += 1
         if suffix:
             name = '%s-%s' % (name, str(suffix))

+ 0 - 20
doc/INSTALLING-PLUGINS.TXT

@@ -1,20 +0,0 @@
-HOW TO INSTALL MAX PANDA PLUGINS.
-
-Step 1. Install the visual studio 2008 runtime by
-running "vcredist_x86-sp1.exe" as administrator.
-As a convenience, this installer is included with panda.
-
-Step 2. Make sure that there is only one copy of panda
-in your system PATH.  If you only have one copy of panda
-installed, you can skip this step.
-
-Step 3. Copy the relevant DLLs for your version
-of max from the panda plugins directory to the
-max plugins directory.  For instance, if you are 
-using Max 9, copy maxegg9.dlo and maxeggimport9.dlo
-
-HOW TO INSTALL MAYA PANDA PLUGINS.
-
-(To be written)
-
-

+ 0 - 183
doc/InstallerNotes

@@ -1,183 +0,0 @@
-------------------------  RELEASE 1.0.0  ---------------------------------
-
-	* We now have working exporters for Max5, Max6, Max7, Maya5, Maya6
-
-	* The Max exporter is dramatically improved:
-
-	  - it now includes support for character studio.
-	  - the polygon winding bug has been fixed.
-
-	* Panda no longer requires any registry keys or environment
-	variables. This means it is now possible to:
-
-	     - run panda directly from a compact disc
-	     - install multiple copies of panda on a single machine
-	     - install panda by copying the tree from another computer
-
-        Note that the installer does add the panda 'bin' directory to
-	your PATH, and it does store an uninstall key in the registry,
-	but neither of these is needed for panda to function.
-
-	* The 'makepanda' build system is now capable of building
-	prepackaged games for Windows.  These prepackaged games are simply
-	copies of panda with the game code included, some of the
-	unnecessary stuff stripped out, and some changes to the start
-	menu.  See "Airblade - Installer" on the panda downloads page
-	for an example.
-
-	* All of the sample programs have been tested.  The ones that didn't
-	work have been removed, the ones that do work have been (lightly)
-	documented.
-
-	* This is the first release to include not just a binary installer
-	for windows, but:
-
-	    - a binary installer (RPM) for Fedora 2
-	    - a binary installer (RPM) for Fedora 3
-	    - a binary installer (RPM) for Redhat 9
-	    - a binary installer for windows, as always
-	    - a source tar-ball for linux
-	    - a source zip-file for windows
-
-------------------------  RELEASE 2004-12-13  ---------------------------------
-
-	* Basic server-client networking support is back in Panda3D. There is a
-	networking sample in the samples directory. This uses the Panda3d
-	distributed object system.The README file will explain how to run this.
-	Documentation of this if forthcoming.
-
-	* Panda3d now reduces the number of environment variables such that only 2
-	are needed now - PRC_PATH and PLAYER.
-
-	* GraphicsChannel and GraphicsLayer class have been removed from the
-	panda/src/display directory. Most Panda applications won't need to be
-	changed, since most applications simply use ShowBase.py (which has been
-	adjustedappropriately) to open a window and do the initial setup.  For
-	those rare applications where you need to create your own DisplayRegions,
-	the makeDisplayRegion() interface has been moved from GraphicsLayer to
-	GraphicsWindow (actually, to GraphicsOutput, which is the base class of
-	GraphicsWindow).  You can modify your application to call
-	base.win.makeDisplayRegion() accordingly.  If you have something like
-	displayRegion.getLayer(), replace it with displayRegion.getWindow()
-	instead.
-
-	* Effective with the current version of Panda, the way that HPR angles are
-	calculated will be changing. The change will make a difference to existing
-	code or databases that store a hard-coded rotation as a HPR, but only when
-	R is involved, or both H and P are involved together.  That is to say more
-	precisely, HPR angles with (R != 0 || (H != 0 && P != 0)) now represent a
-	different rotation than they used to. If you find some legacy code that no
-	longer works correctly (e.g. it introduces crazy rotations), try putting
-	the following in your Config.prc file:
-
-		  temp-hpr-fix 0
-
-	To turn off the correct behavior and return to the old, broken behavior.
-	Note that a longer-term solution will be to represent the HPR angles
-	correctly in all legacy code.  The function oldToNewHpr() is provided to
-	aid this transition.
-
-	* PandaNode definition has been changed to support setting an
-	into_collide_mask for any arbitrary node, in particular for any GeomNode.
-	It used to be that only CollisionNodes had an into_collide_mask.  This
-	change obviates the need for CollisionNode::set_collide_geom(), which is
-	now a deprecated interface and will be removed at some point in the future.
-
-	Details:
-	There's now a NodePath::set_collide_mask() and
-	NodePath::get_collide_mask(), which operate on all CollisionNodes and
-	GeomNodes at and below the current node. By default, set_collide_mask()
-	will replace the entire collide mask, but you may also specify (via a
-	second parameter) the subset of bits that are to be changed; other bits
-	will be left alone.  You can also specify a particular type of node to
-	modify via a third parameter, e.g. you can adjust the masks for GeomNodes
-	or CollisionNodes only.
-
-	The NodePath set_collide_mask() interface changes the into_collide_mask.
-	Those familiar with the collision system will recall that a CollisionNode
-	(but only a CollisionNode) also has a from_collide_mask.  The
-	from_collide_mask of the active mover is compared with the into_collide_mask
-	of each object in the world; a collision is only possible if there are some
-	bits in common.
-
-	It used to be that only other CollisionNodes had an into_collide_mask.  A
-	mover would only test for collisions with CollisionNodes that matched its
-	collide_mask. If you wanted to make your mover detect collisions with
-	visible geometry which had no into_collide_mask, you had to call
-	set_collide_geom(1). This allowed the mover to detect collisions with *all*
-	visible geometry; it was either an all-or-none thing.
-
-	Now that GeomNodes also have an into_collide_mask, there's no longer a need
-	for set_collide_geom().  A mover will detect collisions with any
-	CollisionNodes or GeomNodes that match its collide_mask.  This means, for
-	the purposes of collision detection, you can use CollisionNodes and
-	GeomNodes pretty much interchangeably; simply set the appropriate bits on
-	the objects you want to collide with, regardless of whether they are
-	invisible collision solids or visible geometry.
-
-	(This should not be taken as a license to avoid using CollisionNodes
-	altogether. The intersection computation with visible geometry is still
-	less efficient than the same computation with collision solids. And visible
-	geometry tends to be many times more complex than is strictly necessary for
-	collisions.)
-
-	There's one more detail: every GeomNode, by default, has one bit set on in
-	its collide_mask, unless it is explicitly turned off.  This bit is
-	GeomNode::get_default_collide_mask().  This bit is provided for the
-	convenience of programmers who still want the old behavior of
-	set_collide_geom(): it allows you to easily create a CollisionNode that
-	will collide with all visible geometry in the world.
-
-	Along the same lines, there's also CollisionNode::get_default_collide_mask(),
-	which is 0x000fffff.  This is the default mask that is created for a new
-	CollisionNode (and it does not include the bit reserved for GeomNodes, 
-	above). Previously, a new CollisionNode would have all bits on by default.
-
-
-
-------------------------  RELEASE 2004-11-11  -----------------------------------
-
-	* Multiple mice can now be used with Panda3D. showbase has a list called
-	pointerWatcherNodes. The first mouse on this list is the system mouse. The
-	getMouseX() and getMouseY() will return coordinates relative to the
-	application window. The rest of the mice on the list will give raw mouse
-	positions and will change when they are moved on the screen.
-
-	In addition there are new events for mouse buttons. Each mouse will be have
-	a corresponding event. mouse1 will send mousedev1-mouse1, mousedev1-mouse2
-	and mousedev1-mouse3 events. mouse2 and any other mouse attached
-	will send similar events mousedev2-mouse1 etc.
-
-	The old mouse buttons work too. mouse1, mouse2, mouse3 events will be
-	triggered if that button is pressed on any mouse
-
-------------------------  RELEASE 2004-10-13  -----------------------------------
-
-General
-
-	* Release notes: Each release will now have an entry associated with
-	it in this document. This will be updated in reverse-chronological order.
-
-Panda3D
-	* Distributed with this release is a working version of the SceneEditor
-	created in Spring 2004 at the ETC. Documentation will be forthcoming on the
-	website. This can be found in <InstallPath>/SceneEditor
-
-	* The latest version of FMOD is distributed with this release. The latest
-	version is 3.73.
-
-	* AudioSound object now allows more types of sound. These include wma and 
-	ogg vorbis formats. This is valid when using the fmod sound system. Midi, 
-	Mod, s3m, it, xm and such sequencer type file formats are not supported. 
-	Exception - Midi files can be played. This is not fully implemented.
-
-	* A bug in SoundInterval is fixed. SoundInterval looping would incorrectly 
-	add a minimum of 1.5 seconds to the sound. This has been fixed. Sound 
-	looping problems in general should be fixed. Midi's still don't support 
-	looping through the AudioSound object. They should loop through 
-	SoundIntervals though.
-
-	* Cg support has been added to Panda3D. Documentation for this is 
-	forthcoming.
-
-

+ 8 - 0
dtool/src/dtoolbase/dtoolbase.cxx

@@ -62,4 +62,12 @@ default_thread_consider_yield() {
 void (*global_thread_yield)() = default_thread_yield;
 void (*global_thread_consider_yield)() = default_thread_consider_yield;
 
+#ifdef HAVE_PYTHON
+static PyThreadState *
+default_thread_state_swap(PyThreadState *state) {
+  return nullptr;
+}
+PyThreadState *(*global_thread_state_swap)(PyThreadState *tstate) = default_thread_state_swap;
+#endif  // HAVE_PYTHON
+
 #endif  // HAVE_THREADS && SIMPLE_THREADS

+ 2 - 0
dtool/src/dtoolbase/dtoolbase.h

@@ -63,8 +63,10 @@
 /* Windows likes to define min() and max() macros, which will conflict with
    std::min() and std::max() respectively, unless we do this: */
 #ifdef WIN32
+#ifndef NOMINMAX
 #define NOMINMAX
 #endif
+#endif
 
 #ifndef __has_builtin
 #define __has_builtin(x) 0

+ 9 - 0
dtool/src/dtoolbase/dtoolbase_cc.h

@@ -233,6 +233,15 @@ INLINE void thread_consider_yield() {
   (*global_thread_consider_yield)();
 }
 
+#ifdef HAVE_PYTHON
+typedef struct _ts PyThreadState;
+extern EXPCL_DTOOL_DTOOLBASE PyThreadState *(*global_thread_state_swap)(PyThreadState *tstate);
+
+INLINE PyThreadState *thread_state_swap(PyThreadState *tstate) {
+  return (*global_thread_state_swap)(tstate);
+}
+#endif  // HAVE_PYTHON
+
 #else
 
 INLINE void thread_yield() {

+ 10 - 10
dtool/src/dtoolutil/textEncoder.I

@@ -220,7 +220,7 @@ get_unicode_char(size_t index) const {
  * according to set_encoding().
  */
 INLINE void TextEncoder::
-set_unicode_char(size_t index, int character) {
+set_unicode_char(size_t index, char32_t character) {
   get_wtext();
   if (index < _wtext.length()) {
     _wtext[index] = character;
@@ -283,7 +283,7 @@ reencode_text(const std::string &text, TextEncoder::Encoding from,
  * otherwise.  This is akin to ctype's isalpha(), extended to Unicode.
  */
 INLINE bool TextEncoder::
-unicode_isalpha(int character) {
+unicode_isalpha(char32_t character) {
   const UnicodeLatinMap::Entry *entry = UnicodeLatinMap::look_up(character);
   if (entry == nullptr) {
     return false;
@@ -297,7 +297,7 @@ unicode_isalpha(int character) {
  * otherwise.  This is akin to ctype's isdigit(), extended to Unicode.
  */
 INLINE bool TextEncoder::
-unicode_isdigit(int character) {
+unicode_isdigit(char32_t character) {
   const UnicodeLatinMap::Entry *entry = UnicodeLatinMap::look_up(character);
   if (entry == nullptr) {
     // The digits aren't actually listed in the map.
@@ -312,11 +312,11 @@ unicode_isdigit(int character) {
  * otherwise.  This is akin to ctype's ispunct(), extended to Unicode.
  */
 INLINE bool TextEncoder::
-unicode_ispunct(int character) {
+unicode_ispunct(char32_t character) {
   const UnicodeLatinMap::Entry *entry = UnicodeLatinMap::look_up(character);
   if (entry == nullptr) {
     // Some punctuation marks aren't listed in the map.
-    return (character >= 0 && character < 128 && ispunct(character));
+    return (character < 128 && ispunct(character));
   }
   return entry->_char_type == UnicodeLatinMap::CT_punct;
 }
@@ -326,7 +326,7 @@ unicode_ispunct(int character) {
  * otherwise.  This is akin to ctype's isupper(), extended to Unicode.
  */
 INLINE bool TextEncoder::
-unicode_isupper(int character) {
+unicode_isupper(char32_t character) {
   const UnicodeLatinMap::Entry *entry = UnicodeLatinMap::look_up(character);
   if (entry == nullptr) {
     return false;
@@ -339,7 +339,7 @@ unicode_isupper(int character) {
  * otherwise.  This is akin to ctype's isspace(), extended to Unicode.
  */
 INLINE bool TextEncoder::
-unicode_isspace(int character) {
+unicode_isspace(char32_t character) {
   switch (character) {
   case ' ':
   case '\t':
@@ -356,7 +356,7 @@ unicode_isspace(int character) {
  * otherwise.  This is akin to ctype's islower(), extended to Unicode.
  */
 INLINE bool TextEncoder::
-unicode_islower(int character) {
+unicode_islower(char32_t character) {
   const UnicodeLatinMap::Entry *entry = UnicodeLatinMap::look_up(character);
   if (entry == nullptr) {
     return false;
@@ -369,7 +369,7 @@ unicode_islower(int character) {
  * akin to ctype's toupper(), extended to Unicode.
  */
 INLINE int TextEncoder::
-unicode_toupper(int character) {
+unicode_toupper(char32_t character) {
   const UnicodeLatinMap::Entry *entry = UnicodeLatinMap::look_up(character);
   if (entry == nullptr) {
     return character;
@@ -382,7 +382,7 @@ unicode_toupper(int character) {
  * akin to ctype's tolower(), extended to Unicode.
  */
 INLINE int TextEncoder::
-unicode_tolower(int character) {
+unicode_tolower(char32_t character) {
   const UnicodeLatinMap::Entry *entry = UnicodeLatinMap::look_up(character);
   if (entry == nullptr) {
     return character;

+ 10 - 10
dtool/src/dtoolutil/textEncoder.h

@@ -23,7 +23,7 @@ class StringDecoder;
 
 /**
  * This class can be used to convert text between multiple representations,
- * e.g.  utf-8 to Unicode.  You may use it as a static class object, passing
+ * e.g.  UTF-8 to UTF-16.  You may use it as a static class object, passing
  * the encoding each time, or you may create an instance and use that object,
  * which will record the current encoding and retain the current string.
  *
@@ -78,21 +78,21 @@ PUBLISHED:
   INLINE void append_unicode_char(char32_t character);
   INLINE size_t get_num_chars() const;
   INLINE int get_unicode_char(size_t index) const;
-  INLINE void set_unicode_char(size_t index, int character);
+  INLINE void set_unicode_char(size_t index, char32_t character);
   INLINE std::string get_encoded_char(size_t index) const;
   INLINE std::string get_encoded_char(size_t index, Encoding encoding) const;
   INLINE std::string get_text_as_ascii() const;
 
   INLINE static std::string reencode_text(const std::string &text, Encoding from, Encoding to);
 
-  INLINE static bool unicode_isalpha(int character);
-  INLINE static bool unicode_isdigit(int character);
-  INLINE static bool unicode_ispunct(int character);
-  INLINE static bool unicode_islower(int character);
-  INLINE static bool unicode_isupper(int character);
-  INLINE static bool unicode_isspace(int character);
-  INLINE static int unicode_toupper(int character);
-  INLINE static int unicode_tolower(int character);
+  INLINE static bool unicode_isalpha(char32_t character);
+  INLINE static bool unicode_isdigit(char32_t character);
+  INLINE static bool unicode_ispunct(char32_t character);
+  INLINE static bool unicode_islower(char32_t character);
+  INLINE static bool unicode_isupper(char32_t character);
+  INLINE static bool unicode_isspace(char32_t character);
+  INLINE static int unicode_toupper(char32_t character);
+  INLINE static int unicode_tolower(char32_t character);
 
   INLINE static std::string upper(const std::string &source);
   INLINE static std::string upper(const std::string &source, Encoding encoding);

+ 6 - 1
dtool/src/dtoolutil/textEncoder_ext.cxx

@@ -94,7 +94,12 @@ append_text(PyObject *text) {
 #if PY_VERSION_HEX >= 0x03030000
     Py_ssize_t len;
     const char *str = PyUnicode_AsUTF8AndSize(text, &len);
-    _this->append_text(std::string(str, len));
+    std::string text_str(str, len);
+    if (_this->get_encoding() == TextEncoder::E_utf8) {
+      _this->append_text(text_str);
+    } else {
+      _this->append_wtext(TextEncoder::decode_text(text_str, TextEncoder::E_utf8));
+    }
 #else
     Py_ssize_t len = PyUnicode_GET_SIZE(text);
     wchar_t *str = (wchar_t *)alloca(sizeof(wchar_t) * (len + 1));

+ 1 - 1
dtool/src/dtoolutil/unicodeLatinMap.cxx

@@ -1378,7 +1378,7 @@ static const wchar_t combining_accent_map[] = {
  * Returns the Entry associated with the indicated character, if there is one.
  */
 const UnicodeLatinMap::Entry *UnicodeLatinMap::
-look_up(wchar_t character) {
+look_up(char32_t character) {
   if (!_initialized) {
     init();
   }

+ 5 - 5
dtool/src/dtoolutil/unicodeLatinMap.h

@@ -112,17 +112,17 @@ public:
 
   class Entry {
   public:
-    wchar_t _character;
+    char32_t _character;
     CharType _char_type;
     char _ascii_equiv;
     char _ascii_additional;
-    wchar_t _tolower_character;
-    wchar_t _toupper_character;
+    char32_t _tolower_character;
+    char32_t _toupper_character;
     AccentType _accent_type;
     int _additional_flags;
   };
 
-  static const Entry *look_up(wchar_t character);
+  static const Entry *look_up(char32_t character);
 
   static wchar_t get_combining_accent(AccentType accent);
 
@@ -130,7 +130,7 @@ private:
   static void init();
   static bool _initialized;
 
-  typedef phash_map<wchar_t, const Entry *, integer_hash<wchar_t> > ByCharacter;
+  typedef phash_map<char32_t, const Entry *, integer_hash<char32_t> > ByCharacter;
   static ByCharacter *_by_character;
   enum { max_direct_chars = 256 };
   static const Entry *_direct_chars[max_direct_chars];

+ 9 - 1
dtool/src/interrogatedb/py_panda.cxx

@@ -722,7 +722,10 @@ PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename) {
 
     // Extract the __file__ attribute, if present.
     Filename main_dir;
-    PyObject *file_attr = PyObject_GetAttrString(main_module, "__file__");
+    PyObject *file_attr = nullptr;
+    if (main_module != nullptr) {
+      file_attr = PyObject_GetAttrString(main_module, "__file__");
+    }
     if (file_attr == nullptr) {
       // Must be running in the interactive interpreter.  Use the CWD.
       main_dir = ExecutionEnvironment::get_cwd();
@@ -752,6 +755,11 @@ PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename) {
     ExecutionEnvironment::shadow_environment_variable("MAIN_DIR", main_dir.to_os_specific());
     PyErr_Clear();
     initialized_main_dir = true;
+
+    // Also, while we are at it, initialize the thread swap hook.
+#if defined(HAVE_THREADS) && defined(SIMPLE_THREADS)
+    global_thread_state_swap = PyThreadState_Swap;
+#endif
   }
 
   PyModule_AddIntConstant(module, "Dtool_PyNativeInterface", 1);

+ 1 - 1
dtool/src/parser-inc/Python.h

@@ -28,7 +28,7 @@ typedef _typeobject PyTypeObject;
 typedef struct {} PyStringObject;
 typedef struct {} PyUnicodeObject;
 
-class PyThreadState;
+typedef struct _ts PyThreadState;
 typedef int Py_ssize_t;
 typedef struct bufferinfo Py_buffer;
 

+ 0 - 20
dtool/src/prc/notifyCategory.I

@@ -82,26 +82,6 @@ is_debug() const {
   // Instruct the compiler to optimize for the usual case.
   return UNLIKELY(is_on(NS_debug));
 }
-#else
-/**
- * When NOTIFY_DEBUG is not defined, the categories are never set to "spam" or
- * "debug" severities, and these methods are redefined to be static to make it
- * more obvious to the compiler.
- */
-constexpr bool NotifyCategory::
-is_spam() {
-  return false;
-}
-
-/**
- * When NOTIFY_DEBUG is not defined, the categories are never set to "spam" or
- * "debug" severities, and these methods are redefined to be static to make it
- * more obvious to the compiler.
- */
-constexpr bool NotifyCategory::
-is_debug() {
-  return false;
-}
 #endif
 
 /**

+ 2 - 2
dtool/src/prc/notifyCategory.h

@@ -55,8 +55,8 @@ PUBLISHED:
   INLINE bool is_spam() const;
   INLINE bool is_debug() const;
 #else
-  constexpr static bool is_spam();
-  constexpr static bool is_debug();
+  constexpr static bool is_spam() { return false; }
+  constexpr static bool is_debug() { return false; }
 #endif
   INLINE bool is_info() const;
   INLINE bool is_warning() const;

+ 0 - 12
dtool/src/prc/notifyCategoryProxy.I

@@ -72,12 +72,6 @@ is_spam() {
   // Instruct the compiler to optimize for the usual case.
   return UNLIKELY(get_unsafe_ptr()->is_spam());
 }
-#else
-template<class GetCategory>
-constexpr bool NotifyCategoryProxy<GetCategory>::
-is_spam() {
-  return false;
-}
 #endif
 
 /**
@@ -90,12 +84,6 @@ is_debug() {
   // Instruct the compiler to optimize for the usual case.
   return UNLIKELY(get_unsafe_ptr()->is_debug());
 }
-#else
-template<class GetCategory>
-constexpr bool NotifyCategoryProxy<GetCategory>::
-is_debug() {
-  return false;
-}
 #endif
 
 /**

+ 2 - 2
dtool/src/prc/notifyCategoryProxy.h

@@ -75,8 +75,8 @@ public:
   INLINE bool is_spam();
   INLINE bool is_debug();
 #else
-  constexpr static bool is_spam();
-  constexpr static bool is_debug();
+  constexpr static bool is_spam() { return false; }
+  constexpr static bool is_debug() { return false; }
 #endif
   INLINE bool is_info();
   INLINE bool is_warning();

+ 36 - 46
makepanda/makepanda.py

@@ -680,6 +680,9 @@ if (COMPILER == "MSVC"):
         IncDirectory("FCOLLADA", GetThirdpartyDir() + "fcollada/include/FCollada")
     if (PkgSkip("ASSIMP")==0):
         LibName("ASSIMP", GetThirdpartyDir() + "assimp/lib/assimp.lib")
+        path = GetThirdpartyDir() + "assimp/lib/IrrXML.lib"
+        if os.path.isfile(path):
+            LibName("ASSIMP", GetThirdpartyDir() + "assimp/lib/IrrXML.lib")
         IncDirectory("ASSIMP", GetThirdpartyDir() + "assimp/include/assimp")
     if (PkgSkip("SQUISH")==0):
         if GetOptimize() <= 2:
@@ -946,8 +949,6 @@ if (COMPILER=="GCC"):
 
     if GetTarget() == 'darwin':
         LibName("ALWAYS", "-framework AppKit")
-        if (PkgSkip("OPENCV")==0):
-            LibName("OPENCV", "-framework QuickTime")
         LibName("AGL", "-framework AGL")
         LibName("CARBON", "-framework Carbon")
         LibName("COCOA", "-framework Cocoa")
@@ -1334,9 +1335,10 @@ def CompileCxx(obj,src,opts):
                     # Work around Apple compiler bug.
                     cmd += " -U__EXCEPTIONS"
 
-            if 'RTTI' not in opts:
+            target = GetTarget()
+            if 'RTTI' not in opts and target != "darwin":
                 # We always disable RTTI on Android for memory usage reasons.
-                if optlevel >= 4 or GetTarget() == "android":
+                if optlevel >= 4 or target == "android":
                     cmd += " -fno-rtti"
 
         if ('SSE2' in opts or not PkgSkip("SSE2")) and not arch.startswith("arm") and arch != 'aarch64':
@@ -1596,6 +1598,8 @@ def CompileLib(lib, obj, opts):
         else:
             cmd = GetAR() + ' cru ' + BracketNameWithQuotes(lib)
         for x in obj:
+            if GetLinkAllStatic() and x.endswith('.a'):
+                continue
             cmd += ' ' + BracketNameWithQuotes(x)
         oscmd(cmd)
 
@@ -3159,10 +3163,10 @@ CopyAllHeaders('panda/src/movies')
 CopyAllHeaders('panda/src/pgraphnodes')
 CopyAllHeaders('panda/src/pgraph')
 CopyAllHeaders('panda/src/cull')
+CopyAllHeaders('panda/src/display')
 CopyAllHeaders('panda/src/chan')
 CopyAllHeaders('panda/src/char')
 CopyAllHeaders('panda/src/dgraph')
-CopyAllHeaders('panda/src/display')
 CopyAllHeaders('panda/src/device')
 CopyAllHeaders('panda/src/pnmtext')
 CopyAllHeaders('panda/src/text')
@@ -3295,7 +3299,6 @@ if (PkgSkip("PANDATOOL")==0):
     CopyAllHeaders('pandatool/src/ptloader')
     CopyAllHeaders('pandatool/src/miscprogs')
     CopyAllHeaders('pandatool/src/pstatserver')
-    CopyAllHeaders('pandatool/src/softprogs')
     CopyAllHeaders('pandatool/src/text-stats')
     CopyAllHeaders('pandatool/src/vrmlprogs')
     CopyAllHeaders('pandatool/src/win-stats')
@@ -3816,7 +3819,7 @@ if (not RUNTIME):
 if (not RUNTIME):
   OPTS=['DIR:panda/src/gobj', 'BUILDING:PANDA',  'NVIDIACG', 'ZLIB', 'SQUISH']
   TargetAdd('p3gobj_composite1.obj', opts=OPTS, input='p3gobj_composite1.cxx')
-  TargetAdd('p3gobj_composite2.obj', opts=OPTS, input='p3gobj_composite2.cxx')
+  TargetAdd('p3gobj_composite2.obj', opts=OPTS+['BIGOBJ'], input='p3gobj_composite2.cxx')
 
   OPTS=['DIR:panda/src/gobj', 'NVIDIACG', 'ZLIB', 'SQUISH', 'PYTHON']
   IGATEFILES=GetDirectoryContents('panda/src/gobj', ["*.h", "*_composite*.cxx"])
@@ -3875,6 +3878,31 @@ if (not RUNTIME):
   TargetAdd('libp3cull.in', opts=['IMOD:panda3d.core', 'ILIB:libp3cull', 'SRCDIR:panda/src/cull'])
   TargetAdd('libp3cull_igate.obj', input='libp3cull.in', opts=["DEPENDENCYONLY"])
 
+#
+# DIRECTORY: panda/src/display/
+#
+
+if (not RUNTIME):
+  OPTS=['DIR:panda/src/display', 'BUILDING:PANDA']
+  TargetAdd('p3display_graphicsStateGuardian.obj', opts=OPTS, input='graphicsStateGuardian.cxx')
+  TargetAdd('p3display_composite1.obj', opts=OPTS, input='p3display_composite1.cxx')
+  TargetAdd('p3display_composite2.obj', opts=OPTS, input='p3display_composite2.cxx')
+
+  OPTS=['DIR:panda/src/display', 'PYTHON']
+  IGATEFILES=GetDirectoryContents('panda/src/display', ["*.h", "*_composite*.cxx"])
+  IGATEFILES.remove("renderBuffer.h")
+  TargetAdd('libp3display.in', opts=OPTS, input=IGATEFILES)
+  TargetAdd('libp3display.in', opts=['IMOD:panda3d.core', 'ILIB:libp3display', 'SRCDIR:panda/src/display'])
+  TargetAdd('libp3display_igate.obj', input='libp3display.in', opts=["DEPENDENCYONLY"])
+  TargetAdd('p3display_graphicsStateGuardian_ext.obj', opts=OPTS, input='graphicsStateGuardian_ext.cxx')
+  TargetAdd('p3display_graphicsWindow_ext.obj', opts=OPTS, input='graphicsWindow_ext.cxx')
+  TargetAdd('p3display_pythonGraphicsWindowProc.obj', opts=OPTS, input='pythonGraphicsWindowProc.cxx')
+
+  if RTDIST and GetTarget() == 'darwin':
+    OPTS=['DIR:panda/src/display']
+    TargetAdd('subprocessWindowBuffer.obj', opts=OPTS, input='subprocessWindowBuffer.cxx')
+    TargetAdd('libp3subprocbuffer.ilb', input='subprocessWindowBuffer.obj')
+
 #
 # DIRECTORY: panda/src/chan/
 #
@@ -3922,30 +3950,6 @@ if (not RUNTIME):
   TargetAdd('libp3dgraph.in', opts=['IMOD:panda3d.core', 'ILIB:libp3dgraph', 'SRCDIR:panda/src/dgraph'])
   TargetAdd('libp3dgraph_igate.obj', input='libp3dgraph.in', opts=["DEPENDENCYONLY"])
 
-#
-# DIRECTORY: panda/src/display/
-#
-
-if (not RUNTIME):
-  OPTS=['DIR:panda/src/display', 'BUILDING:PANDA']
-  TargetAdd('p3display_composite1.obj', opts=OPTS, input='p3display_composite1.cxx')
-  TargetAdd('p3display_composite2.obj', opts=OPTS, input='p3display_composite2.cxx')
-
-  OPTS=['DIR:panda/src/display', 'PYTHON']
-  IGATEFILES=GetDirectoryContents('panda/src/display', ["*.h", "*_composite*.cxx"])
-  IGATEFILES.remove("renderBuffer.h")
-  TargetAdd('libp3display.in', opts=OPTS, input=IGATEFILES)
-  TargetAdd('libp3display.in', opts=['IMOD:panda3d.core', 'ILIB:libp3display', 'SRCDIR:panda/src/display'])
-  TargetAdd('libp3display_igate.obj', input='libp3display.in', opts=["DEPENDENCYONLY"])
-  TargetAdd('p3display_graphicsStateGuardian_ext.obj', opts=OPTS, input='graphicsStateGuardian_ext.cxx')
-  TargetAdd('p3display_graphicsWindow_ext.obj', opts=OPTS, input='graphicsWindow_ext.cxx')
-  TargetAdd('p3display_pythonGraphicsWindowProc.obj', opts=OPTS, input='pythonGraphicsWindowProc.cxx')
-
-  if RTDIST and GetTarget() == 'darwin':
-    OPTS=['DIR:panda/src/display']
-    TargetAdd('subprocessWindowBuffer.obj', opts=OPTS, input='subprocessWindowBuffer.cxx')
-    TargetAdd('libp3subprocbuffer.ilb', input='subprocessWindowBuffer.obj')
-
 #
 # DIRECTORY: panda/src/device/
 #
@@ -4167,6 +4171,7 @@ if (not RUNTIME):
   TargetAdd('libpanda.dll', input='p3device_composite2.obj')
   TargetAdd('libpanda.dll', input='p3dgraph_composite1.obj')
   TargetAdd('libpanda.dll', input='p3dgraph_composite2.obj')
+  TargetAdd('libpanda.dll', input='p3display_graphicsStateGuardian.obj')
   TargetAdd('libpanda.dll', input='p3display_composite1.obj')
   TargetAdd('libpanda.dll', input='p3display_composite2.obj')
   TargetAdd('libpanda.dll', input='p3pipeline_composite1.obj')
@@ -6346,21 +6351,6 @@ if (PkgSkip("PANDATOOL")==0):
     TargetAdd('p3pstatserver_composite1.obj', opts=OPTS, input='p3pstatserver_composite1.cxx')
     TargetAdd('libp3pstatserver.lib', input='p3pstatserver_composite1.obj')
 
-#
-# DIRECTORY: pandatool/src/softprogs/
-#
-
-if (PkgSkip("PANDATOOL")==0):
-    OPTS=['DIR:pandatool/src/softprogs', 'OPENSSL']
-    TargetAdd('softcvs_softCVS.obj', opts=OPTS, input='softCVS.cxx')
-    TargetAdd('softcvs_softFilename.obj', opts=OPTS, input='softFilename.cxx')
-    TargetAdd('softcvs.exe', input='softcvs_softCVS.obj')
-    TargetAdd('softcvs.exe', input='softcvs_softFilename.obj')
-    TargetAdd('softcvs.exe', input='libp3progbase.lib')
-    TargetAdd('softcvs.exe', input='libp3pandatoolbase.lib')
-    TargetAdd('softcvs.exe', input=COMMON_PANDA_LIBS)
-    TargetAdd('softcvs.exe', opts=['ADVAPI'])
-
 #
 # DIRECTORY: pandatool/src/text-stats/
 #

+ 0 - 20
makepanda/makepanda.vcproj

@@ -4770,12 +4770,6 @@
 				<File RelativePath="..\pandatool\src\ptloader\config_ptloader.h"></File>
 				<File RelativePath="..\pandatool\src\ptloader\loaderFileTypePandatool.h"></File>
 			</Filter>
-			<Filter Name="softprogs">
-				<File RelativePath="..\pandatool\src\softprogs\softCVS.cxx"></File>
-				<File RelativePath="..\pandatool\src\softprogs\softFilename.h"></File>
-				<File RelativePath="..\pandatool\src\softprogs\softCVS.h"></File>
-				<File RelativePath="..\pandatool\src\softprogs\softFilename.cxx"></File>
-			</Filter>
 			<Filter Name="imageprogs">
 				<File RelativePath="..\pandatool\src\imageprogs\imageTrans.h"></File>
 				<File RelativePath="..\pandatool\src\imageprogs\imageTransformColors.cxx"></File>
@@ -5305,20 +5299,6 @@
 				<File RelativePath="..\pandatool\src\lwo\lwoSurfaceBlockImage.h"></File>
 				<File RelativePath="..\pandatool\src\lwo\lwoSurfaceBlockCoordSys.cxx"></File>
 			</Filter>
-			<Filter Name="softegg">
-				<File RelativePath="..\pandatool\src\softegg\soft2Egg.c"></File>
-				<File RelativePath="..\pandatool\src\softegg\softNodeTree.cxx"></File>
-				<File RelativePath="..\pandatool\src\softegg\softNodeDesc.h"></File>
-				<File RelativePath="..\pandatool\src\softegg\softEggGroupUserData.cxx"></File>
-				<File RelativePath="..\pandatool\src\softegg\softEggGroupUserData.I"></File>
-				<File RelativePath="..\pandatool\src\softegg\config_softegg.cxx"></File>
-				<File RelativePath="..\pandatool\src\softegg\softToEggConverter.cxx"></File>
-				<File RelativePath="..\pandatool\src\softegg\softNodeTree.h"></File>
-				<File RelativePath="..\pandatool\src\softegg\config_softegg.h"></File>
-				<File RelativePath="..\pandatool\src\softegg\softNodeDesc.cxx"></File>
-				<File RelativePath="..\pandatool\src\softegg\softToEggConverter.h"></File>
-				<File RelativePath="..\pandatool\src\softegg\softEggGroupUserData.h"></File>
-			</Filter>
 			<Filter Name="xfileprogs">
 				<File RelativePath="..\pandatool\src\xfileprogs\eggToX.cxx"></File>
 				<File RelativePath="..\pandatool\src\xfileprogs\xFileTrans.cxx"></File>

+ 2 - 2
panda/src/chan/animControl.cxx

@@ -32,14 +32,14 @@ AnimControl(const std::string &name, PartBundle *part,
   Namable(name),
   _pending_lock(name),
   _pending_cvar(_pending_lock),
-  _bound_joints(BitArray::all_on())
+  _bound_joints(BitArray::all_on()),
+  _part(part)
 {
 #ifdef DO_MEMORY_USAGE
   MemoryUsage::update_type(this, get_class_type());
 #endif
 
   _pending = true;
-  _part = part;
   _anim = nullptr;
   _channel_index = -1;
   set_frame_rate(frame_rate);

+ 3 - 1
panda/src/chan/animControl.h

@@ -39,6 +39,8 @@ class EXPCL_PANDA_CHAN AnimControl : public TypedReferenceCount, public AnimInte
 public:
   AnimControl(const std::string &name, PartBundle *part,
               double frame_rate, int num_frames);
+  AnimControl(const AnimControl &copy) = delete;
+
   void setup_anim(PartBundle *part, AnimBundle *anim, int channel_index,
                   const BitArray &bound_joints);
   void set_bound_joints(const BitArray &bound_joints);
@@ -82,7 +84,7 @@ private:
   // This is a PT(PartGroup) instead of a PT(PartBundle), just because we
   // can't include partBundle.h for circular reasons.  But it actually keeps a
   // pointer to a PartBundle.
-  PT(PartGroup) _part;
+  const PT(PartGroup) _part;
   PT(AnimBundle) _anim;
   int _channel_index;
 

+ 7 - 0
panda/src/chan/partBundle.cxx

@@ -556,8 +556,15 @@ control_removed(AnimControl *control) {
     CDStageWriter cdata(_cycler, pipeline_stage);
     ChannelBlend::iterator cbi = cdata->_blend.find(control);
     if (cbi != cdata->_blend.end()) {
+      cdata->_net_blend -= cbi->second;
       cdata->_blend.erase(cbi);
       cdata->_anim_changed = true;
+
+      // We need to make sure that any _effective_channel pointers that point
+      // to this control are cleared.
+      if (pipeline_stage == 0) {
+        determine_effective_channels(cdata);
+      }
     }
   }
   CLOSE_ITERATE_ALL_STAGES(_cycler);

+ 1 - 1
panda/src/collide/collisionTraverser.cxx

@@ -1254,7 +1254,7 @@ compare_collider_to_geom(CollisionEntry &entry, const Geom *geom,
 
     if (geom->get_primitive_type() == Geom::PT_polygons) {
       Thread *current_thread = Thread::get_current_thread();
-      CPT(GeomVertexData) data = geom->get_vertex_data()->animate_vertices(true, current_thread);
+      CPT(GeomVertexData) data = geom->get_animated_vertex_data(true, current_thread);
       GeomVertexReader vertex(data, InternalName::get_vertex());
 
       int num_primitives = geom->get_num_primitives();

+ 5 - 5
panda/src/display/graphicsEngine.cxx

@@ -753,7 +753,7 @@ render_frame() {
         // frames, so we won't have to recompute it each frame.
         int num_drs = win->get_num_active_display_regions();
         for (int i = 0; i < num_drs; ++i) {
-          DisplayRegion *dr = win->get_active_display_region(i);
+          PT(DisplayRegion) dr = win->get_active_display_region(i);
           if (dr != nullptr) {
             NodePath camera_np = dr->get_camera(current_thread);
             if (!camera_np.is_empty()) {
@@ -1359,7 +1359,7 @@ is_scene_root(const PandaNode *node) {
     if (win->is_active() && win->get_gsg()->is_active()) {
       int num_display_regions = win->get_num_active_display_regions();
       for (int i = 0; i < num_display_regions; i++) {
-        DisplayRegion *dr = win->get_active_display_region(i);
+        PT(DisplayRegion) dr = win->get_active_display_region(i);
         if (dr != nullptr) {
           NodePath camera = dr->get_camera();
           if (camera.is_empty()) {
@@ -1435,7 +1435,7 @@ cull_and_draw_together(GraphicsEngine::Windows wlist,
 
         int num_display_regions = win->get_num_active_display_regions();
         for (int i = 0; i < num_display_regions; i++) {
-          DisplayRegion *dr = win->get_active_display_region(i);
+          PT(DisplayRegion) dr = win->get_active_display_region(i);
           if (dr != nullptr) {
             cull_and_draw_together(win, dr, current_thread);
           }
@@ -1539,7 +1539,7 @@ cull_to_bins(GraphicsEngine::Windows wlist, Thread *current_thread) {
       PStatTimer timer(win->get_cull_window_pcollector(), current_thread);
       int num_display_regions = win->get_num_active_display_regions();
       for (int i = 0; i < num_display_regions; ++i) {
-        DisplayRegion *dr = win->get_active_display_region(i);
+        PT(DisplayRegion) dr = win->get_active_display_region(i);
         if (dr != nullptr) {
           PT(SceneSetup) scene_setup;
           PT(CullResult) cull_result;
@@ -1659,7 +1659,7 @@ draw_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
           }
           int num_display_regions = win->get_num_active_display_regions();
           for (int i = 0; i < num_display_regions; ++i) {
-            DisplayRegion *dr = win->get_active_display_region(i);
+            PT(DisplayRegion) dr = win->get_active_display_region(i);
             if (dr != nullptr) {
               do_draw(win, gsg, dr, current_thread);
             }

+ 13 - 13
panda/src/display/graphicsOutput.cxx

@@ -697,9 +697,6 @@ void GraphicsOutput::
 remove_all_display_regions() {
   LightMutexHolder holder(_lock);
 
-  CDWriter cdata(_cycler, true);
-  cdata->_active_display_regions_stale = true;
-
   TotalDisplayRegions::iterator dri;
   for (dri = _total_display_regions.begin();
        dri != _total_display_regions.end();
@@ -713,6 +710,12 @@ remove_all_display_regions() {
   }
   _total_display_regions.clear();
   _total_display_regions.push_back(_overlay_display_region);
+
+  OPEN_ITERATE_ALL_STAGES(_cycler) {
+    CDStageWriter cdata(_cycler, pipeline_stage);
+    cdata->_active_display_regions_stale = true;
+  }
+  CLOSE_ITERATE_ALL_STAGES(_cycler);
 }
 
 /**
@@ -740,13 +743,8 @@ set_overlay_display_region(DisplayRegion *display_region) {
  */
 int GraphicsOutput::
 get_num_display_regions() const {
-  determine_display_regions();
-  int result;
-  {
-    LightMutexHolder holder(_lock);
-    result = _total_display_regions.size();
-  }
-  return result;
+  LightMutexHolder holder(_lock);
+  return _total_display_regions.size();
 }
 
 /**
@@ -1504,13 +1502,15 @@ do_remove_display_region(DisplayRegion *display_region) {
     find(_total_display_regions.begin(), _total_display_regions.end(), drp);
   if (dri != _total_display_regions.end()) {
     // Let's aggressively clean up the display region too.
-    CDWriter cdata(_cycler, true);
     display_region->cleanup();
     display_region->_window = nullptr;
     _total_display_regions.erase(dri);
 
-    cdata->_active_display_regions_stale = true;
-
+    OPEN_ITERATE_ALL_STAGES(_cycler) {
+      CDStageWriter cdata(_cycler, pipeline_stage);
+      cdata->_active_display_regions_stale = true;
+    }
+    CLOSE_ITERATE_ALL_STAGES(_cycler);
     return true;
   }
 

+ 1 - 0
panda/src/display/graphicsOutput.h

@@ -394,6 +394,7 @@ protected:
   typedef CycleDataLockedReader<CData> CDLockedReader;
   typedef CycleDataReader<CData> CDReader;
   typedef CycleDataWriter<CData> CDWriter;
+  typedef CycleDataStageWriter<CData> CDStageWriter;
 
 protected:
   int _creation_flags;

+ 14 - 28
panda/src/display/graphicsPipeSelection.cxx

@@ -18,7 +18,6 @@
 #include "load_dso.h"
 #include "config_display.h"
 #include "typeRegistry.h"
-#include "pset.h"
 #include "config_putil.h"
 
 #include <algorithm>
@@ -61,8 +60,8 @@ GraphicsPipeSelection() : _lock("GraphicsPipeSelection") {
 
   // Also get the set of modules named in the various aux-display Config
   // variables.  We'll want to know this when we call load_modules() later.
-  int num_aux = aux_display.get_num_unique_values();
-  for (int i = 0; i < num_aux; i++) {
+  size_t num_aux = aux_display.get_num_unique_values();
+  for (size_t i = 0; i < num_aux; ++i) {
     string name = aux_display.get_unique_value(i);
     if (name != _default_display_module) {
       _display_modules.push_back(name);
@@ -124,9 +123,7 @@ print_pipe_types() const {
 
   LightMutexHolder holder(_lock);
   nout << "Known pipe types:" << std::endl;
-  PipeTypes::const_iterator pi;
-  for (pi = _pipe_types.begin(); pi != _pipe_types.end(); ++pi) {
-    const PipeType &pipe_type = (*pi);
+  for (const PipeType &pipe_type : _pipe_types) {
     nout << "  " << pipe_type._type << "\n";
   }
   if (_display_modules.empty()) {
@@ -187,11 +184,9 @@ make_pipe(const string &type_name, const string &module_name) {
 PT(GraphicsPipe) GraphicsPipeSelection::
 make_pipe(TypeHandle type) {
   LightMutexHolder holder(_lock);
-  PipeTypes::const_iterator ti;
 
   // First, look for an exact match of the requested type.
-  for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) {
-    const PipeType &ptype = (*ti);
+  for (const PipeType &ptype : _pipe_types) {
     if (ptype._type == type) {
       // Here's an exact match.
       PT(GraphicsPipe) pipe = (*ptype._constructor)();
@@ -202,8 +197,7 @@ make_pipe(TypeHandle type) {
   }
 
   // Now look for a more-specific type.
-  for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) {
-    const PipeType &ptype = (*ti);
+  for (const PipeType &ptype : _pipe_types) {
     if (ptype._type.is_derived_from(type)) {
       // Here's an approximate match.
       PT(GraphicsPipe) pipe = (*ptype._constructor)();
@@ -215,8 +209,7 @@ make_pipe(TypeHandle type) {
 
   // Couldn't find any match; load the default module and try again.
   load_default_module();
-  for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) {
-    const PipeType &ptype = (*ti);
+  for (const PipeType &ptype : _pipe_types) {
     if (ptype._type.is_derived_from(type)) {
       // Here's an approximate match.
       PT(GraphicsPipe) pipe = (*ptype._constructor)();
@@ -260,13 +253,11 @@ make_default_pipe() {
   load_default_module();
 
   LightMutexHolder holder(_lock);
-  PipeTypes::const_iterator ti;
 
   if (!_default_pipe_name.empty()) {
     // First, look for an exact match of the default type name from the
     // Configrc file (excepting case and hyphenunderscore).
-    for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) {
-      const PipeType &ptype = (*ti);
+    for (const PipeType &ptype : _pipe_types) {
       if (cmp_nocase_uh(ptype._type.get_name(), _default_pipe_name) == 0) {
         // Here's an exact match.
         PT(GraphicsPipe) pipe = (*ptype._constructor)();
@@ -278,8 +269,7 @@ make_default_pipe() {
 
     // No match; look for a substring match.
     string preferred_name = downcase(_default_pipe_name);
-    for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) {
-      const PipeType &ptype = (*ti);
+    for (const PipeType &ptype : _pipe_types) {
       string ptype_name = downcase(ptype._type.get_name());
       if (ptype_name.find(preferred_name) != string::npos) {
         // Here's a substring match.
@@ -292,8 +282,7 @@ make_default_pipe() {
   }
 
   // Couldn't find a matching pipe type; choose the first one on the list.
-  for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) {
-    const PipeType &ptype = (*ti);
+  for (const PipeType &ptype : _pipe_types) {
     PT(GraphicsPipe) pipe = (*ptype._constructor)();
     if (pipe != nullptr) {
       return pipe;
@@ -310,9 +299,8 @@ make_default_pipe() {
  */
 void GraphicsPipeSelection::
 load_aux_modules() {
-  DisplayModules::iterator di;
-  for (di = _display_modules.begin(); di != _display_modules.end(); ++di) {
-    load_named_module(*di);
+  for (const string &module : _display_modules) {
+    load_named_module(module);
   }
 
   _display_modules.clear();
@@ -337,9 +325,7 @@ add_pipe_type(TypeHandle type, PipeConstructorFunc *func) {
 
   // First, make sure we don't already have a GraphicsPipe of this type.
   LightMutexHolder holder(_lock);
-  PipeTypes::const_iterator ti;
-  for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) {
-    const PipeType &ptype = (*ti);
+  for (const PipeType &ptype : _pipe_types) {
     if (ptype._type == type) {
       display_cat->warning()
         << "Attempt to register GraphicsPipe type " << type
@@ -375,8 +361,8 @@ do_load_default_module() {
   load_named_module(_default_display_module);
 
   DisplayModules::iterator di =
-    find(_display_modules.begin(), _display_modules.end(),
-         _default_display_module);
+    std::find(_display_modules.begin(), _display_modules.end(),
+              _default_display_module);
   if (di != _display_modules.end()) {
     _display_modules.erase(di);
   }

+ 47 - 39
panda/src/display/graphicsStateGuardian.cxx

@@ -24,7 +24,6 @@
 #include "renderBuffer.h"
 #include "light.h"
 #include "planeNode.h"
-#include "ambientLight.h"
 #include "throw_event.h"
 #include "clockObject.h"
 #include "pStatTimer.h"
@@ -60,7 +59,6 @@
 #include "fogAttrib.h"
 #include "config_pstatclient.h"
 
-#include <algorithm>
 #include <limits.h>
 
 using std::string;
@@ -932,12 +930,12 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
   }
   case Shader::SMO_frame_time: {
     PN_stdfloat time = ClockObject::get_global_clock()->get_frame_time();
-    t = LMatrix4(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, time, time, time, time);
+    t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, time, time, time, time);
     return &t;
   }
   case Shader::SMO_frame_delta: {
     PN_stdfloat dt = ClockObject::get_global_clock()->get_dt();
-    t = LMatrix4(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dt, dt, dt, dt);
+    t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dt, dt, dt, dt);
     return &t;
   }
   case Shader::SMO_texpad_x: {
@@ -949,7 +947,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
     double cx = (sx * 0.5) / tex->get_x_size();
     double cy = (sy * 0.5) / tex->get_y_size();
     double cz = (sz * 0.5) / tex->get_z_size();
-    t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,cx,cy,cz,0);
+    t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, cx, cy, cz, 0);
     return &t;
   }
   case Shader::SMO_texpix_x: {
@@ -958,7 +956,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
     double px = 1.0 / tex->get_x_size();
     double py = 1.0 / tex->get_y_size();
     double pz = 1.0 / tex->get_z_size();
-    t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,px,py,pz,0);
+    t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, px, py, pz, 0);
     return &t;
   }
   case Shader::SMO_attr_material: {
@@ -966,7 +964,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
       _target_rs->get_attrib_def(MaterialAttrib::get_class_slot());
     // Material matrix contains AMBIENT, DIFFUSE, EMISSION, SPECULAR+SHININESS
     if (target_material->is_off()) {
-      t = LMatrix4(1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0);
+      t.set(1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0);
       return &t;
     }
     Material *m = target_material->get_material();
@@ -975,17 +973,17 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
     LVecBase4 const &emm = m->get_emission();
     LVecBase4 spc = m->get_specular();
     spc[3] = m->get_shininess();
-    t = LMatrix4(amb[0],amb[1],amb[2],amb[3],
-                  dif[0],dif[1],dif[2],dif[3],
-                  emm[0],emm[1],emm[2],emm[3],
-                  spc[0],spc[1],spc[2],spc[3]);
+    t.set(amb[0], amb[1], amb[2], amb[3],
+          dif[0], dif[1], dif[2], dif[3],
+          emm[0], emm[1], emm[2], emm[3],
+          spc[0], spc[1], spc[2], spc[3]);
     return &t;
   }
   case Shader::SMO_attr_material2: {
     const MaterialAttrib *target_material = (const MaterialAttrib *)
       _target_rs->get_attrib_def(MaterialAttrib::get_class_slot());
     if (target_material->is_off()) {
-      t = LMatrix4(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
+      t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
       return &t;
     }
     Material *m = target_material->get_material();
@@ -1000,7 +998,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
       return &LMatrix4::ones_mat();
     }
     LVecBase4 c = target_color->get_color();
-    t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,c[0],c[1],c[2],c[3]);
+    t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c[0], c[1], c[2], c[3]);
     return &t;
   }
   case Shader::SMO_attr_colorscale: {
@@ -1010,7 +1008,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
       return &LMatrix4::ones_mat();
     }
     LVecBase4 cs = target_color->get_scale();
-    t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,cs[0],cs[1],cs[2],cs[3]);
+    t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, cs[0], cs[1], cs[2], cs[3]);
     return &t;
   }
   case Shader::SMO_attr_fog: {
@@ -1022,7 +1020,8 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
     }
     PN_stdfloat start, end;
     fog->get_linear_range(start, end);
-    t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,fog->get_exp_density(),start,end,1.0f/(end-start));
+    t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+          fog->get_exp_density(), start, end, 1.0f / (end - start));
     return &t;
   }
   case Shader::SMO_attr_fogcolor: {
@@ -1033,7 +1032,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
       return &LMatrix4::ones_mat();
     }
     LVecBase4 c = fog->get_color();
-    t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,c[0],c[1],c[2],c[3]);
+    t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c[0], c[1], c[2], c[3]);
     return &t;
   }
   case Shader::SMO_alight_x: {
@@ -1042,7 +1041,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
     AmbientLight *lt;
     DCAST_INTO_R(lt, np.node(), &LMatrix4::zeros_mat());
     LColor const &c = lt->get_color();
-    t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,c[0],c[1],c[2],c[3]);
+    t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c[0], c[1], c[2], c[3]);
     return &t;
   }
   case Shader::SMO_satten_x: {
@@ -1052,7 +1051,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
     DCAST_INTO_R(lt, np.node(), &LMatrix4::ones_mat());
     LVecBase3 const &a = lt->get_attenuation();
     PN_stdfloat x = lt->get_exponent();
-    t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,a[0],a[1],a[2],x);
+    t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a[0], a[1], a[2], x);
     return &t;
   }
   case Shader::SMO_dlight_x: {
@@ -1069,7 +1068,10 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
     d.normalize();
     LVecBase3 h = d + LVecBase3(0,-1,0);
     h.normalize();
-    t = LMatrix4(c[0],c[1],c[2],c[3],s[0],s[1],s[2],c[3],d[0],d[1],d[2],0,h[0],h[1],h[2],0);
+    t.set(c[0], c[1], c[2], c[3],
+          s[0], s[1], s[2], c[3],
+          d[0], d[1], d[2], 0,
+          h[0], h[1], h[2], 0);
     return &t;
   }
   case Shader::SMO_plight_x: {
@@ -1087,7 +1089,10 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
     Lens *lens = lt->get_lens(0);
     PN_stdfloat lnear = lens->get_near();
     PN_stdfloat lfar = lens->get_far();
-    t = LMatrix4(c[0],c[1],c[2],c[3],s[0],s[1],s[2],s[3],p[0],p[1],p[2],lnear,a[0],a[1],a[2],lfar);
+    t.set(c[0], c[1], c[2], c[3],
+          s[0], s[1], s[2], s[3],
+          p[0], p[1], p[2], lnear,
+          a[0], a[1], a[2], lfar);
     return &t;
   }
   case Shader::SMO_slight_x: {
@@ -1105,7 +1110,10 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
       _scene_setup->get_world_transform()->get_mat();
     LVecBase3 p = t.xform_point(lens->get_nodal_point());
     LVecBase3 d = -(t.xform_vec(lens->get_view_vector()));
-    t = LMatrix4(c[0],c[1],c[2],c[3],s[0],s[1],s[2],s[3],p[0],p[1],p[2],0,d[0],d[1],d[2],cutoff);
+    t.set(c[0], c[1], c[2], c[3],
+          s[0], s[1], s[2], s[3],
+          p[0], p[1], p[2], 0,
+          d[0], d[1], d[2], cutoff);
     return &t;
   }
   case Shader::SMO_light_ambient: {
@@ -1149,7 +1157,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
     if (_target_rs->get_attrib(ta) && _target_rs->get_attrib(tma) &&
         index < ta->get_num_on_stages()) {
       LVecBase3 scale = tma->get_transform(ta->get_on_stage(index))->get_scale();
-      t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,scale[0],scale[1],scale[2],0);
+      t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, scale[0], scale[1], scale[2], 0);
       return &t;
     } else {
       return &LMatrix4::ident_mat();
@@ -1173,7 +1181,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
         index < ta->get_num_on_stages()) {
       TextureStage *ts = ta->get_on_stage(index);
       PN_stdfloat v = (ta->get_on_texture(ts)->get_format() == Texture::F_alpha);
-      t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,v,v,v,0);
+      t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, v, v, v, 0);
       return &t;
     } else {
       return &LMatrix4::zeros_mat();
@@ -1185,7 +1193,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
     const PlaneNode *plane_node;
     DCAST_INTO_R(plane_node, np.node(), &LMatrix4::zeros_mat());
     LPlane p = plane_node->get_plane();
-    t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,p[0],p[1],p[2],p[3]);
+    t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, p[0], p[1], p[2], p[3]);
     return &t;
   }
   case Shader::SMO_clipplane_x: {
@@ -1235,10 +1243,10 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
   case Shader::SMO_vec_constant_x: {
     const LVecBase4 &input = _target_shader->get_shader_input_vector(name);
     const PN_stdfloat *data = input.get_data();
-    t = LMatrix4(data[0],data[1],data[2],data[3],
-                 data[0],data[1],data[2],data[3],
-                 data[0],data[1],data[2],data[3],
-                 data[0],data[1],data[2],data[3]);
+    t.set(data[0], data[1], data[2], data[3],
+          data[0], data[1], data[2], data[3],
+          data[0], data[1], data[2], data[3],
+          data[0], data[1], data[2], data[3]);
     return &t;
   }
   case Shader::SMO_world_to_view: {
@@ -1394,10 +1402,10 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
       // There is an input specifying precisely this whole thing, with dot and
       // all.  Support this, even if only for backward compatibility.
       const LVecBase4 &data = _target_shader->get_shader_input_vector(name);
-      t = LMatrix4(data[0],data[1],data[2],data[3],
-                   data[0],data[1],data[2],data[3],
-                   data[0],data[1],data[2],data[3],
-                   data[0],data[1],data[2],data[3]);
+      t.set(data[0], data[1], data[2], data[3],
+            data[0], data[1], data[2], data[3],
+            data[0], data[1], data[2], data[3],
+            data[0], data[1], data[2], data[3]);
       return &t;
     }
 
@@ -1578,11 +1586,11 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t)
 
   } else if (attrib == IN_position) {
     if (np.is_empty()) {
-      t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0);
+      t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);
       return &t;
     } else if (node->is_ambient_light()) {
       // Ambient light has no position.
-      t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
+      t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
       return &t;
     } else if (node->is_of_type(DirectionalLight::get_class_type())) {
       DirectionalLight *light;
@@ -1591,7 +1599,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t)
       CPT(TransformState) transform = np.get_transform(_scene_setup->get_scene_root().get_parent());
       LVector3 dir = -(light->get_direction() * transform->get_mat());
       dir *= _scene_setup->get_cs_world_transform()->get_mat();
-      t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,dir[0],dir[1],dir[2],0);
+      t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dir[0], dir[1], dir[2], 0);
       return &t;
     } else {
       LightLensNode *light;
@@ -1611,11 +1619,11 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t)
 
   } else if (attrib == IN_halfVector) {
     if (np.is_empty()) {
-      t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0);
+      t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);
       return &t;
     } else if (node->is_ambient_light()) {
       // Ambient light has no half-vector.
-      t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
+      t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
       return &t;
     } else if (node->is_of_type(DirectionalLight::get_class_type())) {
       DirectionalLight *light;
@@ -1627,7 +1635,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t)
       dir.normalize();
       dir += LVector3(0, 0, 1);
       dir.normalize();
-      t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,dir[0],dir[1],dir[2],1);
+      t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dir[0], dir[1], dir[2], 1);
       return &t;
     } else {
       LightLensNode *light;
@@ -1644,7 +1652,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t)
       pos.normalize();
       pos += LVector3(0, 0, 1);
       pos.normalize();
-      t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,pos[0],pos[1],pos[2],1);
+      t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pos[0],pos[1],pos[2], 1);
       return &t;
     }
 

+ 0 - 1
panda/src/display/p3display_composite2.cxx

@@ -1,5 +1,4 @@
 #include "graphicsPipeSelection.cxx"
-#include "graphicsStateGuardian.cxx"
 #include "graphicsThreadingModel.cxx"
 #include "graphicsWindow.cxx"
 #include "graphicsWindowProc.cxx"

+ 3 - 5
panda/src/distort/projectionScreen.cxx

@@ -484,8 +484,7 @@ recompute_geom(Geom *geom, const LMatrix4 &rel_mat) {
   const LMatrix4 &to_uv = _invert_uvs ? lens_to_uv_inverted : lens_to_uv;
 
   // Iterate through all the vertices in the Geom.
-  CPT(GeomVertexData) vdata = geom->get_vertex_data(current_thread);
-  vdata = vdata->animate_vertices(true, current_thread);
+  CPT(GeomVertexData) vdata = geom->get_animated_vertex_data(true, current_thread);
 
   CPT(GeomVertexFormat) vformat = vdata->get_format();
   if (!vformat->has_column(_texcoord_name) || (_texcoord_3d && vformat->get_column(_texcoord_name)->get_num_components() < 3)) {
@@ -507,7 +506,7 @@ recompute_geom(Geom *geom, const LMatrix4 &rel_mat) {
   PT(GeomVertexData) modify_vdata = geom->modify_vertex_data();
 
   // Maybe the vdata has animation that we should consider.
-  CPT(GeomVertexData) animated_vdata = geom->get_vertex_data(current_thread)->animate_vertices(true, current_thread);
+  CPT(GeomVertexData) animated_vdata = geom->get_animated_vertex_data(true, current_thread);
 
   GeomVertexWriter texcoord(modify_vdata, _texcoord_name, current_thread);
   GeomVertexWriter color(modify_vdata, current_thread);
@@ -674,9 +673,8 @@ make_mesh_geom(const Geom *geom, Lens *lens, LMatrix4 &rel_mat) {
 
   Thread *current_thread = Thread::get_current_thread();
   PT(Geom) new_geom = geom->make_copy();
+  new_geom->set_vertex_data(new_geom->get_animated_vertex_data(false, current_thread));
   PT(GeomVertexData) vdata = new_geom->modify_vertex_data();
-  new_geom->set_vertex_data(vdata->animate_vertices(false, current_thread));
-  vdata = new_geom->modify_vertex_data();
   GeomVertexRewriter vertex(vdata, InternalName::get_vertex());
   while (!vertex.is_at_end()) {
     LVertex vert = vertex.get_data3();

+ 5 - 5
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -5240,9 +5240,9 @@ calc_fb_properties(DWORD cformat, DWORD dformat,
 #define GAMMA_1 (255.0 * 256.0)
 
 static bool _gamma_table_initialized = false;
-static unsigned short _orignial_gamma_table [256 * 3];
+static unsigned short _original_gamma_table [256 * 3];
 
-void _create_gamma_table (PN_stdfloat gamma, unsigned short *original_red_table, unsigned short *original_green_table, unsigned short *original_blue_table, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table) {
+void _create_gamma_table_dx9 (PN_stdfloat gamma, unsigned short *original_red_table, unsigned short *original_green_table, unsigned short *original_blue_table, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table) {
   int i;
   double gamma_correction;
 
@@ -5304,7 +5304,7 @@ get_gamma_table(void) {
     HDC hdc = GetDC(nullptr);
 
     if (hdc) {
-      if (GetDeviceGammaRamp (hdc, (LPVOID) _orignial_gamma_table)) {
+      if (GetDeviceGammaRamp (hdc, (LPVOID) _original_gamma_table)) {
         _gamma_table_initialized = true;
         get = true;
       }
@@ -5329,10 +5329,10 @@ static_set_gamma(bool restore, PN_stdfloat gamma) {
     unsigned short ramp [256 * 3];
 
     if (restore && _gamma_table_initialized) {
-      _create_gamma_table (gamma, &_orignial_gamma_table [0], &_orignial_gamma_table [256], &_orignial_gamma_table [512], &ramp [0], &ramp [256], &ramp [512]);
+      _create_gamma_table_dx9 (gamma, &_original_gamma_table [0], &_original_gamma_table [256], &_original_gamma_table [512], &ramp [0], &ramp [256], &ramp [512]);
     }
     else {
-      _create_gamma_table (gamma, 0, 0, 0, &ramp [0], &ramp [256], &ramp [512]);
+      _create_gamma_table_dx9 (gamma, 0, 0, 0, &ramp [0], &ramp [256], &ramp [512]);
     }
 
     if (SetDeviceGammaRamp (hdc, ramp)) {

+ 1 - 1
panda/src/gles2gsg/gles2gsg.h

@@ -51,7 +51,7 @@
 // OpenGL ES 2 has no fixed-function pipeline.
 #undef SUPPORT_FIXED_FUNCTION
 
-#ifdef IS_OSX
+#ifdef BUILD_IPHONE
   #include <OpenGLES/ES2/gl.h>
 // #include <OpenGLESES2glext.h>
 #else

+ 1 - 1
panda/src/glesgsg/glesgsg.h

@@ -54,7 +54,7 @@
 #define __glext_h_
 #define ES1_GLEXT_H_GUARD
 
-#ifdef IS_OSX
+#ifdef BUILD_IPHONE
   #include <OpenGLES/ES1/gl.h>
 // #include <OpenGLESES1glext.h>
 #else

+ 11 - 9
panda/src/glstuff/glCgShaderContext_src.cxx

@@ -226,12 +226,14 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte
         if (!resource) {
           resource = "unknown";
         }
-        GLCAT.error()
-          << "Could not find Cg varying " << cgGetParameterName(p);
-        if (attribname) {
-          GLCAT.error(false) << " : " << attribname;
+        if (GLCAT.is_debug()) {
+          GLCAT.debug()
+            << "Could not find Cg varying " << cgGetParameterName(p);
+          if (attribname) {
+            GLCAT.debug(false) << " : " << attribname;
+          }
+          GLCAT.debug(false) << " (" << resource << ") in the compiled GLSL program.\n";
         }
-        GLCAT.error(false) << " (" << resource << ") in the compiled GLSL program.\n";
 
       } else if (loc != 0 && bind._id._name == "vtx_position") {
         // We really have to bind the vertex position to attribute 0, since
@@ -312,10 +314,10 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte
         GLCAT.debug(false)
           << " is bound to a conventional attribute (" << resource << ")\n";
       }
-    }
-    if (loc == CA_unknown) {
-      // Suggest fix to developer.
-      GLCAT.error() << "Try using a different semantic.\n";
+      if (loc == CA_unknown) {
+        // Suggest fix to developer.
+        GLCAT.debug() << "Try using a different semantic.\n";
+      }
     }
 #endif
 

+ 9 - 0
panda/src/glstuff/glGraphicsBuffer_src.cxx

@@ -1097,6 +1097,15 @@ bind_slot_multisample(bool rb_resize, Texture **attach, RenderTexturePlane slot,
 #endif
       glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, _rbm[slot]);
       GLuint format = GL_DEPTH_COMPONENT;
+#ifndef OPENGLES
+      if (_fb_properties.get_float_depth()) {
+        if (!glgsg->_use_remapped_depth_range) {
+          format = GL_DEPTH_COMPONENT32F;
+        } else {
+          format = GL_DEPTH_COMPONENT32F_NV;
+        }
+      } else
+#endif
       if (tex) {
         switch (tex->get_format()) {
           case Texture::F_depth_component16:

+ 3 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -8925,6 +8925,9 @@ get_panda_wrap_mode(GLenum wm) {
   case GL_REPEAT:
     return SamplerState::WM_repeat;
 
+  case GL_MIRRORED_REPEAT:
+    return SamplerState::WM_mirror;
+
 #ifndef OPENGLES
   case GL_MIRROR_CLAMP_EXT:
   case GL_MIRROR_CLAMP_TO_EDGE_EXT:

+ 23 - 2
panda/src/gobj/geom.cxx

@@ -286,6 +286,28 @@ make_nonindexed(bool composite_only) {
   return num_changed;
 }
 
+/**
+ * Returns a GeomVertexData that represents the results of computing the
+ * vertex animation on the CPU for this Geom's vertex data.
+ *
+ * If there is no CPU-defined vertex animation on this object, this just
+ * returns the original object.
+ *
+ * If there is vertex animation, but the VertexTransform values have not
+ * changed since last time, this may return the same pointer it returned
+ * previously.  Even if the VertexTransform values have changed, it may still
+ * return the same pointer, but with its contents modified (this is preferred,
+ * since it allows the graphics backend to update vertex buffers optimally).
+ *
+ * If force is false, this method may return immediately with stale data, if
+ * the vertex data is not completely resident.  If force is true, this method
+ * will never return stale data, but may block until the data is available.
+ */
+CPT(GeomVertexData) Geom::
+get_animated_vertex_data(bool force, Thread *current_thread) const {
+  return get_vertex_data()->animate_vertices(force, current_thread);
+}
+
 /**
  * Replaces the ith GeomPrimitive object stored within the Geom with the new
  * object.
@@ -1311,8 +1333,7 @@ compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const {
   int num_vertices = 0;
 
   // Get the vertex data, after animation.
-  CPT(GeomVertexData) vertex_data = cdata->_data.get_read_pointer(current_thread);
-  vertex_data = vertex_data->animate_vertices(true, current_thread);
+  CPT(GeomVertexData) vertex_data = get_animated_vertex_data(true, current_thread);
 
   // Now actually compute the bounding volume.  We do this by using
   // calc_tight_bounds to determine our box first.

+ 2 - 0
panda/src/gobj/geom.h

@@ -85,6 +85,8 @@ PUBLISHED:
   void offset_vertices(const GeomVertexData *data, int offset);
   int make_nonindexed(bool composite_only);
 
+  CPT(GeomVertexData) get_animated_vertex_data(bool force, Thread *current_thread) const;
+
   INLINE bool is_empty() const;
 
   INLINE size_t get_num_primitives() const;

+ 3 - 1
panda/src/gobj/geomVertexArrayData.I

@@ -45,7 +45,9 @@ has_column(const InternalName *name) const {
  */
 INLINE int GeomVertexArrayData::
 get_num_rows() const {
-  return get_handle()->get_num_rows();
+  CDReader cdata(_cycler);
+  nassertr(_array_format->get_stride() != 0, 0);
+  return cdata->_buffer.get_size() / _array_format->get_stride();
 }
 
 /**

+ 16 - 3
panda/src/gobj/geomVertexData.I

@@ -60,9 +60,20 @@ has_column(const InternalName *name) const {
  */
 INLINE int GeomVertexData::
 get_num_rows() const {
-  GeomVertexDataPipelineReader reader(this, Thread::get_current_thread());
-  reader.check_array_readers();
-  return reader.get_num_rows();
+  CPT(GeomVertexArrayData) array;
+  {
+    CDReader cdata(_cycler);
+    nassertr(cdata->_format->get_num_arrays() == cdata->_arrays.size(), 0);
+
+    if (cdata->_arrays.size() == 0) {
+      // No arrays means no rows.  Weird but legal.
+      return 0;
+    }
+
+    array = cdata->_arrays[0].get_read_pointer();
+  }
+
+  return array->get_num_rows();
 }
 
 /**
@@ -761,7 +772,9 @@ set_object(const GeomVertexData *object) {
   _cdata = (GeomVertexData::CData *)_object->_cycler.read_unlocked(_current_thread);
   _got_array_readers = false;
 
+#ifdef DO_PIPELINING
   _cdata->ref();
+#endif  // DO_PIPELINING
 }
 
 /**

+ 18 - 5
panda/src/gobj/geomVertexData.cxx

@@ -621,13 +621,26 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
             const TransformBlend &blend = blend_table->get_blend(from.get_data1i());
             LVecBase4 weights = LVecBase4::zero();
             LVecBase4i indices(0, 0, 0, 0);
-            nassertv(blend.get_num_transforms() <= 4);
 
-            for (size_t i = 0; i < blend.get_num_transforms(); i++) {
-              weights[i] = blend.get_weight(i);
-              indices[i] = add_transform(transform_table, blend.get_transform(i),
-                                         already_added);
+            if (blend.get_num_transforms() <= 4) {
+              for (size_t i = 0; i < blend.get_num_transforms(); i++) {
+                weights[i] = blend.get_weight(i);
+                indices[i] = add_transform(transform_table, blend.get_transform(i),
+                                           already_added);
+              }
+            } else {
+              // Limit the number of blends to the four with highest weights.
+              TransformBlend blend2(blend);
+              blend2.limit_transforms(4);
+              blend2.normalize_weights();
+
+              for (size_t i = 0; i < 4; i++) {
+                weights[i] = blend2.get_weight(i);
+                indices[i] = add_transform(transform_table, blend2.get_transform(i),
+                                           already_added);
+              }
             }
+
             if (weight.has_column()) {
               weight.set_data4(weights);
             }

+ 2 - 2
panda/src/gobj/preparedGraphicsObjects.cxx

@@ -1619,8 +1619,8 @@ begin_frame(GraphicsStateGuardianBase *gsg, Thread *current_thread) {
        ++qsi) {
     Shader *shader = qsi->first;
     ShaderContext *sc = shader->prepare_now(this, gsg);
-    if (qti->second != nullptr) {
-      qti->second->set_result(sc);
+    if (qsi->second != nullptr) {
+      qsi->second->set_result(sc);
     }
   }
 

+ 1 - 1
panda/src/gobj/textureReloadRequest.cxx

@@ -40,7 +40,7 @@ do_task() {
       // become a kind of a leak (if the texture is never rendered again on
       // this GSG, we'll just end up carrying the texture memory in RAM
       // forever, instead of dumping it as soon as it gets prepared).
-      _texture->prepare(_pgo);
+      _pgo->enqueue_texture(_texture);
     }
   }
 

+ 1 - 1
panda/src/grutil/multitexReducer.cxx

@@ -866,7 +866,7 @@ transfer_geom(GeomNode *geom_node, const InternalName *texcoord_name,
     PT(Geom) geom = orig_geom->make_copy();
 
     // Ensure that any vertex animation has been applied.
-    geom->set_vertex_data(geom->get_vertex_data(current_thread)->animate_vertices(true, current_thread));
+    geom->set_vertex_data(geom->get_animated_vertex_data(true, current_thread));
 
     // Now get a modifiable pointer to the vertex data in the new Geom.  This
     // will actually perform a deep copy of the vertex data.

+ 1 - 1
panda/src/net/connection.cxx

@@ -445,7 +445,7 @@ do_flush() {
     if (data_sent > 0) {
       total_sent += data_sent;
     }
-    double last_report = 0;
+
     while (!okflag && tcp->Active() &&
            (data_sent > 0 || tcp->GetLastError() == LOCAL_BLOCKING_ERROR)) {
       if (data_sent == 0) {

+ 3 - 0
panda/src/pgraph/cullTraverserData.cxx

@@ -54,6 +54,9 @@ apply_transform_and_state(CullTraverser *trav) {
     CPT(TransformState) node_transform = _node_reader.get_transform();
     node_effects->cull_callback(trav, *this, node_transform, node_state);
     apply_transform(node_transform);
+
+    // The cull callback may have changed the node properties.
+    _node_reader.check_cached(false);
   }
 
   if (!node_state->is_empty()) {

+ 2 - 3
panda/src/pgraph/geomNode.cxx

@@ -376,8 +376,7 @@ r_prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *node_state,
     geom = transformer.premunge_geom(geom, munger);
 
     // Prepare each of the vertex arrays in the munged Geom.
-    CPT(GeomVertexData) vdata = geom->get_vertex_data(current_thread);
-    vdata = vdata->animate_vertices(false, current_thread);
+    CPT(GeomVertexData) vdata = geom->get_animated_vertex_data(false, current_thread);
     GeomVertexDataPipelineReader vdata_reader(vdata, current_thread);
     int num_arrays = vdata_reader.get_num_arrays();
     for (int i = 0; i < num_arrays; ++i) {
@@ -474,7 +473,7 @@ calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point, bool &found_any,
   for (gi = geoms->begin(); gi != geoms->end(); ++gi) {
     CPT(Geom) geom = (*gi)._geom.get_read_pointer();
     geom->calc_tight_bounds(min_point, max_point, found_any,
-                            geom->get_vertex_data(current_thread)->animate_vertices(true, current_thread),
+                            geom->get_animated_vertex_data(true, current_thread),
                             !next_transform->is_identity(), mat,
                             current_thread);
   }

+ 4 - 1
panda/src/pgraph/renderAttrib.cxx

@@ -211,7 +211,7 @@ garbage_collect() {
   }
 
   num_this_pass = std::min(num_this_pass, size);
-  size_t stop_at_element = (_garbage_index + num_this_pass) % size;
+  size_t stop_at_element = (si + num_this_pass) % size;
 
   do {
     RenderAttrib *attrib = (RenderAttrib *)_attribs->get_key(si);
@@ -229,6 +229,9 @@ garbage_collect() {
       // still need to visit.
       --size;
       --si;
+      if (stop_at_element > 0) {
+        --stop_at_element;
+      }
     }
 
     si = (si + 1) % size;

+ 3 - 0
panda/src/pgraph/renderState.cxx

@@ -950,6 +950,9 @@ garbage_collect() {
       // still need to visit.
       --size;
       --si;
+      if (stop_at_element > 0) {
+        --stop_at_element;
+      }
     }
 
     si = (si + 1) % size;

+ 3 - 0
panda/src/pgraph/transformState.cxx

@@ -1216,6 +1216,9 @@ garbage_collect() {
       // still need to visit.
       --size;
       --si;
+      if (stop_at_element > 0) {
+        --stop_at_element;
+      }
     }
 
     si = (si + 1) % size;

+ 0 - 8
panda/src/pipeline/blockerSimple.I

@@ -11,14 +11,6 @@
  * @date 2007-06-20
  */
 
-/**
- *
- */
-INLINE BlockerSimple::
-BlockerSimple() {
-  _flags = 0;
-}
-
 /**
  *
  */

+ 2 - 2
panda/src/pipeline/blockerSimple.h

@@ -28,7 +28,7 @@
  */
 class EXPCL_PANDA_PIPELINE BlockerSimple {
 protected:
-  INLINE BlockerSimple();
+  constexpr BlockerSimple() = default;
   INLINE ~BlockerSimple();
 
 protected:
@@ -38,7 +38,7 @@ protected:
     F_has_waiters  = 0x40000000,
   };
 
-  unsigned int _flags;
+  unsigned int _flags = 0;
 
   friend class ThreadSimpleManager;
 };

+ 3 - 0
panda/src/pipeline/config_pipeline.cxx

@@ -71,7 +71,10 @@ init_libpipeline() {
   }
   initialized = true;
 
+#ifdef DO_PIPELINING
   CycleData::init_type();
+#endif
+
   MainThread::init_type();
   ExternalThread::init_type();
   GenericThread::init_type();

+ 9 - 10
panda/src/pipeline/contextSwitch_longjmp_src.c

@@ -1,8 +1,4 @@
-/* Filename: contextSwitch_longjmp_src.c
- * Created by:  drose (15Apr10)
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
+/**
  * PANDA 3D SOFTWARE
  * Copyright (c) Carnegie Mellon University.  All rights reserved.
  *
@@ -10,7 +6,10 @@
  * license.  You should have received a copy of this license along
  * with this source code in a file named "LICENSE."
  *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+ * @file contextSwitch_longjmp_src.c
+ * @author drose
+ * @date 2010-04-15
+ */
 
 /* This is the implementation of user-space context switching using
    setmp() / longjmp().  This is the hackier implementation,
@@ -90,14 +89,14 @@ void
 cs_longjmp(cs_jmp_buf env) {
   _asm {
     mov eax, env;
-    
+
     mov ebx, [eax + 0];
     mov edi, [eax + 4];
     mov esi, [eax + 8];
     mov ebp, [eax + 12];
     mov esp, [eax + 16];
     mov edx, [eax + 20];
-    
+
     frstor [eax + 24];  /* restore floating-point state */
 
     mov eax, 1;   /* return 1 from setjmp: pass 2 return */
@@ -251,7 +250,7 @@ setup_context_1(void) {
 }
 
 void
-init_thread_context(struct ThreadContext *context, 
+init_thread_context(struct ThreadContext *context,
                     unsigned char *stack, size_t stack_size,
                     ThreadFunction *thread_func, void *data) {
   /* Copy all of the input parameters to static variables, then begin
@@ -263,7 +262,7 @@ init_thread_context(struct ThreadContext *context,
   st_data = data;
 
   setup_context_1();
-}  
+}
 
 void
 save_thread_context(struct ThreadContext *context,

+ 14 - 15
panda/src/pipeline/contextSwitch_posix_src.c

@@ -1,8 +1,4 @@
-/* Filename: contextSwitch_posix_src.c
- * Created by:  drose (15Apr10)
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
+/**
  * PANDA 3D SOFTWARE
  * Copyright (c) Carnegie Mellon University.  All rights reserved.
  *
@@ -10,7 +6,10 @@
  * license.  You should have received a copy of this license along
  * with this source code in a file named "LICENSE."
  *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+ * @file contextSwitch_posix_src.c
+ * @author drose
+ * @date 2010-04-15
+ */
 
 /* This is the implementation of user-space context switching using
    posix threads to manage the different execution contexts.  This
@@ -44,7 +43,7 @@ struct ThreadContext {
   pthread_mutex_t _ready_mutex;
   pthread_cond_t _ready_cvar;
   int _ready_flag;
-  
+
   /* This is set FALSE while the thread is alive, and TRUE if the
      thread is to be terminated when it next wakes up. */
   int _terminated;
@@ -83,19 +82,19 @@ thread_main(void *data) {
 }
 
 void
-init_thread_context(struct ThreadContext *context, 
+init_thread_context(struct ThreadContext *context,
                     unsigned char *stack, size_t stack_size,
                     ThreadFunction *thread_func, void *data) {
   context->_thread_func = thread_func;
   context->_data = data;
 
-  pthread_attr_t attr; 
-  pthread_attr_init(&attr); 
+  pthread_attr_t attr;
+  pthread_attr_init(&attr);
   pthread_attr_setstacksize(&attr, stack_size);
-  pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); 
+  pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
 
-  pthread_create(&(context->_thread), &attr, thread_main, context); 
-  pthread_attr_destroy(&attr); 
+  pthread_create(&(context->_thread), &attr, thread_main, context);
+  pthread_attr_destroy(&attr);
 }
 
 void
@@ -142,7 +141,7 @@ switch_to_thread_context(struct ThreadContext *from_context,
     /* We've been rudely terminated.  Exit gracefully. */
     pthread_exit(NULL);
   }
-  
+
   /* Now we have been signaled again, and we're ready to resume the
      thread. */
   longjmp(from_context->_jmp_context, 1);
@@ -164,7 +163,7 @@ alloc_thread_context() {
   pthread_mutexattr_init(&attr);
   // The symbol PTHREAD_MUTEX_DEFAULT isn't always available?
   //  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT);
-  int result = pthread_mutex_init(&context->_ready_mutex, &attr);
+  pthread_mutex_init(&context->_ready_mutex, &attr);
   pthread_mutexattr_destroy(&attr);
 
   pthread_cond_init(&context->_ready_cvar, NULL);

+ 6 - 7
panda/src/pipeline/contextSwitch_ucontext_src.c

@@ -1,8 +1,4 @@
-/* Filename: contextSwitch_ucontext_src.c
- * Created by:  drose (15Apr10)
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
+/**
  * PANDA 3D SOFTWARE
  * Copyright (c) Carnegie Mellon University.  All rights reserved.
  *
@@ -10,7 +6,10 @@
  * license.  You should have received a copy of this license along
  * with this source code in a file named "LICENSE."
  *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+ * @file contextSwitch_ucontext_src.c
+ * @author drose
+ * @date 2010-04-15
+ */
 
 /* This is the implementation of user-space context switching using
    getcontext() / setcontext().  This is the preferred implementation,
@@ -43,7 +42,7 @@ begin_context(ThreadFunction *thread_func, void *data) {
 }
 
 void
-init_thread_context(struct ThreadContext *context, 
+init_thread_context(struct ThreadContext *context,
                     unsigned char *stack, size_t stack_size,
                     ThreadFunction *thread_func, void *data) {
   if (getcontext(&context->_ucontext) != 0) {

+ 9 - 10
panda/src/pipeline/contextSwitch_windows_src.c

@@ -1,8 +1,4 @@
-/* Filename: contextSwitch_windows_src.c
- * Created by:  drose (15Apr10)
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
+/**
  * PANDA 3D SOFTWARE
  * Copyright (c) Carnegie Mellon University.  All rights reserved.
  *
@@ -10,7 +6,10 @@
  * license.  You should have received a copy of this license along
  * with this source code in a file named "LICENSE."
  *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+ * @file contextSwitch_windows_src.c
+ * @author drose
+ * @date 2010-04-15
+ */
 
 /* This is the implementation of user-space context switching using
    native Windows threading constructs to manage the different
@@ -37,7 +36,7 @@ struct ThreadContext {
   /* This event is in the signaled state when the thread is ready to
      roll. */
   HANDLE _ready;
-  
+
   /* This is set FALSE while the thread is alive, and TRUE if the
      thread is to be terminated when it next wakes up. */
   int _terminated;
@@ -71,13 +70,13 @@ thread_main(LPVOID data) {
 }
 
 void
-init_thread_context(struct ThreadContext *context, 
+init_thread_context(struct ThreadContext *context,
                     unsigned char *stack, size_t stack_size,
                     ThreadFunction *thread_func, void *data) {
   context->_thread_func = thread_func;
   context->_data = data;
 
-  context->_thread = CreateThread(NULL, stack_size, 
+  context->_thread = CreateThread(NULL, stack_size,
                                   thread_main, context, 0, NULL);
 }
 
@@ -117,7 +116,7 @@ switch_to_thread_context(struct ThreadContext *from_context,
     /* We've been rudely terminated.  Exit gracefully. */
     ExitThread(1);
   }
-  
+
   /* Now we have been signaled again, and we're ready to resume the
      thread. */
   longjmp(from_context->_jmp_context, 1);

+ 3 - 0
panda/src/pipeline/cycleData.h

@@ -54,6 +54,9 @@ public:
   INLINE CycleData(const CycleData &copy) = default;
   virtual ~CycleData();
 
+  CycleData &operator = (CycleData &&from) = default;
+  CycleData &operator = (const CycleData &copy) = default;
+
   virtual CycleData *make_copy() const=0;
 
   virtual void write_datagram(BamWriter *, Datagram &) const;

+ 25 - 13
panda/src/pipeline/cycleDataLockedReader.I

@@ -45,6 +45,19 @@ CycleDataLockedReader(const CycleDataLockedReader<CycleDataType> &copy) :
   _cycler->increment_read(_pointer);
 }
 
+/**
+ *
+ */
+template<class CycleDataType>
+INLINE CycleDataLockedReader<CycleDataType>::
+CycleDataLockedReader(CycleDataLockedReader<CycleDataType> &&from) noexcept :
+  _cycler(from._cycler),
+  _current_thread(from._current_thread),
+  _pointer(from._pointer)
+{
+  from._pointer = nullptr;
+}
+
 /**
  *
  */
@@ -61,19 +74,6 @@ operator = (const CycleDataLockedReader<CycleDataType> &copy) {
   _cycler->increment_read(_pointer);
 }
 
-/**
- *
- */
-template<class CycleDataType>
-INLINE CycleDataLockedReader<CycleDataType>::
-CycleDataLockedReader(CycleDataLockedReader<CycleDataType> &&from) noexcept :
-  _cycler(from._cycler),
-  _current_thread(from._current_thread),
-  _pointer(from._pointer)
-{
-  from._pointer = nullptr;
-}
-
 /**
  *
  */
@@ -177,6 +177,18 @@ operator = (const CycleDataLockedReader<CycleDataType> &copy) {
   _pointer = copy._pointer;
 }
 
+/**
+ *
+ */
+template<class CycleDataType>
+INLINE void CycleDataLockedReader<CycleDataType>::
+operator = (CycleDataLockedReader<CycleDataType> &&from) noexcept {
+  nassertv(_pointer == nullptr);
+
+  _pointer = from._pointer;
+  from._pointer = nullptr;
+}
+
 /**
  *
  */

+ 37 - 14
panda/src/pipeline/cycleDataLockedStageReader.I

@@ -47,6 +47,20 @@ CycleDataLockedStageReader(const CycleDataLockedStageReader<CycleDataType> &copy
   _cycler->increment_read(_pointer);
 }
 
+/**
+ *
+ */
+template<class CycleDataType>
+INLINE CycleDataLockedStageReader<CycleDataType>::
+CycleDataLockedStageReader(CycleDataLockedStageReader<CycleDataType> &&from) noexcept :
+  _cycler(from._cycler),
+  _current_thread(from._current_thread),
+  _pointer(from._pointer),
+  _stage(from._stage)
+{
+  from._pointer = nullptr;
+}
+
 /**
  *
  */
@@ -64,20 +78,6 @@ operator = (const CycleDataLockedStageReader<CycleDataType> &copy) {
   _cycler->increment_read(_pointer);
 }
 
-/**
- *
- */
-template<class CycleDataType>
-INLINE CycleDataLockedStageReader<CycleDataType>::
-CycleDataLockedStageReader(CycleDataLockedStageReader<CycleDataType> &&from) noexcept :
-  _cycler(from._cycler),
-  _current_thread(from._current_thread),
-  _pointer(from._pointer),
-  _stage(from._stage)
-{
-  from._pointer = nullptr;
-}
-
 /**
  *
  */
@@ -174,6 +174,17 @@ CycleDataLockedStageReader(const CycleDataLockedStageReader<CycleDataType> &copy
 {
 }
 
+/**
+ *
+ */
+template<class CycleDataType>
+INLINE CycleDataLockedStageReader<CycleDataType>::
+CycleDataLockedStageReader(CycleDataLockedStageReader<CycleDataType> &&from) noexcept :
+  _pointer(from._cycler)
+{
+  from._pointer = nullptr;
+}
+
 /**
  *
  */
@@ -183,6 +194,18 @@ operator = (const CycleDataLockedStageReader<CycleDataType> &copy) {
   _pointer = copy._pointer;
 }
 
+/**
+ *
+ */
+template<class CycleDataType>
+INLINE void CycleDataLockedStageReader<CycleDataType>::
+operator = (CycleDataLockedStageReader<CycleDataType> &&from) noexcept {
+  nassertv(_pointer == nullptr);
+
+  _pointer = from._pointer;
+  from._pointer = nullptr;
+}
+
 /**
  *
  */

+ 40 - 17
panda/src/pipeline/cycleDataStageWriter.I

@@ -62,23 +62,6 @@ CycleDataStageWriter(const CycleDataStageWriter<CycleDataType> &copy) :
   _cycler->increment_write(_pointer);
 }
 
-/**
- *
- */
-template<class CycleDataType>
-INLINE void CycleDataStageWriter<CycleDataType>::
-operator = (const CycleDataStageWriter<CycleDataType> &copy) {
-  nassertv(_pointer == nullptr);
-  nassertv(_current_thread == copy._current_thread);
-
-  _cycler = copy._cycler;
-  _pointer = copy._pointer;
-  _stage = copy._stage;
-
-  nassertv(_pointer != nullptr);
-  _cycler->increment_write(_pointer);
-}
-
 /**
  * This flavor of the constructor elevates the pointer from the
  * CycleDataLockedStageReader from a read to a write pointer (and invalidates
@@ -128,6 +111,23 @@ CycleDataStageWriter(CycleDataStageWriter<CycleDataType> &&from) noexcept :
   from._pointer = nullptr;
 }
 
+/**
+ *
+ */
+template<class CycleDataType>
+INLINE void CycleDataStageWriter<CycleDataType>::
+operator = (const CycleDataStageWriter<CycleDataType> &copy) {
+  nassertv(_pointer == nullptr);
+  nassertv(_current_thread == copy._current_thread);
+
+  _cycler = copy._cycler;
+  _pointer = copy._pointer;
+  _stage = copy._stage;
+
+  nassertv(_pointer != nullptr);
+  _cycler->increment_write(_pointer);
+}
+
 /**
  *
  */
@@ -227,6 +227,17 @@ CycleDataStageWriter(const CycleDataStageWriter<CycleDataType> &copy) :
 {
 }
 
+/**
+ *
+ */
+template<class CycleDataType>
+INLINE CycleDataStageWriter<CycleDataType>::
+CycleDataStageWriter(CycleDataStageWriter<CycleDataType> &&from) noexcept :
+  _pointer(from._pointer)
+{
+  from._pointer = nullptr;
+}
+
 /**
  *
  */
@@ -236,6 +247,18 @@ operator = (const CycleDataStageWriter<CycleDataType> &copy) {
   _pointer = copy._pointer;
 }
 
+/**
+ *
+ */
+template<class CycleDataType>
+INLINE void CycleDataStageWriter<CycleDataType>::
+operator = (CycleDataStageWriter<CycleDataType> &&from) noexcept {
+  nassertv(_pointer == nullptr);
+
+  _pointer = from._pointer;
+  from._pointer = nullptr;
+}
+
 /**
  * This flavor of the constructor elevates the pointer from the
  * CycleDataLockedStageReader from a read to a write pointer (and invalidates

+ 1 - 1
panda/src/pipeline/pythonThread.cxx

@@ -225,7 +225,7 @@ call_python_func(PyObject *function, PyObject *args) {
 
     } else {
       // No exception.  Restore the thread state normally.
-      PyThreadState *state = PyThreadState_Swap(orig_thread_state);
+      PyThreadState_Swap(orig_thread_state);
       thread_states.push_back(new_thread_state);
       // PyThreadState_Clear(new_thread_state);
       // PyThreadState_Delete(new_thread_state);

+ 0 - 8
panda/src/pipeline/threadSimpleImpl.I

@@ -51,14 +51,6 @@ is_threading_supported() {
   return true;
 }
 
-/**
- *
- */
-INLINE bool ThreadSimpleImpl::
-is_true_threads() {
-  return (is_os_threads != 0);
-}
-
 /**
  *
  */

+ 11 - 3
panda/src/pipeline/threadSimpleImpl.cxx

@@ -141,8 +141,8 @@ start(ThreadPriority priority, bool joinable) {
 
 #ifdef HAVE_PYTHON
   // Query the current Python thread state.
-  _python_state = PyThreadState_Swap(nullptr);
-  PyThreadState_Swap(_python_state);
+  _python_state = thread_state_swap(nullptr);
+  thread_state_swap(_python_state);
 #endif  // HAVE_PYTHON
 
   init_thread_context(_context, _stack, _stack_size, st_begin_thread, this);
@@ -201,6 +201,14 @@ prepare_for_exit() {
   manager->prepare_for_exit();
 }
 
+/**
+ *
+ */
+bool ThreadSimpleImpl::
+is_true_threads() {
+  return (is_os_threads != 0);
+}
+
 /**
  *
  */
@@ -238,7 +246,7 @@ st_begin_thread(void *data) {
 void ThreadSimpleImpl::
 begin_thread() {
 #ifdef HAVE_PYTHON
-  PyThreadState_Swap(_python_state);
+  thread_state_swap(_python_state);
 #endif  // HAVE_PYTHON
 
 #ifdef HAVE_POSIX_THREADS

+ 1 - 1
panda/src/pipeline/threadSimpleImpl.h

@@ -63,7 +63,7 @@ public:
 
   INLINE static void bind_thread(Thread *thread);
   INLINE static bool is_threading_supported();
-  INLINE static bool is_true_threads();
+  static bool is_true_threads();
   INLINE static bool is_simple_threads();
   INLINE static void sleep(double seconds);
   INLINE static void yield();

+ 5 - 13
panda/src/pipeline/threadSimpleManager.cxx

@@ -20,7 +20,9 @@
 #include "mainThread.h"
 
 #ifdef WIN32
-#define WIN32_LEAN_AND_MEAN
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif
 #include <windows.h>
 #endif
 
@@ -235,7 +237,7 @@ next_context() {
 
 #ifdef HAVE_PYTHON
   // Save the current Python thread state.
-  _current_thread->_python_state = PyThreadState_Swap(nullptr);
+  _current_thread->_python_state = thread_state_swap(nullptr);
 #endif  // HAVE_PYTHON
 
 #ifdef DO_PSTATS
@@ -256,7 +258,7 @@ next_context() {
 #endif  // DO_PSTATS
 
 #ifdef HAVE_PYTHON
-  PyThreadState_Swap(_current_thread->_python_state);
+  thread_state_swap(_current_thread->_python_state);
 #endif  // HAVE_PYTHON
 }
 
@@ -468,16 +470,6 @@ init_pointers() {
     _pointers_initialized = true;
     _global_ptr = new ThreadSimpleManager;
     Thread::get_main_thread();
-
-#ifdef HAVE_PYTHON
-    // Ensure that the Python threading system is initialized and ready to go.
-
-#if PY_VERSION_HEX >= 0x03020000
-    Py_Initialize();
-#endif
-
-    PyEval_InitThreads();
-#endif
   }
 }
 

+ 1 - 1
panda/src/text/textNode.cxx

@@ -291,8 +291,8 @@ output(std::ostream &out) const {
  */
 void TextNode::
 write(std::ostream &out, int indent_level) const {
-  MutexHolder holder(_lock);
   PandaNode::write(out, indent_level);
+  MutexHolder holder(_lock);
   TextProperties::write(out, indent_level + 2);
   indent(out, indent_level + 2)
     << "transform is: " << *TransformState::make_mat(_transform) << "\n";

+ 5 - 5
panda/src/wgldisplay/wglGraphicsStateGuardian.cxx

@@ -778,9 +778,9 @@ register_twindow_class() {
 #define GAMMA_1 (255.0 * 256.0)
 
 static bool _gamma_table_initialized = false;
-static unsigned short _orignial_gamma_table [256 * 3];
+static unsigned short _original_gamma_table [256 * 3];
 
-void _create_gamma_table (PN_stdfloat gamma, unsigned short *original_red_table, unsigned short *original_green_table, unsigned short *original_blue_table, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table) {
+void _create_gamma_table_wgl (PN_stdfloat gamma, unsigned short *original_red_table, unsigned short *original_green_table, unsigned short *original_blue_table, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table) {
   int i;
   double gamma_correction;
 
@@ -842,7 +842,7 @@ get_gamma_table(void) {
     HDC hdc = GetDC(nullptr);
 
     if (hdc) {
-      if (GetDeviceGammaRamp (hdc, (LPVOID) _orignial_gamma_table)) {
+      if (GetDeviceGammaRamp (hdc, (LPVOID) _original_gamma_table)) {
         _gamma_table_initialized = true;
         get = true;
       }
@@ -867,10 +867,10 @@ static_set_gamma(bool restore, PN_stdfloat gamma) {
     unsigned short ramp [256 * 3];
 
     if (restore && _gamma_table_initialized) {
-      _create_gamma_table (gamma, &_orignial_gamma_table [0], &_orignial_gamma_table [256], &_orignial_gamma_table [512], &ramp [0], &ramp [256], &ramp [512]);
+      _create_gamma_table_wgl (gamma, &_original_gamma_table [0], &_original_gamma_table [256], &_original_gamma_table [512], &ramp [0], &ramp [256], &ramp [512]);
     }
     else {
-      _create_gamma_table (gamma, 0, 0, 0, &ramp [0], &ramp [256], &ramp [512]);
+      _create_gamma_table_wgl (gamma, 0, 0, 0, &ramp [0], &ramp [256], &ramp [512]);
     }
 
     if (SetDeviceGammaRamp (hdc, ramp)) {

+ 19 - 3
panda/src/windisplay/winGraphicsWindow.cxx

@@ -293,13 +293,29 @@ set_properties_now(WindowProperties &properties) {
       _properties.set_fixed_size(properties.get_fixed_size());
       properties.clear_fixed_size();
     }
+    // When switching undecorated mode, Windows will keep the window at the
+    // current outer size, whereas we want to keep it with the configured
+    // inner size.  Store the current size and origin.
+    LPoint2i top_left = _properties.get_origin();
+    LPoint2i bottom_right = top_left + _properties.get_size();
+
     DWORD window_style = make_style(_properties);
     SetWindowLong(_hWnd, GWL_STYLE, window_style);
 
+    // Now calculate the proper size and origin with the new window style.
+    RECT view_rect;
+    SetRect(&view_rect, top_left[0], top_left[1],
+            bottom_right[0], bottom_right[1]);
+    WINDOWINFO wi;
+    GetWindowInfo(_hWnd, &wi);
+    AdjustWindowRectEx(&view_rect, wi.dwStyle, FALSE, wi.dwExStyle);
+
     // We need to call this to ensure that the style change takes effect.
-    SetWindowPos(_hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
-      SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE |
-      SWP_FRAMECHANGED | SWP_NOSENDCHANGING | SWP_SHOWWINDOW);
+    SetWindowPos(_hWnd, HWND_NOTOPMOST, view_rect.left, view_rect.top,
+                 view_rect.right - view_rect.left,
+                 view_rect.bottom - view_rect.top,
+                 SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED |
+                 SWP_NOSENDCHANGING | SWP_SHOWWINDOW);
   }
 
   if (properties.has_title()) {

+ 2 - 0
pandatool/src/eggcharbase/eggBackPointer.cxx

@@ -13,6 +13,8 @@
 
 #include "eggBackPointer.h"
 
+#include "pnotify.h"
+
 
 TypeHandle EggBackPointer::_type_handle;
 

+ 1 - 0
pandatool/src/eggcharbase/eggCharacterDb.h

@@ -29,6 +29,7 @@
 */
 
 class EggJointPointer;
+class LMatrix4d;
 
 /**
  * This class is used during joint optimization or restructuring to store the

+ 2 - 0
pandatool/src/eggcharbase/eggJointData.cxx

@@ -12,6 +12,8 @@
  */
 
 #include "eggJointData.h"
+
+#include "eggCharacterDb.h"
 #include "eggJointNodePointer.h"
 #include "eggMatrixTablePointer.h"
 #include "pvector.h"

+ 2 - 1
pandatool/src/eggcharbase/eggJointNodePointer.cxx

@@ -14,8 +14,9 @@
 #include "eggJointNodePointer.h"
 
 #include "dcast.h"
-#include "eggObject.h"
+#include "eggCharacterDb.h"
 #include "eggGroup.h"
+#include "eggObject.h"
 #include "pointerTo.h"
 
 

+ 2 - 0
pandatool/src/eggcharbase/eggMatrixTablePointer.cxx

@@ -12,7 +12,9 @@
  */
 
 #include "eggMatrixTablePointer.h"
+
 #include "dcast.h"
+#include "eggCharacterDb.h"
 #include "eggSAnimData.h"
 #include "eggXfmAnimData.h"
 #include "eggXfmSAnim.h"

+ 1 - 0
pandatool/src/palettizer/paletteGroup.cxx

@@ -17,6 +17,7 @@
 #include "textureImage.h"
 #include "palettizer.h"
 #include "paletteImage.h"
+#include "sourceTextureImage.h"
 
 #include "indent.h"
 #include "datagram.h"

+ 0 - 55
pandatool/src/softegg/config_softegg.cxx

@@ -1,55 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file config_softegg.cxx
- * @author masad
- * @date 2003-09-25
- */
-
-#include "config_softegg.h"
-#include "softEggGroupUserData.h"
-#include "softNodeDesc.h"
-
-#include "dconfig.h"
-
-Configure(config_softegg);
-NotifyCategoryDef(softegg, ":soft");
-
-ConfigureFn(config_softegg) {
-  init_libsoftegg();
-}
-
-// These control the default behavior of the softegg converter, but not
-// necessarily the default behavior of the soft2egg command-line tool (which
-// has its own defaults).
-
-// Should we respect the Soft?  double-sided flag (true) or ignore it and
-// assume everything is single-sided (false)?
-ConfigVariableBool soft_default_double_sided("soft-default-double-sided", false);
-
-// Should we apply vertex color even when a texture is applied (true) or only
-// when no texture is applied or the vertex-color egg flag is set (false)?
-ConfigVariableBool soft_default_vertex_color("soft-default-vertex-color", true);
-
-/**
- * Initializes the library.  This must be called at least once before any of
- * the functions or classes in this library can be used.  Normally it will be
- * called by the static initializers and need not be called explicitly, but
- * special cases exist.
- */
-void
-init_libsoftegg() {
-  static bool initialized = false;
-  if (initialized) {
-    return;
-  }
-  initialized = true;
-
-  SoftEggGroupUserData::init_type();
-  SoftNodeDesc::init_type();
-}

+ 0 - 28
pandatool/src/softegg/config_softegg.h

@@ -1,28 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file config_softegg.h
- * @author masad
- * @date 2003-09-25
- */
-
-#ifndef CONFIG_SOFTEGG_H
-#define CONFIG_SOFTEGG_H
-
-#include "pandatoolbase.h"
-#include "notifyCategoryProxy.h"
-#include "configVariableBool.h"
-
-NotifyCategoryDeclNoExport(softegg);
-
-extern ConfigVariableBool soft_default_double_sided;
-extern ConfigVariableBool soft_default_vertex_color;
-
-extern void init_libsoftegg();
-
-#endif

+ 0 - 4751
pandatool/src/softegg/soft2Egg.c

@@ -1,4751 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file soft2Egg.c
- * @author masad
- * @date 2003-09-26
- */
-
-#include <SAA.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "pandatoolbase.h"
-
-int init_soft2egg(int, char **);
-
-#if 0
-// DWD includes
-#include "eggBase.h"
-#include <eggParametrics.h>
-#include <animTable.h>
-#include <linMathOutput.h>
-
-// system includes
-#include <fstream.h>
-#include <strstream.h>
-#include <math.h>
-#include <assert.h>
-#include <unistd.h>
-#include <ieeefp.h>
-
-// Performer includes
-#include <Performer/pr/pfLinMath.h>
-
-// SoftImage includes
-#include <SAA.h>
-#include <SI_macros.h>
-
-static const int    TEX_PER_MAT = 1;
-static FILE            *outStream  = stdout;
-// static FILE        *outStream  = stderr;
-
-class soft2egg : public EggBase
-{
-  public:
-
-    soft2egg() : EggBase("r:d:s:m:t:P:b:e:f:T:S:M:A:N:v:o:FhknpaxiucCD")
-    {
-        rsrc_path = "/ful/ufs/soft371_mips2/3D/rsrc";
-        database_name = NULL;
-        scene_name = NULL;
-        model_name = NULL;
-        animFileName = NULL;
-        eggFileName = NULL;
-        tex_path = NULL;
-        eggGroupName = NULL;
-        tex_filename = NULL;
-        search_prefix = NULL;
-        result = SI_SUCCESS;
-
-        skeleton = new EggGroup();
-        foundRoot = FALSE;
-        animRoot = NULL;
-        morphRoot = NULL;
-        geom_as_joint = 0;
-        make_anim = 0;
-        make_nurbs = 0;
-        make_poly = 0;
-        make_soft = 0;
-        make_morph = 1;
-        make_duv = 1;
-        make_dart = TRUE;
-        has_morph = 0;
-        make_pose = 0;
-        animData.is_z_up = FALSE;
-        nurbs_step = 1;
-        anim_start = -1000;
-        anim_end = -1000;
-        anim_rate = 24;
-        pose_frame = -1;
-        verbose = 0;
-        flatten = 0;
-        shift_textures = 0;
-        ignore_tex_offsets = 0;
-        use_prefix = 0;
-    }
-
-    virtual void Help();
-    virtual void Usage();
-    virtual void ShowOpts();
-
-    virtual boolean UseOutputSwitch() const {
-       return false;
-    }
-
-    virtual boolean
-    HandleGetopts(char flag, char *optarg, int &optind, int argc, char **argv);
-
-    int   isNum( float );
-    char *GetRootName( const char * );
-    char *RemovePathName( const char * );
-    char *GetSliderName( const char * );
-    char *GetFullName( SAA_Scene *, SAA_Elem * );
-    char *GetName( SAA_Scene *, SAA_Elem * );
-    char *GetModelNoteInfo( SAA_Scene *, SAA_Elem * );
-    char *MakeTableName( const char *, int );
-    char *DepointellizeName( char * );
-    SAA_Elem *FindModelByName( char *, SAA_Scene *, SAA_Elem *, int );
-    char *ConvertTexture( SAA_Scene *, SAA_Elem * );
-    int  *FindClosestTriVert( EggVertexPool *, SAA_DVector *, int );
-    int  *MakeIndexMap( int *, int, int );
-    int     findShapeVert( SAA_DVector, SAA_DVector *, int );
-    void LoadSoft();
-    void MakeEgg( EggGroup *, EggJoint *, AnimGroup *, SAA_Scene *, SAA_Elem * );
-    void MakeSurfaceCurve(  SAA_Scene *, SAA_Elem *, EggGroup *,
-        EggNurbsSurface *&, int , SAA_SubElem *, bool );
-
-    EggNurbsCurve *MakeUVNurbsCurve( int, long *,  double *, double *,
-        EggGroup *, char * );
-
-    EggNurbsCurve *MakeNurbsCurve( SAA_Scene *, SAA_Elem *, EggGroup *,
-        float [4][4], char * );
-
-    void AddKnots( perf_vector<double> &, double *, int, SAA_Boolean, int );
-    void MakeJoint( SAA_Scene *, EggJoint *&, AnimGroup *&, SAA_Elem *, char * );
-    void MakeSoftSkin( SAA_Scene *, SAA_Elem *, SAA_Elem *, int, char * );
-    void CleanUpSoftSkin( SAA_Scene *, SAA_Elem *, char * );
-    void MakeAnimTable( SAA_Scene *, SAA_Elem *, char * );
-    void MakeVertexOffsets( SAA_Scene *, SAA_Elem *, SAA_ModelType type,
-        int, int, SAA_DVector *, float (*)[4], char * );
-    void MakeMorphTable( SAA_Scene *, SAA_Elem *, SAA_Elem *, int,  char *,
-        float );
-    void MakeLinearMorphTable( SAA_Scene *, SAA_Elem *, int, char *, float );
-    void MakeWeightedMorphTable( SAA_Scene *, SAA_Elem *, SAA_Elem *, int,
-        int, char *, float );
-    void MakeExpressionMorphTable( SAA_Scene *, SAA_Elem *, SAA_Elem *, int,
-        int, char *, float );
-    void MakeTexAnim( SAA_Scene *, SAA_Elem *, char * );
-
-  private:
-
-    char        *rsrc_path;
-    char        *database_name;
-    char        *scene_name;
-    char        *model_name;
-    char        *eggFileName;
-    char         *animFileName;
-    char         *eggGroupName;
-    char        *tex_path;
-    char        *tex_filename;
-    char        *search_prefix;
-
-    SI_Error            result;
-    SAA_Scene           scene;
-    SAA_Elem            model;
-    SAA_Database        database;
-    EggGroup           *dart;
-    EggGroup           *skeleton;
-    AnimGroup          *rootAnim;
-    EggJoint           *rootJnt;
-    AnimGroup          *animRoot;
-    AnimGroup          *morphRoot;
-    EggData             animData;
-
-    int                    nurbs_step;
-    int                    anim_start;
-    int                    anim_end;
-    int                    anim_rate;
-    int                    pose_frame;
-    int                    verbose;
-    int                    flatten;
-    int                    shift_textures;
-    int                    ignore_tex_offsets;
-    int                    use_prefix;
-
-    bool                foundRoot;
-    bool                geom_as_joint;
-    bool                make_anim;
-    bool                make_nurbs;
-    bool                make_poly;
-    bool                make_soft;
-    bool                make_morph;
-    bool                make_duv;
-    bool                make_dart;
-    bool                has_morph;
-    bool                make_pose;
-
-    std::ofstream eggFile;
-    std::ofstream animFile;
-    std::ofstream texFile;
-};
-
-
-/**
- * Displays the "what is this program" message, along with the usage message.
- * Should be overridden in base classes to describe the current program.
- */
-void soft2egg::
-Help()
-{
-    cerr <<
-    "soft2egg takes a SoftImage scene or model\n"
-    "and outputs its contents as an egg file\n";
-
-    Usage();
-}
-
-/**
- * Displays the usage message.
- */
-void soft2egg::
-Usage() {
-  cerr << "\nUsage:\n"
-       << _commandName << " [opts] (must specify -m or -s)\n\n"
-       << "Options:\n";
-
-  ShowOpts();
-  cerr << "\n";
-}
-
-
-
-/**
- * Displays the valid options.  Should be extended in base classes to show
- * additional options relevant to the current program.
- */
-void soft2egg::
-ShowOpts()
-{
-    cerr <<
-    "  -r <path>  - Used to provide soft with the resource\n"
-    "               Defaults to 'c:/Softimage/SOFT_3.9.2/3D/test'.\n"
-      // "               Defaults to 'fulufssoft371_mips23Drsrc'.\n"
-    "  -d <path>  - Database path.\n"
-    "  -s <scene> - Indicates that a scene will be converted.\n"
-    "  -m <model> - Indicates that a model will be converted.\n"
-    "  -t <path>  - Specify path to place converted textures.\n"
-    "  -T <name>  - Specify filename for texture map listing.\n"
-    "  -S <step>  - Specify step for nurbs surface triangulation.\n"
-    "  -M <name>  - Specify model output filename. Defaults to scene name.\n"
-    "  -A <name>  - Specify anim output filename. Defaults to scene name.\n"
-    "  -N <name>  - Specify egg group name.\n"
-    "  -k         - Enable soft assignment for geometry.\n"
-    "  -n         - Specify egg NURBS representation instead of poly's.\n"
-    "  -p         - Specify egg polygon output for geometry.\n"
-    "  -P <frame> - Specify frame number for static pose.\n"
-    "  -b <frame> - Specify starting frame for animation (default = first).\n"
-    "  -e <frame> - Specify ending frame for animation (default = last).\n"
-    "  -f <fps>   - Specify frame rate for animation playback.\n"
-    "  -a         - Compile animation tables if animation present.\n"
-    "  -F         - Ignore hierarchy and build a completely flat skeleton.\n"
-    "  -v <level> - Set debug level.\n"
-    "  -x         - Shift NURBS parameters to preserve Alias textures.\n"
-    "  -i         - Ignore Soft texture uv offsets.\n"
-    "  -u         - Use Soft prefix in model names.\n"
-    "  -c         - Cancel morph conversion.\n"
-    "  -C         - Cancel duv conversion.\n"
-    "  -D         - Don't make the output model a character.\n"
-    "  -o <prefix>- Convert only models with given prefix.\n";
-
-      EggBase::ShowOpts();
-}
-
-
-/**
- *
- */
-boolean soft2egg::
-HandleGetopts(char flag, char *optarg, int &optind, int argc, char **argv)
-{
-    boolean okflag = true;
-
-    switch (flag)
-    {
-      case 'r':       // Set the resource path for soft.
-        if ( strcmp( optarg, "" ) )
-        {
-            // Get the path.
-            rsrc_path = optarg;
-            fprintf( outStream, "using rsrc path %s\n", rsrc_path );
-        }
-        break;
-
-    case 'd':       // Set the database path.
-        if ( strcmp( optarg, "" ) )
-        {
-            // Get the path.
-            database_name = optarg;
-            fprintf( outStream, "using database %s\n", database_name );
-        }
-        break;
-
-    case 's':     // Check if its a scene.
-        if ( strcmp( optarg, "" ) )
-        {
-            // Get scene name.
-            scene_name = optarg;
-            fprintf( outStream, "loading scene %s\n", scene_name );
-        }
-        break;
-
-    case 'm':     // Check if its a model.
-        if ( strcmp( optarg, "" ) )
-        {
-            // Get model name.
-            model_name = optarg;
-            fprintf( outStream, "loading model %s\n", model_name );
-        }
-        break;
-
-    case 't':     // Get converted texture path.
-        if ( strcmp( optarg, "" ) )
-        {
-            // Get tex path name.
-            tex_path = optarg;
-            fprintf( outStream, "texture path:  %s\n", tex_path );
-        }
-        break;
-
-    case 'T':      // Specify texture list filename.
-        if ( strcmp( optarg, "") )
-        {
-            // Get the name.
-            tex_filename = optarg;
-            fprintf( outStream, "creating texture list file: %s\n",
-                tex_filename );
-        }
-        break;
-    case 'S':     // Set NURBS step.
-        if ( strcmp( optarg, "" ) )
-        {
-            nurbs_step = atoi(optarg);
-            fprintf( outStream, "NURBS step:  %d\n", nurbs_step );
-        }
-        break;
-
-    case 'M':     // Set model output file name.
-        if ( strcmp( optarg, "" ) )
-        {
-            eggFileName = optarg;
-            fprintf( outStream, "Model output filename:  %s\n", eggFileName );
-        }
-        break;
-
-    case 'A':     // Set anim output file name.
-        if ( strcmp( optarg, "" ) )
-        {
-            animFileName = optarg;
-            fprintf( outStream, "Anim output filename:  %s\n", animFileName );
-        }
-        break;
-
-    case 'N':     // Set egg model name.
-        if ( strcmp( optarg, "" ) )
-        {
-            eggGroupName = optarg;
-            fprintf( outStream, "Egg group name:  %s\n", eggGroupName );
-        }
-        break;
-
-    case 'o':     // Set search_prefix.
-        if ( strcmp( optarg, "" ) )
-        {
-            search_prefix = optarg;
-            fprintf( outStream, "Only converting models with prefix:  %s\n",
-                search_prefix );
-        }
-        break;
-
-    case 'h':    // print help message
-        Help();
-        exit(1);
-        break;
-
-    case 'c':    // Cancel morph animation conversion
-        make_morph = FALSE;
-        fprintf( outStream, "canceling morph conversion\n" );
-        break;
-
-    case 'C':    // Cancel uv animation conversion
-        make_duv = FALSE;
-        fprintf( outStream, "canceling uv animation conversion\n" );
-        break;
-
-    case 'D':    // Omit the Dart flag
-        make_dart = FALSE;
-        fprintf( outStream, "making a non-character model\n" );
-        break;
-
-    case 'k':    // Enable soft skinning
-        // make_soft = TRUE; fprintf( outStream, "enabling soft skinning\n" );
-        fprintf( outStream, "-k flag no longer necessary\n" );
-        break;
-
-    case 'n':    // Generate egg NURBS output
-        make_nurbs = TRUE;
-        fprintf( outStream, "outputting egg NURBS info\n" );
-        break;
-
-    case 'p':    // Generate egg polygon output
-        make_poly = TRUE;
-        fprintf( outStream, "outputting egg polygon info\n" );
-        break;
-
-    case 'P':    // Generate static pose from given frame
-        if ( strcmp( optarg, "" ) )
-        {
-            make_pose = TRUE;
-            pose_frame = atoi(optarg);
-            fprintf( outStream, "generating static pose from frame %d\n",
-                pose_frame );
-        }
-        break;
-
-    case 'a':     // Compile animation tables.
-        make_anim = TRUE;
-        fprintf( outStream, "attempting to compile anim tables\n" );
-        break;
-
-    case 'F':     // Build a flat skeleton.
-        flatten = TRUE;
-        fprintf( outStream, "building a flat skeleton!!!\n" );
-        break;
-
-    case 'x':     // Shift NURBS parameters to preserve Alias textures.
-        shift_textures = TRUE;
-        fprintf( outStream, "shifting NURBS parameters...\n" );
-        break;
-
-    case 'i':     // Ignore Soft uv texture offsets
-        ignore_tex_offsets = TRUE;
-        fprintf( outStream, "ignoring texture offsets...\n" );
-        break;
-
-    case 'u':     // Use Soft prefix in model names
-        use_prefix = TRUE;
-        fprintf( outStream, "using prefix in model names...\n" );
-        break;
-
-
-    case 'v':     // print debug messages.
-        if ( strcmp( optarg, "" ) )
-        {
-            verbose = atoi(optarg);
-            fprintf( outStream, "using debug level %d\n", verbose );
-        }
-        break;
-
-    case 'b':     // Set animation start frame.
-        if ( strcmp( optarg, "" ) )
-        {
-            anim_start = atoi(optarg);
-            fprintf( outStream, "animation starting at frame:  %d\n",
-                anim_start );
-        }
-        break;
-
-    case 'e':     /// Set animation end frame.
-        if ( strcmp( optarg, "" ) )
-        {
-            anim_end = atoi(optarg);
-            fprintf( outStream, "animation ending at frame:  %d\n", anim_end );
-        }
-        break;
-
-    case 'f':     /// Set animation frame rate.
-        if ( strcmp( optarg, "" ) )
-        {
-            anim_rate = atoi(optarg);
-            fprintf( outStream, "animation frame rate:  %d\n", anim_rate );
-        }
-        break;
-
-    default:
-        okflag = EggBase::HandleGetopts(flag, optarg, optind, argc, argv);
-  }
-
-  return (okflag);
-}
-
-
-
-/**
- * Take a float and make sure it is of the body.
- */
-int soft2egg::
-isNum( float num )
-{
-    return( ( num < HUGE_VAL ) && finite( num ) );
-}
-
-
-/**
- * Given a string, return a copy of the string up to the first occurrence of
- * '-'.
- */
-char *soft2egg::
-GetRootName( const char *name )
-{
-    char *hyphen;
-    char *root;
-    int      len;
-
-    hyphen = strchr( name, '-' );
-    len = hyphen-name;
-
-    if ( (hyphen != NULL) && len )
-    {
-        root = (char *)malloc(sizeof(char)*(len+1));
-        strncpy( root, name, len );
-        root[sizeof(char)*(len)] = '\0';
-    }
-    else
-    {
-        root = (char *)malloc( sizeof(char)*(strlen(name)+1));
-        strcpy( root, name );
-    }
-
-    return( root );
-}
-
-
-/**
- * Given a string, return a copy of the string after the last occurence of '
- */
-char *soft2egg::
-RemovePathName( const char *name )
-{
-    char *slash;
-    char *root;
-
-    if ( *name != NULL )
-    {
-        slash = strrchr( name, '/' );
-
-        root = (char *)malloc( sizeof(char)*(strlen(name)+1));
-
-        if ( slash != NULL )
-            strcpy( root, ++slash );
-        else
-            strcpy( root, name );
-
-        return( root );
-    }
-
-    fprintf( stderr, "Error: RemovePathName received NULL string!\n" );
-    return ( (char *)name );
-}
-
-/**
- * Given a string, return that part of the string after the first occurence of
- * '-' and before the last occurance of '.'
- */
-char *soft2egg::
-GetSliderName( const char *name )
-{
-    if ( name != NULL )
-    {
-        strstream newStr;
-        char *hyphen;
-        char *end;
-
-        hyphen = strchr( name, '-' );
-
-        // pull off stuff before first hyphen
-        if (hyphen != NULL)
-        {
-            newStr << ++hyphen;
-            end = newStr.str();
-        }
-
-        char *lastPeriod;
-
-        lastPeriod = strrchr( end, '.' );
-
-        // ignore stuff after last period
-        if ( lastPeriod != NULL )
-        {
-            *lastPeriod = '\0';
-        }
-
-        if ( verbose >= 1 )
-            fprintf( stdout, "slider name: '%s'\n", end );
-
-        return( end );
-    }
-
-    return( (char *)name );
-}
-
-/**
- * Given an element, return a copy of the element's name WITHOUT prefix.
- */
-char *soft2egg::
-GetName( SAA_Scene *scene, SAA_Elem *element )
-{
-    int    nameLen;
-    char *name;
-
-    // get the name
-    SAA_elementGetNameLength( scene, element, &nameLen );
-    name = (char *)malloc(sizeof(char)*++nameLen);
-    SAA_elementGetName( scene, element, nameLen, name );
-
-    return name;
-}
-
-/**
- * Given an element, return a copy of the element's name complete with prefix.
- */
-char *soft2egg::
-GetFullName( SAA_Scene *scene, SAA_Elem *element )
-{
-    int    nameLen;
-    char *name;
-
-    // get the name
-    SAA_elementGetNameLength( scene, element, &nameLen );
-    name = (char *)malloc(sizeof(char)*++nameLen);
-    SAA_elementGetName( scene, element, nameLen, name );
-
-    int prefixLen;
-    char *prefix;
-
-    // get the prefix
-    SAA_elementGetPrefixLength( scene, element, &prefixLen );
-    prefix = (char *)malloc(sizeof(char)*++prefixLen);
-    SAA_elementGetPrefix( scene, element, prefixLen, prefix );
-
-    strstream fullNameStrm;
-
-    // add 'em together
-    fullNameStrm << prefix << "-" << name << ends;
-
-    // free( name ); free( prefix );
-
-    return fullNameStrm.str();
-}
-
-/**
- * Given an element, return a string containing the contents of its MODEL NOTE
- * entry
- */
-char *soft2egg::
-GetModelNoteInfo( SAA_Scene *scene, SAA_Elem *model )
-{
-
-    int         size;
-    char     *modelNote = NULL;
-    SAA_Boolean bigEndian;
-
-
-    SAA_elementGetUserDataSize( scene, model, "MNOT", &size );
-
-    if ( size != 0 )
-    {
-        // allocate modelNote string
-        modelNote = (char *)malloc(sizeof(char)*(size + 1));
-
-        // get ModelNote data from this model
-        SAA_elementGetUserData( scene, model, "MNOT", size,
-            &bigEndian, (void *)modelNote );
-
-        // strip off newline, if present
-        char *eol = strchr( modelNote, '\n' );
-        if ( eol != NULL)
-            *eol = '\0';
-        else
-            modelNote[size] = '\0';
-
-        if ( verbose >= 1 )
-            fprintf( outStream, "\nmodelNote = %s\n",
-                modelNote );
-    }
-
-    return modelNote;
-}
-
-
-/**
- * Given a string, and a number, return a new string consisting of
- * "string.number".
- */
-char *soft2egg::
-MakeTableName( const char *name, int number )
-{
-    strstream namestrm;
-
-    namestrm << name << "." << number << ends;
-    return namestrm.str();
-}
-
-/**
- * Given a string, find the model in the scene whose name corresponds to the
- * given string.
- */
-SAA_Elem *soft2egg::
-FindModelByName( char *name, SAA_Scene *scene, SAA_Elem *models,
-    int numModels )
-{
-    char     *foundName;
-    SAA_Elem *foundModel = NULL;
-
-    for ( int model = 0; model < numModels; model++ )
-    {
-        foundName = GetName( scene, &models[model] );
-
-        if ( !strcmp( name, foundName ) )
-        {
-            if ( verbose >= 1 )
-                fprintf( outStream, "foundModel: '%s' = '%s'\n",
-                    name, foundName );
-
-            foundModel = &models[model];
-            return( foundModel );
-        }
-    }
-
-    fprintf( outStream, "findModelByName: failed to find model named: '%s'\n",
-        name );
-
-    return ( foundModel );
-}
-
-
-/**
- * Given a string, return the string up to the first period.
- */
-char *soft2egg::
-DepointellizeName( char *name )
-{
-    char    *endPtr;
-    char    *newName;
-
-    newName = (char *)malloc(sizeof(char)*(strlen(name)+1));
-    sprintf( newName, "%s", name );
-
-    endPtr = strchr( newName, '.' );
-    if ( endPtr != NULL )
-      *endPtr = '\0';
-
-    return ( newName );
-}
-
-
-/**
- * Given a string, return a copy of the string without the leading file path,
- * and make an rgb file of the same name in the tex_path directory.
- */
-char *soft2egg::
-ConvertTexture( SAA_Scene *scene, SAA_Elem *texture )
-{
-  char *fileName = NULL;
-  int  fileNameLen = 0;
-
-  // get the texture's name
-  SAA_texture2DGetPicNameLength( scene, texture, &fileNameLen);
-
-  if ( fileNameLen )
-  {
-        fileName = (char *)malloc(sizeof(char)*++fileNameLen);
-        SAA_texture2DGetPicName( scene, texture, fileNameLen, fileName );
-  }
-
-  // make sure we are not being passed a NULL image, an empty image string or
-  // the default image created by egg2soft
-  if ( (fileName != NULL) && strlen( fileName ) && strcmp( fileName,
-        "/fat/people/gregw/new_test/PICTURES/default") &&
-                                ( strstr( fileName, "noIcon" ) == NULL) )
-  {
-    char *texName = NULL;
-    char *texNamePath = NULL;
-    char *tmpName = NULL;
-    char *fileNameExt = NULL;
-
-    // strip off path and add .rgb
-    tmpName = strrchr( fileName, '/' );
-
-    if ( tmpName == NULL )
-        tmpName = fileName;
-    else
-        tmpName++;
-
-    float transp;
-
-        // check for alpha
-        SAA_texture2DGetTransparency( scene, texture, &transp );
-
-        if ( transp != 0.0f ) {
-        texName = (char *)malloc(sizeof(char)*(strlen(tmpName)+6));
-        sprintf( texName, "%s.rgba", tmpName );
-        } else {
-        texName = (char *)malloc(sizeof(char)*(strlen(tmpName)+5));
-        sprintf( texName, "%s.rgb", tmpName );
-        }
-
-    fileNameExt = (char *)malloc(sizeof(char)*(strlen(fileName)+5));
-    sprintf( fileNameExt, "%s.pic", fileName );
-
-    if ( verbose >= 1 )
-        fprintf( outStream, "Looking for texture file: '%s'\n", fileNameExt );
-
-    // try to make conversion of file
-    int found_file = ( access( fileNameExt, F_OK ) == 0);
-
-    if ( found_file )
-    {
-        if ( tex_path )
-        {
-            texNamePath = (char *)malloc(sizeof(char)*(strlen(tex_path) +
-                strlen(texName) + 2));
-
-            sprintf( texNamePath, "%s/%s", tex_path, texName );
-
-            if ( texFile )
-                texFile << texNamePath << ": " << fileNameExt << "\n";
-
-            // make sure conversion doesn't already exist
-            if ( (access( texNamePath, F_OK ) != 0)  && !texFile )
-            {
-                char *command = (char *)malloc(sizeof(char)*
-                    (strlen(fileNameExt) + strlen(texNamePath) + 20));
-
-                sprintf( command, "image-resize -1 %s %s",
-                    fileNameExt, texNamePath );
-
-                if ( verbose >=1 )
-                    fprintf( outStream, "executing %s\n", command );
-
-                system( command );
-
-                // free( command );
-            }
-            else
-                if ( verbose >=1 )
-                    fprintf( outStream, "%s already exists!\n", texNamePath );
-        }
-        else
-        {
-            if ( verbose >= 1 )
-            {
-                fprintf( outStream, "Warning: No texture path defined" );
-                fprintf( outStream, " - No automatic conversion performed\n" );
-            }
-        }
-    }
-    else
-    {
-        fprintf( outStream, "Warning: Couldn't find texture file: %s\n",
-            fileNameExt );
-    }
-
-    // free( fileNameExt );
-
-    if (tex_path)
-        return( texNamePath );
-    else
-        return( texName );
-  }
-  else
-  {
-    fprintf( outStream, "Warning: ConvertTexture received NULL fileName\n" );
-    return( NULL );
-  }
-}
-
-/**
- * Given an egg vertex pool, map each vertex therein to a vertex within an
- * array of SAA model vertices of size numVert.  Mapping is done by closest
- * proximity.
- */
-int *soft2egg::
-FindClosestTriVert( EggVertexPool *vpool, SAA_DVector *vertices, int numVert )
-{
-    int    *vertMap = NULL;
-    int     vpoolSize = vpool->NumVertices();
-    int     i,j;
-    float   thisDist;
-    float   closestDist;
-    int     closest;
-
-
-    vertMap = (int *)malloc(sizeof(int)*vpoolSize);
-
-    // for each vertex in vpool
-    for ( i = 0; i < vpoolSize; i++ )
-    {
-        // find closest model vertex
-        for ( j = 0; j < numVert-1; j++ )
-        {
-            // calculate distance
-            thisDist =    sqrtf(
-                powf( vpool->Vertex(i)->position[0] - vertices[j].x , 2 ) +
-                powf( vpool->Vertex(i)->position[1] - vertices[j].y , 2 ) +
-                powf( vpool->Vertex(i)->position[2] - vertices[j].z , 2 ) );
-
-            // remember this if its the closest so far
-            if ( !j || ( thisDist < closestDist ) )
-            {
-                closest = j;
-                closestDist = thisDist;
-            }
-        }
-        vertMap[i] = closest;
-
-        if ( verbose >= 2 )
-        {
-            fprintf( outStream, "mapping v %d of %d:( %f, %f, %f )\n", i,
-                vpoolSize, vpool->Vertex(i)->position[0],
-                vpool->Vertex(i)->position[1],
-                vpool->Vertex(i)->position[2] );
-            fprintf( outStream, "to cv %d of %d:( %f, %f, %f )\tdelta = %f\n",
-                closest, numVert-1, vertices[closest].x, vertices[closest].y,
-                vertices[closest].z, closestDist );
-        }
-                }
-
-        return( vertMap );
-}
-
-
-/**
- * Given an array of indices that is a map from one set of vertices to
- * another, return an array that performs the reverse mapping of the indices
- * array
- */
-int *soft2egg::
-MakeIndexMap( int *indices, int numIndices, int mapSize )
-{
-    int i, j;
-
-    // allocate map array
-    int *map = (int *)malloc(sizeof(int)*mapSize);
-
-    if ( map != NULL )
-    {
-        for ( i = 0; i < mapSize; i++ )
-        {
-            j = 0;
-            int found = 0;
-            while( j < numIndices )
-            {
-                if ( indices[j] == i )
-                {
-                    map[i] = j;
-                    if ( verbose >= 2 )
-                        fprintf( outStream, "map[%d] = %d\n", i, map[i] );
-                    found = 1;
-                    break;
-                }
-                j++;
-            }
-            if ( !found)
-            {
-                if ( verbose >= 2 )
-                    fprintf( outStream, "Warning: orphan vertex (%d)\n", i );
-                // default to -1 for now
-                map[i] = -1;
-            }
-        }
-    }
-    else
-        fprintf( outStream, "Not enough Memory for index Map...\n");
-
-    return( map );
-}
-
-/**
- * given a vertex, find its corresponding shape vertex and return its index.
- */
-int     soft2egg::
-findShapeVert( SAA_DVector vertex, SAA_DVector *vertices, int numVert )
-{
-    int i;
-    int found = 0;
-
-    for ( i = 0; i < numVert && !found ; i++ )
-    {
-        if ( ( vertex.x == vertices[i].x ) &&
-             ( vertex.y == vertices[i].y ) &&
-             ( vertex.z == vertices[i].z ) )
-        {
-            found = 1;
-
-            if ( verbose >= 2)
-                fprintf( outStream, "found shape vert at index %d\n", i );
-        }
-    }
-
-    if (!found )
-        i = -1;
-    else
-        i--;
-
-    return( i );
-}
-
-
-/**
- * Open the SI database and grab the scene & model info
- */
-void soft2egg::
-LoadSoft()
-{
-    int      i;
-
-    if ( (scene_name == NULL && model_name == NULL) || database_name == NULL )
-    {
-        Usage();
-        exit( 1 );
-    }
-
-    if ((result = SAA_Init(rsrc_path, FALSE)) != SI_SUCCESS)
-    {
-        fprintf( outStream, "Error: Couldn't get resource path!\n");
-        exit( 1 );
-    }
-
-    if ((result = SAA_databaseLoad(database_name, &database)) != SI_SUCCESS)
-    {
-        fprintf( outStream, "Error: Couldn't load database!\n");
-        exit( 1 );
-    }
-
-    if ((result = SAA_sceneGetCurrent(&scene)) == SI_SUCCESS)
-    {
-        // load scene if present
-        if ( scene_name != NULL )
-        {
-            SAA_sceneLoad( &database, scene_name, &scene );
-
-            // if no egg filename specified, make up a name
-            if ( eggFileName == NULL )
-            {
-                eggFileName = (char *)malloc(sizeof(char)*
-                    (strlen( scene_name ) + 14 ));
-                sprintf( eggFileName, "%s", DepointellizeName(scene_name) );
-                if ( make_nurbs )
-                    strcat( eggFileName, "-nurb" );
-                strcat( eggFileName, "-mod.egg" );
-            }
-
-            // open an output file for the geometry if necessary
-            if ( make_poly || make_nurbs )
-            {
-                unlink( eggFileName );
-                eggFile.open( eggFileName, ios::out, 0666 );
-
-                if ( !eggFile )
-                {
-                    fprintf( outStream, "Couldn't open output file: %s\n",
-                        eggFileName );
-                    exit( 1 );
-                }
-            }
-
-            // open an output file for texture list if specified
-            if ( tex_filename != NULL )
-            {
-                unlink( tex_filename );
-                texFile.open( tex_filename, ios::out, 0666 );
-
-                if ( !texFile )
-                {
-                    fprintf( outStream, "Couldn't open output file: %s\n",
-                        tex_filename );
-                    exit( 1 );
-                }
-            }
-
-            if ( SAA_updatelistGet( &scene ) == SI_SUCCESS )
-            {
-                float time;
-
-                fprintf( outStream, "setting Scene to frame %d...\n", pose_frame );
-                // SAA_sceneSetPlayCtrlCurrentFrame( &scene, pose_frame );
-                SAA_frame2Seconds( &scene, pose_frame, &time );
-                SAA_updatelistEvalScene( &scene, time );
-                sginap( 100 );
-                SAA_updatelistEvalScene( &scene, time );
-                if ( make_pose )
-                    SAA_sceneFreeze( &scene );
-            }
-
-            int            numModels;
-            SAA_Elem    *models;
-
-            SAA_sceneGetNbModels( &scene, &numModels );
-            fprintf( outStream, "Scene has %d model(s)...\n", numModels );
-
-            if ( numModels )
-            {
-                // allocate array of models
-                models = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numModels);
-
-                if ( models != NULL )
-                {
-                    char *rootName = GetRootName( eggFileName );
-
-                    if ( eggGroupName == NULL )
-                        dart = _data.CreateGroup( NULL, rootName );
-                    else
-                        dart = _data.CreateGroup( NULL, eggGroupName );
-
-                    if (make_dart)
-                      dart->flags |= EF_DART;
-
-                    AnimGroup    *rootTable;
-
-                    rootTable = animData.CreateTable( NULL, eggFileName );
-
-                    if ( eggGroupName == NULL )
-                        animRoot = animData.CreateBundle( rootTable, rootName );
-                    else
-                        animRoot = animData.CreateBundle( rootTable,
-                            eggGroupName );
-
-                    // propagate commet to anim data
-                    animData.root_group.children.push_front(
-                        new EggComment( _commandLine ) );
-
-                    if ( verbose >= 1 )
-                        fprintf( outStream, "made animRoot: %s\n", rootName );
-
-                    SAA_sceneGetModels( &scene, numModels, models );
-
-                    for ( i = 0; i < numModels; i++ )
-                    {
-                        int level;
-
-                        SAA_elementGetHierarchyLevel( &scene, &models[i], &level );
-                        if ( !level )
-                        {
-                            if ( verbose >= 1 )
-                                fprintf( outStream,
-                                    "\negging scene model[%d]\n", i );
-
-                            MakeEgg( dart, NULL, NULL,  &scene, &models[i] );
-                        }
-                    }
-
-            if ( make_poly || make_nurbs )
-            {
-                // generate soft skinning assignments if desired disabled 1199
-                // to streamline joint assignments.  all joint assignments now
-                // done here.  Hard & Soft.  if ( make_soft)
-                {
-                    char        *name;
-                    char        *fullname;
-                    SAA_Boolean isSkeleton;
-
-                    // search through models and look for skeleton parts
-                    for ( i = 0; i < numModels; i++ )
-                    {
-                        SAA_modelIsSkeleton( &scene, &models[i], &isSkeleton );
-
-                        // get fullname for splitting files, but only use it
-                        // in file if requested
-                        fullname = GetFullName( &scene, &models[i] );
-                        if ( use_prefix )
-                            name = fullname;
-                        else
-                            name = GetName( &scene, &models[i] );
-
-                        // split
-                        if ( strstr( fullname, search_prefix ) != NULL )
-                        {
-                            // for every skel part: get soft skin info
-                            if ( isSkeleton )
-                                MakeSoftSkin( &scene, &models[i], models,
-                                    numModels, name );
-                        }
-
-                        // free( name );
-                    }
-
-                    // make sure all vertices were assigned via soft skinning
-                    // - if not hard assign them
-                    for ( i = 0; i < numModels; i++ )
-                    {
-                        // get fullname for splitting files, but only use it
-                        // in file if requested
-                        fullname = GetFullName( &scene, &models[i] );
-                        if ( use_prefix )
-                            name = fullname;
-                        else
-                            name = GetName( &scene, &models[i] );
-
-                        // split
-                        if ( strstr( fullname, search_prefix ) != NULL )
-                            CleanUpSoftSkin( &scene, &models[i], name );
-
-                        // free( name );
-                    }
-
-                }
-
-
-                // put the skeleton data into the egg data
-                dart->StealChildren( *skeleton );
-
-                // make sure all elements have unique names
-                _data.UniquifyNames();
-
-                // write out the geometry data if requested if ( make_poly ||
-                // make_nurbs ) {
-                    eggFile << _data << "\n";
-                    fprintf( outStream, "\nwriting out %s...\n", eggFileName );
-                    eggFile.close();
-                }
-
-                // close texture list file if opened
-                if ( texFile )
-                    texFile.close();
-
-                // generate animation data if desired
-                if ( make_anim )
-                {
-                if ( animFileName == NULL )
-                {
-                    animFileName = (char *)malloc(sizeof(char)*
-                        (strlen(scene_name)+ 10 ));
-                    sprintf( animFileName, "%s", DepointellizeName(scene_name) );
-                    strcat( animFileName, "-chan.egg" );
-                }
-
-                unlink( animFileName );
-                animFile.open( animFileName, ios::out, 0666 );
-
-                if ( !animFile )
-                {
-                    fprintf( outStream, "Couldn't open output file: %s\n",
-                        animFileName );
-                    exit( 1 );
-                }
-
-                int frame;
-                // int frameStep;
-                float time;
-
-                // get all the animation frame info if not specified on the
-                // command line
-                if (anim_start == -1000)
-                    SAA_sceneGetPlayCtrlStartFrame( &scene, &anim_start );
-
-                if (anim_end == -1000)
-                    SAA_sceneGetPlayCtrlEndFrame( &scene, &anim_end );
-
-                // SAA_sceneGetPlayCtrlFrameStep( &scene, &frameStep );
-
-                fprintf( outStream, "\nframeStart = %d\n", anim_start );
-                fprintf( outStream, "frameEnd = %d\n", anim_end );
-                // fprintf( outStream, "frameStep = %d\n", frameStep );
-
-                // start at first frame and go to last
-                for ( frame = anim_start; frame <= anim_end;
-                        frame += 1)
-                {
-                    SAA_frame2Seconds( &scene, frame, &time );
-                    SAA_updatelistEvalScene( &scene, time );
-                    sginap( 100 );
-                    SAA_updatelistEvalScene( &scene, time );
-                    fprintf( outStream, "\n> animating frame %d\n", frame );
-
-                    // for each model
-                    for ( i = 0; i < numModels; i++ )
-                    {
-                        char           *name;
-                        char           *fullname;
-                        SAA_Boolean     isSkeleton;
-                        SAA_ModelType     type;
-
-                        SAA_modelIsSkeleton( &scene, &models[i], &isSkeleton );
-
-                        // get fullname for splitting files, but only use it
-                        // in file if requested
-                        fullname = GetFullName( &scene, &models[i] );
-                        if ( use_prefix )
-                            name = fullname;
-                        else
-                            name = GetName( &scene, &models[i] );
-
-                        // split
-                        if ( strstr( fullname, search_prefix ) != NULL )
-                        {
-                            // make the morph table for this critter
-                            if ( make_morph )
-                            {
-                                MakeMorphTable( &scene, &models[i], models,
-                                    numModels, name, time );
-                            }
-                        }
-
-                        // find out what type of node we're dealing with
-                        result = SAA_modelGetType( &scene, &models[i], &type );
-
-                        int size;
-
-                        // check for uv texture animation
-                        SAA_elementGetUserDataSize( &scene, &models[i],
-                            "TEX_OFFSETS", &size );
-
-                        // if so, update for this frame if desired
-                        if ( ( size != 0 ) && make_duv )
-                            MakeTexAnim( &scene, &models[i], name );
-
-                        // if we have a skeleton or something that acts like
-                        // one - build anim tables
-                        if ( isSkeleton  ||
-                            ( strstr( name, "joint") != NULL ) )
-                                MakeAnimTable( &scene, &models[i], name );
-
-                        // free( name );
-                    }
-
-                    if ( verbose >= 1 )
-                        fprintf( outStream, "\n" );
-                }
-
-                animFile << animData << "\n";
-                fprintf( outStream, "\nwriting out %s...\n", animFileName );
-                animFile.close();
-                }
-
-                // free( models );
-
-                }
-                else
-                    fprintf( outStream, "Error: Not enough Memory for models...\n");
-            }
-        }
-        // otherwise try to load a model
-        else if ( model_name != NULL )
-        {
-
-            if ( eggFileName == NULL )
-            {
-                eggFileName =
-                    (char *)malloc(sizeof(char)*(strlen( model_name )+13));
-                sprintf( eggFileName, "%s", DepointellizeName( model_name ) );
-
-                if ( make_nurbs )
-                    strcat( eggFileName, "-nurb" );
-                strcat( eggFileName, "-mod.egg" );
-            }
-
-            eggFile.open( eggFileName );
-
-            if ( !eggFile )
-            {
-                fprintf( outStream, "Couldn't open output file: %s\n",
-                    eggFileName );
-                exit( 1 );
-            }
-
-            if ((result =
-                SAA_elementLoad(&database, &scene, model_name, &model))
-                == SI_SUCCESS)
-            {
-                fprintf( outStream, "Loading single model...\n");
-                MakeEgg( NULL, NULL, NULL,  &scene, &model );
-            }
-
-            eggFile << _data << "\n";
-        }
-    }
-
-}
-
-/**
- * Make egg geometry from a given model.  This include textures, tex coords,
- * colors, normals, and joints.
- */
-void soft2egg::
-MakeEgg( EggGroup *parent, EggJoint *lastJoint, AnimGroup *lastAnim,
-            SAA_Scene *scene, SAA_Elem *model )
-{
-    char        *name;
-    char        *fullname;
-    SAA_ModelType type;
-    int         id = 0;
-    int         numShapes;
-    int         numTri;
-    int         numVert;
-    int         numTexLoc = 0;
-    int         numTexGlb = 0;
-    int         i, j;
-    float        matrix[4][4];
-    float        *uScale = NULL;
-    float        *vScale = NULL;
-    float        *uOffset = NULL;
-    float        *vOffset = NULL;
-    SAA_Boolean    uv_swap = FALSE;
-    void        *relinfo;
-    SAA_SubElem *triangles = NULL;
-    SAA_Elem    *materials = NULL;
-    SAA_SubElem *cvertices = NULL;
-    SAA_DVector *cvertPos = NULL;
-    SAA_DVector *vertices = NULL;
-    SAA_DVector *normals = NULL;
-    int            *indices = NULL;
-    int            *indexMap = NULL;
-    int            *numTexTri = NULL;
-    SAA_Elem    *textures = NULL;
-    char        **texNameArray;
-    float        *uCoords = NULL;
-    float        *vCoords = NULL;
-    SAA_GeomType gtype = SAA_GEOM_ORIGINAL;
-    SAA_Boolean    visible;
-
-    // find out what type of node we're dealing with
-    result = SAA_modelGetType( scene, model, &type );
-
-    if ( verbose >= 1 )
-    {
-        if ( type == SAA_MNILL )
-            fprintf( outStream, "encountered null\n");
-        else if ( type == SAA_MPTCH )
-            fprintf( outStream, "encountered patch\n" );
-        else if ( type == SAA_MFACE )
-            fprintf( outStream, "encountered face\n" );
-        else if ( type == SAA_MSMSH )
-            fprintf( outStream, "encountered mesh\n" );
-        else if ( type == SAA_MJNT )
-            fprintf( outStream, "encountered joint\n" );
-        else if ( type == SAA_MSPLN )
-            fprintf( outStream, "encountered spline\n" );
-        else if ( type == SAA_MMETA )
-            fprintf( outStream, "encountered meta element\n" );
-        else if ( type == SAA_MBALL )
-            fprintf( outStream, "encountered metaball\n" );
-        else if ( type == SAA_MNCRV )
-            fprintf( outStream, "encountered nurb curve\n" );
-        else if ( type == SAA_MNSRF )
-            fprintf( outStream, "encountered nurbs surf\n" );
-        else
-            fprintf( outStream, "encountered unknown type: %d\n", type );
-    }
-
-    // Get the name of the model
-
-    // Get the FULL name of the model
-    fullname = GetFullName( scene, model );
-
-    if ( use_prefix )
-    {
-        // Get the FULL name of the trim curve
-        name = fullname;
-    }
-    else
-    {
-        // Get the name of the trim curve
-        name = GetName( scene, model );
-    }
-
-    if ( verbose >= 1 )
-        fprintf( outStream, "element name <%s>\n", name );
-
-    fflush( outStream );
-
-    // get the model's matrix
-    SAA_modelGetMatrix( scene, model, SAA_COORDSYS_GLOBAL,  matrix );
-
-    if ( verbose >= 2 )
-    {
-        fprintf( outStream, "model matrix = %f %f %f %f\n", matrix[0][0],
-             matrix[0][1],  matrix[0][2],  matrix[0][3] );
-        fprintf( outStream, "model matrix = %f %f %f %f\n", matrix[1][0],
-             matrix[1][1],  matrix[1][2],  matrix[1][3] );
-        fprintf( outStream, "model matrix = %f %f %f %f\n", matrix[2][0],
-             matrix[2][1],  matrix[2][2],  matrix[2][3] );
-        fprintf( outStream, "model matrix = %f %f %f %f\n", matrix[3][0],
-             matrix[3][1],  matrix[3][2],  matrix[3][3] );
-    }
-
-    // check to see if this is a branch we don't want to descend - this will
-    // prevent creating geometry for animation control structures
-    if ( (strstr( name, "con-" ) == NULL) &&
-         (strstr( name, "con_" ) == NULL) &&
-         (strstr( name, "fly_" ) == NULL) &&
-         (strstr( name, "fly-" ) == NULL) &&
-         (strstr( name, "camRIG" ) == NULL) &&
-         (strstr( name, "bars" ) == NULL) &&
-         // split
-         (strstr( fullname, search_prefix ) != NULL) )
-    {
-
-    // if making a pose - get deformed geometry
-    if ( make_pose )
-        gtype = SAA_GEOM_DEFORMED;
-
-    // Get the number of key shapes
-    SAA_modelGetNbShapes( scene, model, &numShapes );
-    if ( verbose >= 1 )
-        fprintf( outStream, "MakeEgg: num shapes: %d\n", numShapes);
-
-    // if multiple key shapes exist create table entries for each
-    if ( (numShapes > 0) && make_morph )
-    {
-        has_morph = 1;
-
-        // make sure root morph table exists
-        if ( morphRoot == NULL )
-            morphRoot = animData.CreateTable( animRoot, "morph" );
-
-        char   *tableName;
-
-        // create morph table entry for each key shape (start at second shape
-        // - as first is the original geometry)
-        for ( i = 1; i < numShapes; i++ )
-        {
-            tableName = MakeTableName( name, i );
-            SAnimTable *table = new SAnimTable( );
-            table->name = tableName;
-            table->fps = anim_rate;
-            morphRoot->children.push_back( table );
-            if ( verbose >= 1 )
-                fprintf( outStream, "created table named: '%s'\n", tableName );
-        }
-
-        // free( tableName );
-    }
-
-    SAA_modelGetNodeVisibility( scene, model, &visible );
-    if ( verbose >= 1 )
-        fprintf( outStream, "model visibility: %d\n", visible );
-
-    // Only create egg polygon data if: the node is visible, and its not a
-    // NULL or a Joint, and we're outputing polys (or if we are outputing
-    // NURBS and the model is a poly mesh or a face)
-    if ( visible &&
-         (type != SAA_MNILL) &&
-         (type != SAA_MJNT) &&
-         ((make_poly ||
-         (make_nurbs && ((type == SAA_MSMSH) || (type == SAA_MFACE )) ))
-         || (!make_poly && !make_nurbs && make_duv &&
-            ((type == SAA_MSMSH) || (type == SAA_MFACE )) ))
-       )
-    {
-      // If the model is a NURBS in soft, set its step before tesselating
-      if ( type == SAA_MNSRF )
-        SAA_nurbsSurfaceSetStep( scene, model, nurbs_step, nurbs_step );
-
-      // If the model is a PATCH in soft, set its step before tesselating
-      else if ( type == SAA_MPTCH )
-        SAA_patchSetStep( scene, model, nurbs_step, nurbs_step );
-
-      // Get the number of triangles
-      result = SAA_modelGetNbTriangles( scene, model, gtype, id, &numTri);
-      if ( verbose >= 1 )
-          fprintf( outStream, "triangles: %d\n", numTri);
-
-      if ( result != SI_SUCCESS )
-      {
-        if ( verbose >= 1 ) {
-            fprintf( outStream,
-            "Error: couldn't get number of triangles!\n" );
-            fprintf( outStream, "\tbailing on model: '%s'\n", name );
-        }
-        return;
-      }
-
-      // check to see if surface is also skeleton...
-      SAA_Boolean isSkeleton = FALSE;
-
-      SAA_modelIsSkeleton( scene, model, &isSkeleton );
-
-      // check to see if this surface is used as a skeleton or is animated via
-      // constraint only ( these nodes are tagged by the animator with the
-      // keyword "joint" somewhere in the nodes name)
-      if ( isSkeleton || (strstr( name, "joint" ) != NULL) )
-      {
-          if ( verbose >= 1 )
-              fprintf( outStream, "animating Polys as joint!!!\n" );
-
-            MakeJoint( scene, lastJoint, lastAnim, model, name );
-      }
-
-      // model is not a null and has no triangles!
-      if ( !numTri )
-      {
-        if ( verbose >= 1 )
-            fprintf( outStream, "no triangles!\n");
-      }
-      else
-      {
-        // allocate array of triangles
-        triangles = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*numTri);
-        if ( triangles != NULL )
-        {
-            // triangulate model and read the triangles into array
-            SAA_modelGetTriangles( scene, model, gtype, id, numTri, triangles );
-        }
-        else
-            fprintf( outStream, "Not enough Memory for triangles...\n");
-
-        // allocate array of materials
-        materials = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numTri);
-        if ( materials != NULL )
-        {
-            // read each triangle's material into array
-            SAA_triangleGetMaterials( scene, model, numTri, triangles,
-                materials );
-        }
-        else
-            fprintf( outStream, "Not enough Memory for materials...\n");
-
-        // allocate array of textures per triangle
-        numTexTri = (int *)malloc(sizeof(int)*numTri);
-
-        // find out how many local textures per triangle
-        for ( i = 0; i < numTri; i++ )
-        {
-            result = SAA_materialRelationGetT2DLocNbElements( scene,
-                                                        &materials[i], FALSE, &relinfo, &numTexTri[i] );
-
-            // polytex
-            if ( result == SI_SUCCESS )
-                numTexLoc += numTexTri[i];
-        }
-
-        // don't need this anymore... free( numTexTri );
-
-        // get local textures if present
-        if ( numTexLoc )
-        {
-            // ASSUME only one texture per material
-            textures = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numTri);
-
-            for ( i = 0; i < numTri; i++ )
-            {
-                // and read all referenced local textures into array
-                SAA_materialRelationGetT2DLocElements( scene, &materials[i],
-                    TEX_PER_MAT , &textures[i] );
-            }
-
-            if ( verbose >= 1 )
-                fprintf( outStream, "numTexLoc = %d\n", numTexLoc);
-        }
-        // if no local textures, try to get global textures
-        else
-        {
-            SAA_modelRelationGetT2DGlbNbElements( scene, model,
-                FALSE, &relinfo, &numTexGlb );
-
-            if ( numTexGlb )
-            {
-                // ASSUME only one texture per model
-                textures = (SAA_Elem *)malloc(sizeof(SAA_Elem));
-
-                // get the referenced texture
-                SAA_modelRelationGetT2DGlbElements( scene, model,
-                    TEX_PER_MAT, textures );
-
-                if ( verbose >= 1 )
-                    fprintf( outStream, "numTexGlb = %d\n", numTexGlb);
-            }
-        }
-
-        // allocate array of control vertices
-        cvertices = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*numTri*3);
-        if ( cvertices != NULL )
-        {
-            // read each triangle's control vertices into array
-            SAA_triangleGetCtrlVertices( scene, model, gtype, id,
-                numTri, triangles, cvertices );
-
-            if ( verbose >= 2 )
-            {
-                cvertPos = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numTri*3);
-                SAA_ctrlVertexGetPositions(  scene, model, numTri*3,
-                    cvertices, cvertPos);
-
-                for ( i=0; i < numTri*3; i++ )
-                {
-                    fprintf( outStream, "cvert[%d] = %f %f %f %f\n", i,
-                        cvertPos[i].x, cvertPos[i].y, cvertPos[i].z,
-                        cvertPos[i].w );
-                }
-            }
-        }
-        else
-            fprintf( outStream, "Not enough Memory for control vertices...\n");
-
-        // allocate array of control vertex indices this array maps from the
-        // redundant cvertices array into the unique vertices array
-        // (cvertices->vertices)
-        indices = (int *)malloc(sizeof(int)*numTri*3);
-        if ( indices != NULL )
-        {
-            for ( i=0; i < numTri*3; i++ )
-                indices[i] = 0;
-
-            SAA_ctrlVertexGetIndices( scene, model, numTri*3,
-                cvertices, indices );
-
-            if ( verbose >= 2 )
-                for ( i=0; i < numTri*3; i++ )
-                    fprintf( outStream, "indices[%d] = %d\n", i, indices[i] );
-        }
-        else
-            fprintf( outStream, "Not enough Memory for indices...\n");
-
-        // get number of UNIQUE vertices in model
-        SAA_modelGetNbTriVertices( scene, model, &numVert );
-
-        if ( verbose >= 2 )
-            fprintf( outStream, "num unique verts = %d\n", numVert );
-
-        // allocate array of vertices
-        vertices = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numVert);
-
-        // get the UNIQUE vertices of all triangles in model
-        SAA_modelGetTriVertices( scene, model, numVert, vertices );
-
-        if ( verbose >= 2 )
-        {
-            for ( i=0; i < numVert; i++ )
-            {
-                fprintf( outStream, "vertices[%d] = %f ", i, vertices[i].x );
-                fprintf( outStream, "%f %f %f\n", vertices[i].y,
-                vertices[i].z, vertices[i].w );
-            }
-        }
-
-        // allocate indexMap array we contruct this array to map from the
-        // unique vertices array to the redundant cvertices array - it will
-        // save us from doing repetitive searches later
-        indexMap = MakeIndexMap( indices, numTri*3, numVert );
-
-        // allocate array of normals
-        normals = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numTri*3);
-        if ( normals != NULL )
-        {
-            // read each control vertex's normals into an array
-            SAA_ctrlVertexGetNormals( scene, model, numTri*3,
-                cvertices, normals );
-        }
-        else
-            fprintf( outStream, "Not enough Memory for normals...\n");
-
-        if ( verbose >= 2 )
-        {
-            for ( i=0; i<numTri*3; i++ )
-                fprintf( outStream, "normals[%d] = %f %f %f %f\n", i,
-                    normals[i].x, normals[i].y, normals[i].z, normals[i].w );
-        }
-
-        int uRepeat, vRepeat;
-
-        // make sure we have textures before we get t-coords
-        if ( numTexLoc )
-        {
-            // allocate arrays for u & v coords
-            uCoords = (float *)malloc(sizeof(float)*numTri*numTexLoc*3);
-            vCoords = (float *)malloc(sizeof(float)*numTri*numTexLoc*3);
-
-            // read the u & v coords into the arrays
-            if ( uCoords != NULL && vCoords != NULL)
-            {
-              for ( i = 0; i < numTri*numTexLoc*3; i++ )
-                uCoords[i] = vCoords[i] = 0.0f;
-
-                SAA_ctrlVertexGetUVTxtCoords( scene, model, numTri*3,
-                    cvertices, numTexLoc*3, uCoords, vCoords );
-            }
-            else
-                fprintf( outStream, "Not enough Memory for texture coords...\n");
-
-            if ( verbose >= 2 )
-            {
-                for ( i=0; i<numTexLoc*3; i++ )
-                    fprintf( outStream, "texcoords[%d] = ( %f , %f )\n", i,
-                        uCoords[i], vCoords[i] );
-            }
-
-            // allocate arrays of texture info
-            uScale = ( float *)malloc(sizeof(float)*numTri);
-            vScale = ( float *)malloc(sizeof(float)*numTri);
-            uOffset = ( float *)malloc(sizeof(float)*numTri);
-            vOffset = ( float *)malloc(sizeof(float)*numTri);
-            texNameArray = ( char **)malloc(sizeof(char *)*numTri);
-
-            for ( i = 0; i < numTri; i++ )
-            {
-                // initialize the array value
-                texNameArray[i] = NULL;
-
-                SAA_Boolean    valid = FALSE;
-                // check to see if texture is present
-                result = SAA_elementIsValid( scene, &textures[i], &valid );
-
-                if ( result != SI_SUCCESS )
-                    fprintf( outStream, "SAA_elementIsValid failed!!!!\n" );
-
-                // texture present - get the name and uv info
-                if ( valid )
-                {
-                    texNameArray[i] = ConvertTexture( scene, &textures[i] );
-
-                    if ( verbose >= 2 )
-                        fprintf( outStream, " tritex[%d] named: %s\n", i,
-                            texNameArray[i] );
-
-                    SAA_texture2DGetUVSwap( scene, &textures[i], &uv_swap );
-
-                    if ( verbose >= 2 )
-                        if ( uv_swap == TRUE )
-                            fprintf( outStream, " swapping u and v...\n" );
-
-                    SAA_texture2DGetUScale( scene, &textures[i], &uScale[i] );
-                    SAA_texture2DGetVScale( scene, &textures[i], &vScale[i] );
-                    SAA_texture2DGetUOffset( scene, &textures[i], &uOffset[i] );
-                    SAA_texture2DGetVOffset( scene, &textures[i], &vOffset[i] );
-
-                    if ( verbose >= 2 )
-                    {
-                        fprintf(outStream, "tritex[%d] uScale: %f vScale: %f\n",                             i, uScale[i], vScale[i] );
-                        fprintf(outStream, " uOffset: %f vOffset: %f\n",
-                            uOffset[i], vOffset[i] );
-                    }
-
-
-                    SAA_texture2DGetRepeats(  scene, &textures[i], &uRepeat,
-                        &vRepeat );
-
-                    if ( verbose >= 2 )
-                    {
-                        fprintf(outStream, "uRepeat = %d, vRepeat = %d\n",
-                            uRepeat, vRepeat );
-                    }
-                }
-                else
-                {
-                    if ( verbose >= 2 )
-                    {
-                        fprintf( outStream, "Invalid texture...\n");
-                        fprintf( outStream, " tritex[%d] named: (null)\n", i );
-                    }
-                }
-            }
-
-/*
- * debug for ( i = 0; i < numTri; i++ ) { if ( texNameArray[i] != NULL )
- * fprintf( outStream, " tritex[%d] named: %s\n", i, texNameArray[i] ); else
- * fprintf( outStream, " tritex[%d] named: (null)\n", i ); }
- */
-        }
-        // make sure we have textures before we get t-coords
-        else if ( numTexGlb )
-        {
-            SAA_Boolean    valid;
-
-            // check to see if texture is present
-            SAA_elementIsValid( scene, textures, &valid );
-
-            // texture present - get the name and uv info
-            if ( valid )
-            {
-                SAA_texture2DGetUVSwap( scene, textures, &uv_swap );
-
-                if ( verbose >= 1 )
-                    if ( uv_swap == TRUE )
-                        fprintf( outStream, " swapping u and v...\n" );
-
-                // allocate arrays for u & v coords
-                uCoords = (float *)malloc(sizeof(float)*numTri*numTexGlb*3);
-                vCoords = (float *)malloc(sizeof(float)*numTri*numTexGlb*3);
-
-                for ( i = 0; i < numTri*numTexGlb*3; i++ )
-                {
-                    uCoords[i] = vCoords[i] = 0.0f;
-                }
-
-                // read the u & v coords into the arrays
-                if ( uCoords != NULL && vCoords != NULL)
-                {
-                    SAA_triCtrlVertexGetGlobalUVTxtCoords( scene, model,
-                        numTri*3, cvertices, numTexGlb, textures,
-                        uCoords, vCoords );
-                }
-                else
-                    fprintf( outStream, "Not enough Memory for texture coords...\n");
-
-                if ( verbose >= 2 )
-                  {
-                    for ( i=0; i<numTri*numTexGlb*3; i++ )
-                      fprintf( outStream, "texcoords[%d] = ( %f , %f )\n", i,
-                               uCoords[i], vCoords[i] );
-                  }
-
-                texNameArray = ( char **)malloc(sizeof(char *));
-                *texNameArray = ConvertTexture( scene, textures );
-
-                if ( verbose >= 1 )
-                    fprintf( outStream, " global tex named: %s\n",
-                        texNameArray );
-
-                // allocate arrays of texture info
-                uScale = ( float *)malloc(sizeof(float));
-                vScale = ( float *)malloc(sizeof(float));
-                uOffset = ( float *)malloc(sizeof(float));
-                vOffset = ( float *)malloc(sizeof(float));
-
-                SAA_texture2DGetUScale( scene, textures, uScale );
-                SAA_texture2DGetVScale( scene, textures, vScale );
-                SAA_texture2DGetUOffset( scene, textures, uOffset );
-                SAA_texture2DGetVOffset( scene, textures, vOffset );
-
-                if ( verbose >= 1 )
-                {
-                    fprintf( outStream, " global tex uScale: %f vScale: %f\n",
-                        *uScale, *vScale );
-                    fprintf( outStream, " uOffset: %f vOffset: %f\n",
-                        *uOffset, *vOffset );
-                }
-
-                SAA_texture2DGetRepeats(  scene, textures, &uRepeat,
-                    &vRepeat );
-
-                if ( verbose >= 2 )
-                {
-                    fprintf(outStream, "uRepeat = %d, vRepeat = %d\n",
-                        uRepeat, vRepeat );
-                }
-            }
-            else fprintf( outStream, "Invalid texture...\n");
-        }
-
-        // make the egg vertex pool
-        EggVertexPool *pool = _data.CreateVertexPool( parent, name );
-
-        for ( i = 0; i < numVert; i++ )
-        {
-            pfVec3    eggVert;
-            pfVec3    eggNorm;
-
-            // convert to global coords
-            SAA_DVector local = vertices[i];
-            SAA_DVector global;
-
-            _VCT_X_MAT( global, local, matrix );
-
-            // set vertices array to reflect global coords vertices[i].x =
-            // global.x; vertices[i].y = global.y; vertices[i].z = global.z;
-
-            // eggVert.set( vertices[i].x, vertices[i].y, vertices[i].z );
-
-            // we'll preserve original verts for now
-            eggVert.set( global.x, global.y, global.z );
-
-            local = normals[indexMap[i]];
-
-            _VCT_X_MAT( global, local, matrix );
-
-            eggNorm.set( global.x, global.y, global.z );
-            eggNorm.normalize();
-
-            pool->AddVertex( eggVert, i );
-            pool->Vertex(i)->attrib.SetNormal( eggNorm );
-
-            // translate local uv's to global and add to vertex pool
-            if ( numTexLoc && (uCoords != NULL && vCoords !=NULL ))
-            {
-                float u, v;
-
-                if ( ignore_tex_offsets ) {
-                  u = uCoords[indexMap[i]];
-                  v = 1.0f - vCoords[indexMap[i]];
-                } else {
-                  u = (uCoords[indexMap[i]] - uOffset[indexMap[i]/3]) /
-                    uScale[indexMap[i]/3];
-
-                  v = 1.0f - ((vCoords[indexMap[i]] - vOffset[indexMap[i]/3]) /
-                              vScale[indexMap[i]/3]);
-                }
-
-                if ( isNum(u) && isNum(v) )
-                {
-                    if ( uv_swap == TRUE )
-                        pool->Vertex(i)->attrib.SetUV( v, u );
-                    else
-                        pool->Vertex(i)->attrib.SetUV( u, v );
-                }
-            }
-            else if ( numTexGlb && (uCoords != NULL && vCoords !=NULL ) )
-            {
-                float u, v;
-
-                if ( ignore_tex_offsets ) {
-                  u = uCoords[indexMap[i]];
-                  v = 1.0f - vCoords[indexMap[i]];
-                } else {
-                  u = (uCoords[indexMap[i]] - *uOffset) / *uScale;
-                  v = 1.0f - (( vCoords[indexMap[i]] - *vOffset ) / *vScale);
-                }
-
-                if ( isNum(u) && isNum(v) )
-                {
-                    if ( uv_swap == TRUE )
-                        pool->Vertex(i)->attrib.SetUV( v, u );
-                    else
-                        pool->Vertex(i)->attrib.SetUV( u, v );
-                }
-            }
-
-            // if we've encountered textures and we desire duv anims
-            if (( numTexLoc || numTexGlb ) && make_duv )
-            {
-                int            numExp;
-                SAA_Elem   *tex;
-
-                // grab the current texture
-                if ( numTexLoc )
-                    tex = &textures[0];
-                else
-                    tex = textures;
-
-                // find how many expressions for this shape
-                SAA_elementGetNbExpressions( scene, tex, NULL, FALSE,
-                    &numExp );
-
-                // if it has expressions we'll assume its animated
-                if ( numExp )
-                {
-                    // if animated object make base duv's, animtables for the
-                    // duv's and store the original offsets
-                    strstream uName, vName;
-
-                    // create duv target names
-                    uName << name << ".u" << ends;
-                    vName << name << ".v" << ends;
-
-                    // only create tables and store offsets on a per model
-                    // basis (not per vertex)
-                    if ( !i )
-                    {
-
-                        // make sure root morph table exists
-                        if ( morphRoot == NULL )
-                            morphRoot = animData.CreateTable( animRoot,
-                                "morph" );
-
-                        // create morph table entry for each duv
-                        SAnimTable *uTable = new SAnimTable( );
-                        uTable->name = uName.str();
-                        uTable->fps = anim_rate;
-                        morphRoot->children.push_back( uTable );
-                        if ( verbose >= 1 )
-                            fprintf( outStream, "created duv table named: %s\n",                                uName.str() );
-
-                        SAnimTable *vTable = new SAnimTable( );
-                        vTable->name = vName.str();
-                        vTable->fps = anim_rate;
-                        morphRoot->children.push_back( vTable );
-                        if ( verbose >= 1 )
-                            fprintf( outStream, "created duv table named: %s\n",                                vName.str() );
-
-                        float    texOffsets[4];
-
-                        if ( numTexGlb )
-                        {
-                            texOffsets[0] = *uOffset;
-                            texOffsets[1] = *vOffset;
-                            texOffsets[2] = *uScale;
-                            texOffsets[3] = *vScale;
-                        }
-                        else
-                        {
-                            texOffsets[0] = uOffset[indexMap[i]/3];
-                            texOffsets[1] = vOffset[indexMap[i]/3];
-                            texOffsets[2] = uScale[indexMap[i]/3];
-                            texOffsets[3] = vScale[indexMap[i]/3];
-                        }
-
-                        // remember original texture offsets future reference
-                        SAA_elementSetUserData( scene, model, "TEX_OFFSETS",
-                            sizeof( texOffsets ), TRUE, (void  **)&texOffsets );
-                    }
-
-                    EggMorphOffset *duvU;
-                    EggMorphOffset *duvV;
-
-                    // generate base duv's for this vertex
-                    duvU = new EggMorphOffset( uName.str(), 1.0 , 0.0 );
-                    pool->Vertex(i)->attrib.uv_morphs.push_back( *duvU );
-
-                    duvV = new EggMorphOffset( vName.str(), 0.0 , 1.0 );
-                    pool->Vertex(i)->attrib.uv_morphs.push_back( *duvV );
-
-                } // if ( numExp )
-
-            } // if ( numTexLoc || numTexGlb )
-
-        } // for ( i = 0; i < numVert; i++ )
-
-        // if model has key shapes, generate vertex offsets
-        if ( has_morph && make_morph )
-            MakeVertexOffsets( scene, model, type, numShapes, numVert,
-                vertices, matrix,  name );
-
-
-        // create vertex ref list for all polygons in the model
-        EggVertexRef *vref;
-
-        vref = new EggVertexRef( pool);
-        for ( i = 0; i < numVert; i++ )
-        {
-            // add each vert in pool to last joint for hard skinning
-            vref->indices.push_back( EggVertexIndex( i ) );
-        }
-
-/*
- * hard assign poly geometry if no soft-skinning requested disabled 1199 to
- * streamline joint assignments.  all hard-skinning now done in
- * CleanUpSoftSkin.  if ( !make_soft ) { if ( lastJoint != NULL ) {
- * lastJoint->vrefs.AddUniqueNode( *vref );
- */
-
-                // if ( verbose >= 1 ) fprintf( outStream, "hard-skinning %s
-                // (%d vertices)\n", name, i+1 ); } }
-
-        // make an egg group to hold all triangles
-        EggGroup *group = _data.CreateGroup( parent, name);
-
-        // make this group the current parent
-        parent = group;
-
-        EggPolygon *poly = NULL;
-        EggColor *cref = NULL;
-        EggTexture *tref = NULL;
-
-        // for each triangle
-        for ( i = 0; i < numTri*3; i+=3 )
-        {
-            float    r,g,b,a;
-            pfVec4    color;
-
-            // make egg poly for each traingle and reference the appropriate
-            // vertex in the pool
-            poly = _data.CreatePolygon( group, pool );
-            poly->AddVertex(indices[i]);
-            poly->AddVertex(indices[i+1]);
-            poly->AddVertex(indices[i+2]);
-
-            // check for back face flag in model note info
-            char *modelNoteStr = GetModelNoteInfo( scene, model );
-
-            if ( modelNoteStr != NULL )
-            {
-                if ( strstr( modelNoteStr, "bface" ) != NULL )
-                    poly->flags |= EG_BFACE;
-            }
-
-            // check to see if material is present
-            SAA_Boolean    valid;
-            SAA_elementIsValid( scene, &materials[i/3], &valid );
-
-            // material present - get the color
-            if ( valid )
-            {
-                SAA_materialGetDiffuse( scene, &materials[i/3], &r, &g, &b );
-                SAA_materialGetTransparency( scene, &materials[i/3], &a );
-                color.set( r, g, b, 1.0f - a );
-            }
-            // no material - default to white
-            else
-                color.set( 1.0, 1.0, 1.0, 1.0 );
-
-            cref = _data.CreateColor(color);
-            poly->attrib.SetCRef(cref);
-
-            strstream uniqueTexName;
-
-            if (numTexLoc)
-            {
-                // polytex
-                if ( (texNameArray[i/3] != NULL) &&
-                        (strcmp(texNameArray[i/3], "NULL") != 0) )
-                {
-                    // append unique identifier to texname for this particular
-                    // object
-                    uniqueTexName << name << "-"
-                        << RemovePathName(texNameArray[i/3]);
-
-                    tref = _data.CreateTexture( texNameArray[i/3],
-                        uniqueTexName.str() );
-
-                    if ( verbose >= 1 )
-                        fprintf( outStream, " tritex[%d] named: %s\n", i/3,
-                            texNameArray[i/3] );
-                }
-            }
-            else if ( numTexGlb )
-            {
-                if ( texNameArray != NULL )
-                {
-                    // append unique identifier to texname for this particular
-                    // object
-                    uniqueTexName << name << "-"
-                        << RemovePathName(*texNameArray);
-
-                    tref = _data.CreateTexture( *texNameArray,
-                        uniqueTexName.str() );
-
-                    if ( verbose >= 1 )
-                        fprintf( outStream, " tritex named: %s\n",
-                             *texNameArray );
-                }
-            }
-
-            // set the clamp on the texture
-            if ( tref != NULL )
-            {
-                if ( uRepeat > 0 )
-                    tref->wrapu = EggTexture::WM_repeat;
-                else
-                    tref->wrapu = EggTexture::WM_clamp;
-
-                if ( vRepeat > 1 )
-                    tref->wrapv = EggTexture::WM_repeat;
-                else
-                    tref->wrapv = EggTexture::WM_clamp;
-
-                poly->attrib.SetTRef(tref);
-            }
-
-        }
-
-        // we're done - trash triangles...
-        SAA_modelClearTriangles( scene, model );
-
-/*
- * free molloc'd memory free( triangles ); free( materials ); free( normals );
- * free( cvertices ); free( vertices ); free( indices ); free( indexMap );
- */
-
-        // free these only if they were malloc'd for textures
-        if (numTexLoc || numTexGlb)
-        {
-/*
- * free( textures ); free( uCoords ); free( vCoords ); free( texNameArray );
- * free( uScale ); free( vScale ); free( uOffset ); free( vOffset );
- */
-        }
-      }
-    }
-    else
-    {
-        // check to see if its a nurbs surface
-        if ( (type == SAA_MNSRF) && ( visible ) && (( make_nurbs )
-            || ( !make_nurbs && !make_poly &&  make_duv )) )
-        {
-            // check to see if NURBS is also skeleton...
-            SAA_Boolean isSkeleton = FALSE;
-
-            SAA_modelIsSkeleton( scene, model, &isSkeleton );
-
-            // check to see if this NURBS is used as a skeleton or is animated
-            // via constraint only ( these nodes are tagged by the animator
-            // with the keyword "joint" somewhere in the nodes name)
-            if ( isSkeleton || (strstr( name, "joint" ) != NULL) )
-            {
-                MakeJoint( scene, lastJoint, lastAnim, model, name );
-                geom_as_joint = 1;
-                if ( verbose >= 1 )
-                    fprintf( outStream, "animating NURBS as joint!!!\n" );
-            }
-
-            EggNurbsSurface    *eggNurbsSurf = new EggNurbsSurface( name );
-            int uDegree, vDegree;
-
-            // create nurbs representation of surface
-            SAA_nurbsSurfaceGetDegree( scene, model, &uDegree, &vDegree );
-            eggNurbsSurf->u_order = uDegree + 1;
-            eggNurbsSurf->v_order = vDegree + 1;
-            if ( verbose >= 1 )
-            {
-                fprintf( outStream, "nurbs degree: %d u, %d v\n",
-                    uDegree, vDegree );
-                fprintf( outStream, "nurbs order: %d u, %d v\n",
-                    uDegree + 1, vDegree + 1 );
-            }
-
-            SAA_Boolean    uClosed = FALSE;
-            SAA_Boolean    vClosed = FALSE;
-
-            SAA_nurbsSurfaceGetClosed( scene, model, &uClosed, &vClosed);
-
-            if ( verbose >= 1 )
-            {
-                if ( uClosed )
-                    fprintf( outStream, "nurbs is closed in u...\n");
-                if ( vClosed )
-                    fprintf( outStream, "nurbs is closed in v...\n");
-            }
-
-            int uRows, vRows;
-            SAA_nurbsSurfaceGetNbVertices( scene, model, &uRows, &vRows );
-            if ( verbose >= 1 )
-                fprintf( outStream, "nurbs vertices: %d u, %d v\n",
-                    uRows, vRows );
-
-            int uCurves, vCurves;
-            SAA_nurbsSurfaceGetNbCurves( scene, model, &uCurves, &vCurves );
-            if ( verbose >= 1 )
-                fprintf( outStream, "nurbs curves: %d u, %d v\n",
-                    uCurves, vCurves );
-
-            if ( shift_textures )
-            {
-            if ( uClosed )
-                // shift starting point on NURBS surface for correct textures
-                SAA_nurbsSurfaceShiftParameterization( scene, model, -2, 0 );
-
-            if ( vClosed )
-                // shift starting point on NURBS surface for correct textures
-                SAA_nurbsSurfaceShiftParameterization( scene, model, 0, -2 );
-            }
-
-            SAA_nurbsSurfaceSetStep( scene, model, nurbs_step, nurbs_step );
-
-            // check for back face flag in model note info
-            char *modelNoteStr = GetModelNoteInfo( scene, model );
-
-            if ( modelNoteStr != NULL )
-            {
-                if ( strstr( modelNoteStr, "bface" ) != NULL )
-                    eggNurbsSurf->flags |= EG_BFACE;
-            }
-
-            int numKnotsU, numKnotsV;
-
-            SAA_nurbsSurfaceGetNbKnots( scene, model, &numKnotsU, &numKnotsV );
-            if ( verbose >= 1 )
-                fprintf( outStream, "nurbs knots: %d u, %d v\n",
-                    numKnotsU, numKnotsV );
-
-            double *knotsU, *knotsV;
-            knotsU = (double *)malloc(sizeof(double)*numKnotsU);
-            knotsV = (double *)malloc(sizeof(double)*numKnotsV);
-            SAA_nurbsSurfaceGetKnots( scene, model, gtype, 0,
-                numKnotsU, numKnotsV, knotsU, knotsV );
-
-            if ( verbose >= 2 )
-                fprintf( outStream, "u knots:\n" );
-
-            AddKnots( eggNurbsSurf->u_knots, knotsU, numKnotsU, uClosed, uDegree );
-            if ( verbose >= 2 )
-                fprintf( outStream, "v knots:\n" );
-
-            AddKnots( eggNurbsSurf->v_knots, knotsV, numKnotsV, vClosed, vDegree);
-
-            // free( knotsU ); free( knotsV );
-
-            // set sub_div so we can see it in perfly
-            eggNurbsSurf->u_subdiv = (uRows-1)*nurbs_step;
-            eggNurbsSurf->v_subdiv = (vRows-1)*nurbs_step;
-
-            SAA_modelGetNbVertices( scene, model, &numVert );
-
-            if ( verbose >= 2 )
-                fprintf( outStream, "%d CV's\n", numVert );
-
-            // get the CV's
-            vertices = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numVert);
-            SAA_modelGetVertices( scene, model, gtype, 0,
-                numVert, vertices );
-
-            // create pool of NURBS vertices
-            EggVertexPool *pool = _data.CreateVertexPool( parent, name );
-            eggNurbsSurf->SetVertexPool( pool );
-
-            // create vertex ref list for all cv's in the model
-            EggVertexRef *vref;
-
-            vref = new EggVertexRef( pool);
-
-            for ( int k = 0; k<numVert; k++ )
-            {
-                if ( verbose >= 2 )
-                {
-                    fprintf( outStream, "original cv[%d] = %f %f %f %f\n", k,
-                        vertices[k].x, vertices[k].y, vertices[k].z,
-                        vertices[k].w );
-                }
-
-                pfVec4  eggVert;
-
-                // convert to global coords
-                SAA_DVector global;
-
-                _VCT_X_MAT( global, vertices[k], matrix );
-
-                // preserve original weight
-                global.w = vertices[k].w;
-
-                // normalize coords to weight
-                global.x *= global.w;
-                global.y *= global.w;
-                global.z *= global.w;
-
-                // this code is commented out because I am no longer sending
-                // global data to the other routines (ie makevertexoffset)
-
-                // set vertices array to reflect global coords vertices[k].x =
-                // global.x; vertices[k].y = global.y; vertices[k].z =
-                // global.z; vertices[k].w = global.w;
-
-                // if ( verbose >= 2 ) { fprintf( outStream, "global cv[%d] =
-                // %f %f %f %f\n", k, vertices[k].x, vertices[k].y,
-                // vertices[k].z, vertices[k].w ); }
-
-                // eggVert.set( vertices[k].x, vertices[k].y, vertices[k].z,
-                // vertices[k].w );
-
-                if ( verbose >= 2 )
-                {
-                    fprintf( outStream, "global cv[%d] = %f %f %f %f\n", k,
-                        global.x, global.y, global.z,
-                        global.w );
-                }
-
-                eggVert.set( global.x, global.y, global.z,
-                    global.w );
-
-                // populate vertex pool
-                pool->AddVertex( eggVert, k );
-
-                // add vref's to NURBS info
-                eggNurbsSurf->AddVertex( k );
-
-                // add each vert in pool to vref for hard skinning
-                vref->indices.push_back( EggVertexIndex( k ) );
-
-                // check to see if the NURB is closed in u
-                if ( uClosed )
-                {
-                    // add first uDegree verts to end of row
-                    if ( (k % uRows) == ( uRows - 1) )
-                    for ( int i = 0; i < uDegree; i++ )
-                    {
-                        // add vref's to NURBS info
-                        eggNurbsSurf->AddVertex( i+((k/uRows)*uRows) );
-
-                        // add each vert to vref
-                        vref->indices.push_back(
-                            EggVertexIndex( i+((k/uRows)*uRows) ) );
-                    }
-                }
-            }
-
-/*
- * if hard skinned or this nurb is also a joint disabled 1199 to streamline
- * joint assignments.  all hard skinning now done in CleanUpSoftSkin.  if
- * (!make_soft || geom_as_joint) { add the new cv references to the last joint
- * for hard skinning only if ( lastJoint != NULL ) {
- * lastJoint->vrefs.AddUniqueNode( *vref ); geom_as_joint = 0; if ( verbose >=
- * 1 ) fprintf( outStream, "Doing NURBS hard skinning...\n"); } }
- */
-
-            // check to see if the NURB is closed in v
-            if ( vClosed && !uClosed )
-            {
-                // add first vDegree rows of verts to end of list
-                for ( int i = 0; i < vDegree*uRows; i++ )
-                    eggNurbsSurf->AddVertex( i );
-            }
-            // check to see if the NURB is closed in u and v
-            else if ( vClosed && uClosed )
-            {
-                // add the first (degree) v verts and a few extra - for good
-                // measure
-                for ( i = 0; i < vDegree; i++ )
-                {
-                    // add first vDegree rows of verts to end of list
-                    for ( j = 0; j < uRows; j++ )
-                        eggNurbsSurf->AddVertex( j+(i*uRows) );
-
-                    // if u is closed to we have added uDegree verts onto the
-                    // ends of the rows - add them here too
-                    for ( k = 0; k < uDegree; k++ )
-                        eggNurbsSurf->AddVertex( k+(i*uRows)+((k/uRows)*uRows) );
-                }
-
-            }
-
-            // get the color of the NURBS surface
-            int numNurbMats;
-            EggColor *nurbCref;
-            pfVec4    nurbColor;
-
-            SAA_modelRelationGetMatNbElements( scene, model, FALSE, &relinfo,
-                &numNurbMats );
-
-            if ( verbose >= 1 )
-                fprintf( outStream, "nurbs surf has %d materials\n",
-                    numNurbMats );
-
-            if ( numNurbMats )
-            {
-                float r,g,b,a;
-
-                materials = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numNurbMats);
-
-                SAA_modelRelationGetMatElements( scene, model, relinfo,
-                    numNurbMats, materials );
-
-                SAA_materialGetDiffuse( scene, &materials[0], &r, &g, &b );
-                SAA_materialGetTransparency( scene, &materials[0], &a );
-                nurbColor.set( r, g, b, 1.0f - a );
-                // nurbColor.set( r, g, b, 1.0 );
-
-                nurbCref = _data.CreateColor(nurbColor);
-                eggNurbsSurf->attrib.SetCRef(nurbCref);
-
-                // get the texture of the NURBS surface from the material
-                int numNurbTexLoc = 0;
-                int numNurbTexGlb = 0;
-
-                // ASSUME only one texture per material
-                SAA_Elem nurbTex;
-
-                // find out how many local textures per NURBS surface ASSUME
-                // it only has one material
-                SAA_materialRelationGetT2DLocNbElements( scene, &materials[0],
-                    FALSE, &relinfo, &numNurbTexLoc );
-
-                // if present, get local textures
-                if ( numNurbTexLoc )
-                {
-                    if ( verbose >= 1 )
-                        fprintf( outStream, "%s had %d local tex\n", name,
-                            numNurbTexLoc );
-
-                    // get the referenced texture
-                    SAA_materialRelationGetT2DLocElements( scene, &materials[0],
-                        TEX_PER_MAT, &nurbTex );
-
-                }
-                // if no locals, try to get globals
-                else
-                {
-                    SAA_modelRelationGetT2DGlbNbElements( scene, model,
-                        FALSE, &relinfo, &numNurbTexGlb );
-
-                    if ( numNurbTexGlb )
-                    {
-                        if ( verbose >= 1 )
-                            fprintf( outStream, "%s had %d global tex\n", name,
-                                numNurbTexGlb );
-
-                            // get the referenced texture
-                            SAA_modelRelationGetT2DGlbElements( scene,
-                                model, TEX_PER_MAT, &nurbTex );
-                        }
-                }
-
-                // add tex ref's if we found any textures
-                if ( numNurbTexLoc || numNurbTexGlb)
-                {
-                    char    *texName = NULL;
-                    char    *uniqueTexName = NULL;
-                    EggTexture *tref;
-                    pfMatrix  nurbTexMat;
-
-
-                    // convert the texture to .rgb and adjust name
-                    texName = ConvertTexture( scene, &nurbTex );
-
-                    // append unique identifier to texname for this particular
-                    // object
-                    uniqueTexName = (char *)malloc(sizeof(char)*
-                        (strlen(name)+strlen(texName)+3) );
-                    sprintf( uniqueTexName, "%s-%s", name,
-                        RemovePathName(texName) );
-
-                    if ( verbose >= 1 )
-                    {
-                        fprintf( outStream, "creating tref %s\n",
-                            uniqueTexName );
-                    }
-
-                    tref = _data.CreateTexture( texName, uniqueTexName );
-
-                    uScale = ( float *)malloc(sizeof(float));
-                    vScale = ( float *)malloc(sizeof(float));
-                    uOffset = ( float *)malloc(sizeof(float));
-                    vOffset = ( float *)malloc(sizeof(float));
-
-                    // get texture offset info
-                    SAA_texture2DGetUScale( scene, &nurbTex, uScale );
-                    SAA_texture2DGetVScale( scene, &nurbTex, vScale );
-                    SAA_texture2DGetUOffset( scene, &nurbTex, uOffset );
-                    SAA_texture2DGetVOffset( scene, &nurbTex, vOffset );
-                    SAA_texture2DGetUVSwap( scene, &nurbTex, &uv_swap );
-
-
-                    if ( verbose >= 1 )
-                    {
-                        fprintf( outStream, "nurbTex uScale: %f\n", *uScale );
-                        fprintf( outStream, "nurbTex vScale: %f\n", *vScale );
-                        fprintf( outStream, "nurbTex uOffset: %f\n", *uOffset );
-                        fprintf( outStream, "nurbTex vOffset: %f\n", *vOffset );
-                        if ( uv_swap )
-                            fprintf( outStream, "nurbTex u & v swapped!\n" );
-                        else
-                            fprintf( outStream, "nurbTex u & v NOT swapped\n" );
-                    }
-
-                    nurbTexMat.makeIdent();
-
-                    if ( !ignore_tex_offsets )
-                    {
-                        if ( uv_swap )
-                        {
-                            nurbTexMat[0][0] = 0.0f;
-                            nurbTexMat[1][1] = 0.0f;
-                            nurbTexMat[0][1] = 1 / *vScale;
-                            nurbTexMat[1][0] = 1 / *uScale;
-                            nurbTexMat[2][1] = -(*uOffset / *uScale);
-                            nurbTexMat[2][0] = -(*vOffset / *vScale);
-                        }
-                        else
-                        {
-                            nurbTexMat[0][0] = 1 / *uScale;
-                            nurbTexMat[1][1] = 1 / *vScale;
-                            nurbTexMat[2][0] = -(*uOffset / *uScale);
-                            nurbTexMat[2][1] = -(*vOffset / *vScale);
-                        }
-                    }
-
-
-    // call printMat
-    if ( verbose >= 2 )
-    {
-    fprintf( outStream, "nurb tex matrix = %f %f %f %f\n", nurbTexMat[0][0],
-         nurbTexMat[0][1],  nurbTexMat[0][2],  nurbTexMat[0][3] );
-    fprintf( outStream, "nurb tex matrix = %f %f %f %f\n", nurbTexMat[1][0],
-         nurbTexMat[1][1],  nurbTexMat[1][2],  nurbTexMat[1][3] );
-    fprintf( outStream, "nurb tex matrix = %f %f %f %f\n", nurbTexMat[2][0],
-         nurbTexMat[2][1],  nurbTexMat[2][2],  nurbTexMat[2][3] );
-    fprintf( outStream, "nurb tex matrix = %f %f %f %f\n", nurbTexMat[3][0],
-         nurbTexMat[3][1],  nurbTexMat[3][2],  nurbTexMat[3][3] );
-    }
-
-
-                    tref->tex_mat = nurbTexMat;
-                    tref->flags |= EFT_TRANSFORM;
-
-                    eggNurbsSurf->attrib.SetTRef(tref);
-
-                }
-
-                // if we've encountered textures and we desire duv anims
-                if (( numNurbTexLoc || numNurbTexGlb ) && make_duv )
-                {
-                    int            numExp;
-
-                     // find how many expressions for this shape
-                    SAA_elementGetNbExpressions( scene, &nurbTex, NULL, FALSE,
-                        &numExp );
-
-                    // if it has expressions we'll assume its animated
-                    if ( numExp )
-                    {
-                        if ( verbose > 1 )
-                            printf( "nurbTex has %d expressions...\n", numExp );
-
-                        // if animated object make base duv's, animtables for
-                        // the duv's and store the original offsets
-                        strstream uName, vName;
-
-                        // create duv target names
-                        uName << name << ".u" << ends;
-                        vName << name << ".v" << ends;
-
-                        // make sure root morph table exists
-                        if ( morphRoot == NULL )
-                            morphRoot = animData.CreateTable( animRoot,
-                                "morph" );
-
-                        // create morph table entry for each duv
-                        SAnimTable *uTable = new SAnimTable( );
-                        uTable->name = uName.str();
-                        uTable->fps = anim_rate;
-                        morphRoot->children.push_back( uTable );
-                        if ( verbose >= 1 )
-                            fprintf( outStream, "created duv table named: %s\n",                                uName.str() );
-
-                        SAnimTable *vTable = new SAnimTable( );
-                        vTable->name = vName.str();
-                        vTable->fps = anim_rate;
-                        morphRoot->children.push_back( vTable );
-                        if ( verbose >= 1 )
-                            fprintf( outStream, "created duv table named: %s\n",                                vName.str() );
-
-                        float    texOffsets[4];
-
-                        texOffsets[0] = *uOffset;
-                        texOffsets[1] = *vOffset;
-                        texOffsets[2] = *uScale;
-                        texOffsets[3] = *vScale;
-
-                        // remember original texture offsets future reference
-                        SAA_elementSetUserData( scene, model, "TEX_OFFSETS",
-                            sizeof( texOffsets ), TRUE, (void  **)&texOffsets );
-
-                        // create UV's and duv's for each vertex
-                        for( i = 0; i < numVert; i++ )
-                        {
-                            pfVec2            tmpUV;
-                            EggMorphOffset *duvU;
-                            EggMorphOffset *duvV;
-
-                            // create uv's so we can store duv's
-                            eggNurbsSurf->CalcActualUV( i, tmpUV );
-                            pool->Vertex(i)->attrib.SetUV( tmpUV[0], tmpUV[1] );
-
-                            // generate base duv's for this vertex
-                            duvU = new EggMorphOffset(uName.str(), 1.0 , 0.0);
-                            pool->Vertex(i)->attrib.uv_morphs.push_back(*duvU);
-
-                            duvV = new EggMorphOffset(vName.str(), 0.0 , 1.0);
-                            pool->Vertex(i)->attrib.uv_morphs.push_back(*duvV);
-                        }
-
-                  } // if ( numExp )
-                } // if ( numTexLoc || numTexGlb )
-
-                // free( uScale ); free( vScale ); free( uOffset ); free(
-                // vOffset );
-
-                // free( materials );
-            }
-            else
-            {
-                // no material present - default to white
-                nurbColor.set( 1.0, 1.0, 1.0, 1.0 );
-            }
-
-            // check NURBS surface for trim curves
-            int     numTrims;
-            bool    isTrim = TRUE;
-            SAA_SubElem *trims;
-
-            SAA_nurbsSurfaceGetNbTrimCurves( scene, model, SAA_TRIMTYPE_TRIM,
-                &numTrims );
-
-            if ( verbose >= 1 )
-                fprintf( outStream, "nurbs surf has %d trim curves\n",
-                    numTrims );
-
-            if ( numTrims)
-            {
-                trims = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*numTrims);
-
-                if ( trims )
-                {
-                    SAA_nurbsSurfaceGetTrimCurves( scene, model,
-                        gtype, 0, SAA_TRIMTYPE_TRIM, numTrims,
-                        trims );
-
-                    MakeSurfaceCurve( scene, model, parent, eggNurbsSurf,
-                        numTrims, trims, isTrim );
-                }
-
-                // free( trims );
-            }
-
-            // check NURBS surface for surface curves
-            isTrim = FALSE;
-
-            SAA_nurbsSurfaceGetNbTrimCurves( scene, model,
-                SAA_TRIMTYPE_PROJECTION, &numTrims );
-
-            if ( verbose >= 1 )
-                fprintf( outStream, "nurbs surf has %d surface curves\n",
-                    numTrims );
-
-            if ( numTrims)
-            {
-                trims = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*numTrims);
-
-                if ( trims )
-                {
-                    SAA_nurbsSurfaceGetTrimCurves( scene, model,
-                        gtype, 0, SAA_TRIMTYPE_PROJECTION,
-                        numTrims, trims );
-
-                    MakeSurfaceCurve( scene, model, parent, eggNurbsSurf,
-                        numTrims, trims, isTrim );
-                }
-
-                // free( trims );
-            }
-
-            // push the NURBS into the egg data
-            parent->children.push_back( eggNurbsSurf );
-
-            // if model has key shapes, generate vertex offsets
-            if ( has_morph && make_morph )
-                MakeVertexOffsets( scene, model, type, numShapes, numVert,
-                    vertices, matrix, name );
-
-
-            // free( vertices );
-
-        }
-
-        // check to see if its a NURBS curve
-        else if ( (type == SAA_MNCRV) && ( visible ) && ( make_nurbs ) )
-        {
-            // ignore for now make the NURBS curve and push it into the egg
-            // data parent->children.push_back( MakeNurbsCurve( scene, model,
-            // parent, matrix, name ) );
-           }
-        else if ( type == SAA_MJNT )
-        {
-            MakeJoint( scene, lastJoint, lastAnim, model, name );
-            if ( verbose >= 1 )
-                fprintf( outStream, "encountered IK joint: %s\n", name );
-        }
-
-        // it must be a NULL
-        else
-        {
-            SAA_AlgorithmType    algo;
-
-            SAA_modelGetAlgorithm( scene, model, &algo );
-            if ( verbose >= 1 )
-                fprintf( outStream, "null algorithm: %d\n", algo );
-
-            if ( algo == SAA_ALG_INV_KIN )
-            {
-                MakeJoint( scene, lastJoint, lastAnim,  model, name );
-                if ( verbose >= 1 )
-                    fprintf( outStream, "encountered IK root: %s\n", name );
-            }
-            else if ( algo == SAA_ALG_INV_KIN_LEAF )
-            {
-                MakeJoint( scene, lastJoint, lastAnim, model, name );
-                if ( verbose >= 1 )
-                    fprintf( outStream, "encountered IK leaf: %s\n", name );
-            }
-            else if ( algo == SAA_ALG_STANDARD )
-            {
-                SAA_Boolean isSkeleton = FALSE;
-
-                if ( verbose >= 1 )
-                    fprintf( outStream, "encountered Standard null: %s\n", name);
-
-                SAA_modelIsSkeleton( scene, model, &isSkeleton );
-
-                // check to see if this NULL is used as a skeleton or is
-                // animated via constraint only ( these nodes are tagged by
-                // the animator with the keyword "joint" somewhere in the
-                // nodes name)
-                if ( isSkeleton || (strstr( name, "joint" ) != NULL) )
-                {
-                    MakeJoint( scene, lastJoint, lastAnim, model, name );
-                    if ( verbose >= 1 )
-                        fprintf( outStream, "animating Standard null!!!\n" );
-                }
-            }
-            else
-                if ( verbose >= 1 )
-                    fprintf( outStream, "encountered some other NULL: %d\n",
-                        algo );
-        }
-    }
-
-
-    // check for children...
-    int        numChildren;
-    int        thisChild;
-    SAA_Elem *children;
-
-    SAA_modelGetNbChildren( scene, model, &numChildren );
-    if ( verbose >= 1 )
-        fprintf( outStream, "Model children: %d\n", numChildren );
-
-    if ( numChildren )
-    {
-        children = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numChildren);
-        SAA_modelGetChildren( scene, model, numChildren, children );
-        if ( children != NULL )
-        {
-            for ( thisChild = 0; thisChild < numChildren; thisChild++ )
-            {
-                if ( verbose >= 1 )
-                    fprintf( outStream, "\negging child %d...\n", thisChild);
-                MakeEgg( parent, lastJoint, lastAnim, scene,
-                    &children[thisChild] );
-            }
-        }
-        else
-            fprintf( outStream, "Not enough Memory for children...\n");
-        // free( children );
-    }
-    fflush( outStream );
-  }
-  else
-    if ( verbose >= 1 )
-        fprintf( outStream, "Don't descend this branch!\n" );
-
-  // we are done for the most part - start cleaning up memory free( name );
-}
-
-
-/**
- * Given a scene and lists of u and v samples create a an egg NURBS curve of
- * degree two from the samples
- */
-void  soft2egg::
-MakeSurfaceCurve(  SAA_Scene *scene, SAA_Elem *model, EggGroup *parent,
-    EggNurbsSurface *&nurbsSurf, int numTrims, SAA_SubElem *trims,
-    bool isTrim )
-{
-    int      i;
-    long      totalSamples = 0;
-    long    *numSamples;
-    double    *uSamples;
-    double    *vSamples;
-    SAA_Elem *trimCurves;
-    char    *name;
-
-    // get UV coord data
-    numSamples = (long *)malloc(sizeof(long)*numTrims);
-
-    SAA_surfaceCurveGetNbLinearSamples( scene, model,  numTrims, trims,
-        numSamples );
-
-    for ( i = 0; i < numTrims; i++ )
-    {
-        totalSamples += numSamples[i];
-        if ( verbose >= 2 )
-            fprintf( outStream, "numSamples[%d] = %d\n", i, numSamples[i] );
-    }
-
-    if ( verbose >= 2 )
-        fprintf( outStream, "total samples = %ld\n", totalSamples );
-
-    uSamples = (double *)malloc(sizeof(double)*totalSamples);
-    vSamples = (double *)malloc(sizeof(double)*totalSamples);
-
-    SAA_surfaceCurveGetLinearSamples( scene, model, numTrims, trims,
-        numSamples, uSamples, vSamples );
-
-    if ( verbose >= 2 )
-        for ( long li = 0; li < totalSamples; li++ )
-            fprintf( outStream, "master list cv[%ld] = %f, %f\n", li,
-                uSamples[li], vSamples[li] );
-
-    trimCurves = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numTrims);
-
-    SAA_surfaceCurveExtract( scene, model, numTrims, trims, trimCurves );
-
-    // if it's a trim create a trim to assign trim curves to
-    EggNurbsSurface::Trim *eggTrim = new EggNurbsSurface::Trim();
-
-    // for each trim curve, make an egg curve and add it to the trims of the
-    // NURBS surface
-    for ( i = 0; i < numTrims; i++ )
-    {
-        if ( use_prefix )
-        {
-            // Get the FULL name of the trim curve
-            name = GetFullName( scene, &trimCurves[i] );
-        }
-        else
-        {
-            // Get the name of the trim curve
-            name = GetName( scene, &trimCurves[i] );
-        }
-
-        if ( isTrim )
-        {
-            // add to trim list
-            EggNurbsSurface::Loop *eggLoop = new EggNurbsSurface::Loop();
-            eggLoop->push_back( MakeUVNurbsCurve( i, numSamples, uSamples,
-                vSamples, parent, name ) );
-            eggTrim->push_back( *eggLoop );
-        }
-        else
-            // add to curve list
-            nurbsSurf->curves.push_back( MakeUVNurbsCurve( i, numSamples,                         uSamples, vSamples, parent, name ) );
-    }
-
-    if ( isTrim )
-        // pus trim list onto trims list
-        nurbsSurf->trims.push_back( *eggTrim );
-
-    // free( name ); free( trimCurves ); free( uSamples ); free( vSamples );
-}
-
-/**
- * Given a scene and lists of u and v samples create a an egg NURBS curve of
- * degree two from the samples
- */
-EggNurbsCurve  *soft2egg::
-MakeUVNurbsCurve( int numCurve, long *numSamples, double *uSamples,
-    double *vSamples, EggGroup *parent, char *name )
-{
-    EggNurbsCurve    *eggNurbsCurve = new EggNurbsCurve( name );
-
-    eggNurbsCurve->order = 2;
-
-
-    if ( verbose >= 2 )
-        fprintf( outStream, "nurbs UV curve %s:\n", name );
-
-    // set sub_div so we can see it in perfly eggNurbsCurve->subdiv =
-    // numSamples[numCurve]4; perfly chokes on big numbers - keep it
-    // reasonable
-    eggNurbsCurve->subdiv = 150;
-
-    // create pool of NURBS vertices
-    EggVertexPool *pool = _data.CreateVertexPool( parent, name );
-    eggNurbsCurve->SetVertexPool( pool );
-
-    // calculate offset to this curve's samples in list of all curve samples
-    int offset = 0;
-
-    for ( int o = 0; o < numCurve; o++ )
-        offset += numSamples[o];
-
-    for ( int k = 0; k<numSamples[numCurve]; k++ )
-    {
-        pfVec3  eggVert;
-
-        // index into the array of samples for this curve
-        eggVert.set( uSamples[k+offset], vSamples[k+offset], 1.0f );
-
-        if ( verbose >= 2 )
-            fprintf( outStream, "cv[%d] = %f %f %f\n", k, eggVert[0],
-                eggVert[1], eggVert[2] );
-
-        // populate vertex pool
-        pool->AddVertex( eggVert, k );
-
-        // add vref's to NURBS info
-        eggNurbsCurve->AddVertex( k );
-    }
-
-    // create numSamples[numCurve]+2 knots
-    eggNurbsCurve->knots.push_back( 0 );
-    for ( k = 0; k < numSamples[numCurve]; k++ )
-        eggNurbsCurve->knots.push_back( k  );
-    eggNurbsCurve->knots.push_back( numSamples[numCurve] - 1 );
-
-    // set color to bright green for now
-    EggColor *nurbCref;
-    pfVec4    nurbColor;
-
-    nurbColor.set( 0.5, 1.0, 0.5, 1.0 );
-    nurbCref = _data.CreateColor(nurbColor);
-    eggNurbsCurve->attrib.SetCRef(nurbCref);
-
-    return( eggNurbsCurve );
-}
-
-/**
- * Given a scene and a NURBS curve model create the the appropriate egg
- * structures
- */
-EggNurbsCurve  *soft2egg::
-MakeNurbsCurve( SAA_Scene *scene, SAA_Elem *model, EggGroup *parent,
-    float matrix[4][4], char *name )
-{
-    EggNurbsCurve    *eggNurbsCurve = new EggNurbsCurve( name );
-    int degree;
-
-    if ( verbose >= 2 )
-        fprintf( outStream, "nurbs curve %s:\n", name );
-
-    // create nurbs representation of surface
-    SAA_nurbsCurveGetDegree( scene, model, &degree );
-    eggNurbsCurve->order = degree + 1;
-    if ( verbose >= 2 )
-        fprintf( outStream, "nurbs curve order: %d\n", degree + 1 );
-
-    SAA_nurbsCurveSetStep( scene, model, nurbs_step );
-
-    SAA_Boolean    closed = FALSE;
-
-    SAA_nurbsCurveGetClosed( scene, model, &closed );
-    if ( closed )
-        if ( verbose >= 2 )
-            fprintf( outStream, "nurbs curve is closed...\n");
-
-    int numKnots;
-
-    SAA_nurbsCurveGetNbKnots( scene, model, &numKnots );
-    if ( verbose >= 2 )
-        fprintf( outStream, "nurbs curve knots: %d\n", numKnots );
-    double *knots;
-    knots = (double *)malloc(sizeof(double)*numKnots);
-    SAA_nurbsCurveGetKnots( scene, model, SAA_GEOM_ORIGINAL, 0,
-        numKnots, knots );
-
-    AddKnots( eggNurbsCurve->knots, knots, numKnots, closed, degree );
-
-    // free( knots );
-
-    int    numCV;
-
-    SAA_modelGetNbVertices( scene, model, &numCV );
-    if ( verbose >= 2 )
-        fprintf( outStream, "%d CV's (=? %d)\n", numCV, (numKnots-(degree+1)) );
-
-    // set sub_div so we can see it in perfly
-    eggNurbsCurve->subdiv = (numCV-1)*nurbs_step;
-
-    // get the CV's
-    SAA_DVector *cvArray;
-    cvArray = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numCV);
-    SAA_modelGetVertices( scene, model, SAA_GEOM_ORIGINAL, 0,
-        numCV, cvArray );
-
-    // create pool of NURBS vertices
-    EggVertexPool *pool = _data.CreateVertexPool( parent, name );
-    eggNurbsCurve->SetVertexPool( pool );
-
-    for ( int k = 0; k<numCV; k++ )
-    {
-        if ( verbose >= 2 )
-            fprintf( outStream, "cv[%d] = %f %f %f %f\n", k, cvArray[k].x,
-                cvArray[k].y, cvArray[k].z, cvArray[k].w );
-
-        pfVec4  eggVert;
-
-        // convert to global coords
-        SAA_DVector local = cvArray[k];
-        SAA_DVector global;
-
-        _HVCT_X_MAT( global, local, matrix );
-
-        eggVert.set( global.x, global.y, global.z, global.w );
-
-        // populate vertex pool
-        pool->AddVertex( eggVert, k );
-
-        // add vref's to NURBS info
-        eggNurbsCurve->AddVertex( k );
-    }
-
-    if ( closed )
-    {
-        // need to replicate first (degree) vertices
-        for ( k = 0; k < degree; k++ )
-        {
-            eggNurbsCurve->AddVertex( k );
-            if ( verbose >= 2 )
-                fprintf( outStream, "adding cv[%d] = %f %f %f %f\n", k,
-                    cvArray[k].x, cvArray[k].y, cvArray[k].z, cvArray[k].w );
-        }
-    }
-
-    // free( cvArray );
-
-    // set color to bright green for now
-    EggColor *nurbCref;
-    pfVec4    nurbColor;
-
-    nurbColor.set( 0.5, 1.0, 0.5, 1.0 );
-    nurbCref = _data.CreateColor(nurbColor);
-    eggNurbsCurve->attrib.SetCRef(nurbCref);
-
-    return( eggNurbsCurve );
-}
-
-/**
- * Given a parametric surface, and its knots, create the appropriate egg
- * structure by filling in Soft's implicit knots and assigning the rest to
- * eggKnots.
- */
-void soft2egg::
-AddKnots( perf_vector<double> &eggKnots, double *knots, int numKnots,
-    SAA_Boolean closed, int degree )
-{
-    int k = 0;
-    double lastKnot = knots[0];
-    double    *newKnots;
-
-    // add initial implicit knot(s)
-    if ( closed )
-    {
-        int i = 0;
-        newKnots = (double *)malloc(sizeof(double)*degree);
-
-        // need to add (degree) number of knots
-        for ( k = numKnots - 1; k >= numKnots - degree; k-- )
-        {
-            // we have to know these in order to calculate next knot value so
-            // hold them in temp array
-            newKnots[i] =  lastKnot - (knots[k] - knots[k-1]);
-            lastKnot = newKnots[i];
-            i++;
-        }
-        for ( k = degree - 1; k >= 0; k-- )
-        {
-            eggKnots.push_back( newKnots[k] );
-            if ( verbose >= 2 )
-                fprintf( outStream, "knots[%d] = %f\n", k, newKnots[k] );
-        }
-
-        // free( newKnots );
-    }
-    else
-    {
-        eggKnots.push_back( knots[k] );
-        if ( verbose >= 2 )
-            fprintf( outStream, "knots[%d] = %f\n", k, knots[k] );
-    }
-
-    // add the regular complement of knots
-    for (k = 0; k < numKnots; k++)
-    {
-        eggKnots.push_back( knots[k] );
-        if ( verbose >= 2 )
-            fprintf( outStream, "knots[%d] = %f\n", k+1, knots[k] );
-    }
-
-    lastKnot = knots[numKnots-1];
-
-    // add trailing implicit knots
-    if ( closed )
-    {
-
-        // need to add (degree) number of knots
-        for ( k = 1; k <= degree; k++ )
-        {
-            eggKnots.push_back( lastKnot + (knots[k] - knots[k-1]) );
-            if ( verbose >= 2 )
-                fprintf( outStream, "knots[%d] = %f\n", k,
-                    lastKnot + (knots[k] - knots[k-1]) );
-            lastKnot = lastKnot + (knots[k] - knots[k-1]);
-        }
-    }
-    else
-    {
-        eggKnots.push_back( knots[k-1] );
-        if ( verbose >= 2 )
-            fprintf( outStream, "knots[%d] = %f\n", k+1, knots[k-1] );
-    }
-}
-
-/**
- * Given a name, a parent and a model create a new a new EggJoint for that
- * model.
- */
-void soft2egg::
-MakeJoint( SAA_Scene *scene, EggJoint *&lastJoint, AnimGroup *&lastAnim,
-    SAA_Elem *model, char *name )
-{
-    float     matrix[4][4];
-    pfMatrix  Matrix;
-    EggJoint *joint;
-    SAA_Boolean    globalFlag = FALSE;
-    int    scale_joint = 0;
-
-
-    // this is a quick fix to make scaled skeletons possible if the parent
-    // contains the keyword "scale" make this joint a global root joint
-    // instead of a child...
-    if (lastJoint != NULL)
-    {
-        if ( strstr( lastJoint->name.Str(), "scale" ) != NULL )
-        {
-            scale_joint = 1;
-            if ( verbose >= 1 )
-                fprintf( outStream, "scale joint flag set!\n" );
-        }
-    }
-
-    // if not root, flatten is false, and last joint had no scaling applied to
-    // it, then create joint in skeleton tree
-    if ( (lastJoint != NULL) && !flatten && !scale_joint )
-    {
-        if ( verbose >= 1 )
-        {
-            fprintf( outStream, "lastJoint = %s\n", lastJoint->name.Str() );
-            fprintf( outStream, "getting local transform\n" );
-        }
-
-        SAA_elementSetUserData( scene, model, "GLOBAL", sizeof( SAA_Boolean ),
-            TRUE, (void  **)&globalFlag );
-
-        // get the local matrix
-        SAA_modelGetMatrix( scene, model, SAA_COORDSYS_LOCAL,  matrix );
-
-        // make this into a pfMatrix
-        Matrix[0][0] = matrix[0][0];
-        Matrix[0][1] = matrix[0][1];
-        Matrix[0][2] = matrix[0][2];
-        Matrix[0][3] = matrix[0][3];
-        Matrix[1][0] = matrix[1][0];
-        Matrix[1][1] = matrix[1][1];
-        Matrix[1][2] = matrix[1][2];
-        Matrix[1][3] = matrix[1][3];
-        Matrix[2][0] = matrix[2][0];
-        Matrix[2][1] = matrix[2][1];
-        Matrix[2][2] = matrix[2][2];
-        Matrix[2][3] = matrix[2][3];
-        Matrix[3][0] = matrix[3][0];
-        Matrix[3][1] = matrix[3][1];
-        Matrix[3][2] = matrix[3][2];
-        Matrix[3][3] = matrix[3][3];
-
-        joint = _data.CreateJoint( lastJoint, name );
-        joint->transform = Matrix;
-    }
-    // if we already have a root attach this joint to it
-    else if (foundRoot)
-    {
-        if ( verbose >= 1 )
-            fprintf( outStream, "getting global transform\n" );
-
-        globalFlag = TRUE;
-
-        SAA_elementSetUserData( scene, model, "GLOBAL", sizeof( SAA_Boolean ),
-            TRUE, (void *)&globalFlag );
-
-        // get the global matrix
-        SAA_modelGetMatrix( scene, model, SAA_COORDSYS_GLOBAL,  matrix );
-
-        // make this into a pfMatrix
-        Matrix[0][0] = matrix[0][0];
-        Matrix[0][1] = matrix[0][1];
-        Matrix[0][2] = matrix[0][2];
-        Matrix[0][3] = matrix[0][3];
-        Matrix[1][0] = matrix[1][0];
-        Matrix[1][1] = matrix[1][1];
-        Matrix[1][2] = matrix[1][2];
-        Matrix[1][3] = matrix[1][3];
-        Matrix[2][0] = matrix[2][0];
-        Matrix[2][1] = matrix[2][1];
-        Matrix[2][2] = matrix[2][2];
-        Matrix[2][3] = matrix[2][3];
-        Matrix[3][0] = matrix[3][0];
-        Matrix[3][1] = matrix[3][1];
-        Matrix[3][2] = matrix[3][2];
-        Matrix[3][3] = matrix[3][3];
-
-        if ( verbose >= 1 )
-            fprintf( outStream, "attaching orphan chain to root\n" );
-
-        joint = _data.CreateJoint( rootJnt, name );
-        joint->transform = Matrix;
-        lastAnim = rootAnim;
-    }
-    // if root, make a seperate tree for skeleton and create required Table
-    // for the Egg heirarchy
-    else
-    {
-        if ( verbose >= 1 )
-            fprintf( outStream, "getting global transform\n" );
-
-        globalFlag = TRUE;
-
-        SAA_elementSetUserData( scene, model, "GLOBAL", sizeof( SAA_Boolean ),
-            TRUE, (void *)&globalFlag );
-
-        // get the global matrix
-        SAA_modelGetMatrix( scene, model, SAA_COORDSYS_GLOBAL,  matrix );
-
-        // make this into a pfMatrix
-        Matrix[0][0] = matrix[0][0];
-        Matrix[0][1] = matrix[0][1];
-        Matrix[0][2] = matrix[0][2];
-        Matrix[0][3] = matrix[0][3];
-        Matrix[1][0] = matrix[1][0];
-        Matrix[1][1] = matrix[1][1];
-        Matrix[1][2] = matrix[1][2];
-        Matrix[1][3] = matrix[1][3];
-        Matrix[2][0] = matrix[2][0];
-        Matrix[2][1] = matrix[2][1];
-        Matrix[2][2] = matrix[2][2];
-        Matrix[2][3] = matrix[2][3];
-        Matrix[3][0] = matrix[3][0];
-        Matrix[3][1] = matrix[3][1];
-        Matrix[3][2] = matrix[3][2];
-        Matrix[3][3] = matrix[3][3];
-
-        rootJnt = _data.CreateJoint( skeleton, "root" );
-        rootJnt->transform.makeIdent();
-        if ( verbose >= 1 )
-            fprintf( outStream, "setting skeleton root\n" );
-        rootJnt->flags |= EF_TRANSFORM;
-
-        joint = _data.CreateJoint( rootJnt, name );
-        joint->transform = Matrix;
-        foundRoot = TRUE;
-        if ( verbose >= 1 )
-            fprintf( outStream, "found first chain\n" );
-
-        // make skeleton table
-        AnimGroup *skeletonTable;
-        skeletonTable = animData.CreateTable( animRoot, "<skeleton>" );
-        rootAnim = animData.CreateTable( skeletonTable, "root" );
-        XfmSAnimTable *table = new XfmSAnimTable( );
-        table->name = "xform";
-        table->fps = anim_rate;
-        rootAnim->children.push_back( table );
-        lastAnim = rootAnim;
-    }
-
-    joint->flags |= EF_TRANSFORM;
-
-    // if ( make_anim) {
-        AnimGroup *anim = animData.CreateTable( lastAnim, name );
-        XfmSAnimTable *table = new XfmSAnimTable( );
-        if ( verbose >= 1 )
-            fprintf( outStream, "created anim table: %s\n", "xform" );
-        table->name = "xform";
-        table->fps = anim_rate;
-        anim->children.push_back( table );
-        lastAnim = anim;
-    // }
-
-    // make this joint current parent of chain
-    lastJoint = joint;
-}
-
-
-/**
- * Given a skeleton part find its envelopes (if any) get the vertices
- * associated with the envelopes and their weights and make vertex ref's for
- * the joint
- */
-void soft2egg::
-MakeSoftSkin( SAA_Scene *scene, SAA_Elem *model, SAA_Elem *models,
-    int numModels, char *name )
-{
-    int            numEnv;
-    SAA_ModelType   type;
-    SAA_Elem    *envelopes;
-
-    if ( verbose >= 1 )
-        fprintf( outStream, "\n>found skeleton part( %s )!\n", name );
-
-    SAA_skeletonGetNbEnvelopes( scene, model, &numEnv );
-
-    if ( numEnv )
-    {
-        // it's got envelopes - must be soft skinned
-        if ( verbose >= 1 )
-            fprintf( outStream, "numEnv = %d\n", numEnv );
-
-        // allocate envelope array
-        envelopes = ( SAA_Elem *)malloc( sizeof( SAA_Elem )*numEnv );
-
-        if ( envelopes != NULL )
-        {
-            int         thisEnv;
-            SAA_EnvType envType;
-            bool        hasEnvVertices = 0;
-
-            SAA_skeletonGetEnvelopes( scene, model, numEnv, envelopes );
-
-            for ( thisEnv = 0; thisEnv < numEnv; thisEnv++ )
-            {
-                if ( verbose >= 1 )
-                    fprintf( outStream, "env[%d]: ", thisEnv );
-
-                SAA_envelopeGetType( scene, &envelopes[thisEnv], &envType );
-
-                if ( envType == SAA_ENVTYPE_NONE )
-                {
-                    if ( verbose >= 1 )
-                        fprintf( outStream, "envType = none\n" );
-                }
-                else if ( envType == SAA_ENVTYPE_FLXLCL )
-                {
-                    if ( verbose >= 1 )
-                        fprintf( outStream, "envType = flexible, local\n" );
-                    hasEnvVertices = 1;
-                }
-                else if ( envType == SAA_ENVTYPE_FLXGLB )
-                {
-                    if ( verbose >= 1 )
-                        fprintf( outStream, "envType = flexible, global\n" );
-                    hasEnvVertices = 1;
-                }
-                else if ( envType == SAA_ENVTYPE_RGDGLB )
-                {
-                    if ( verbose >= 1 )
-                        fprintf( outStream, "envType = rigid, global\n" );
-                    hasEnvVertices = 1;
-                }
-                else
-                {
-                    if ( verbose >= 1 )
-                        fprintf( outStream, "envType = unknown\n" );
-                }
-            }
-
-            if ( hasEnvVertices)
-            {
-                int            *numEnvVertices;
-                SAA_SubElem    *envVertices = NULL;
-
-                numEnvVertices = (int *)malloc(sizeof(int)*numEnv);
-
-                SAA_envelopeGetNbCtrlVertices( scene, model, numEnv,
-                    envelopes, numEnvVertices );
-
-                if ( numEnvVertices != NULL )
-                {
-                    int totalEnvVertices = 0;
-                    int    i,j,k;
-
-                    for( i = 0; i < numEnv; i++ )
-                    {
-                        totalEnvVertices += numEnvVertices[i];
-                        if ( verbose >= 1 )
-                            fprintf( outStream, "numEnvVertices[%d] = %d\n",
-                                i, numEnvVertices[i] );
-                    }
-
-
-                    if ( verbose >= 1 )
-                        fprintf( outStream, "total env verts = %d\n",
-                            totalEnvVertices );
-
-                    if ( totalEnvVertices )
-                    {
-                    envVertices = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*totalEnvVertices);
-
-                    if ( envVertices != NULL )
-                    {
-
-                        SAA_envelopeGetCtrlVertices( scene, model,
-                            numEnv, envelopes, numEnvVertices, envVertices);
-
-                        // loop through for each envelope
-                        for ( i = 0; i < numEnv; i++ )
-                        {
-                            float *weights = NULL;
-                            int       vertArrayOffset = 0;
-
-                            if ( verbose >= 2 )
-                                fprintf( outStream, "\nenvelope[%d]:\n", i );
-
-                            weights = (float *)malloc(sizeof(float)*numEnvVertices[i]);
-
-                            if ( weights )
-                            {
-                            char *envName;
-                            int *vpoolMap = NULL;
-
-                            for ( j = 0; j < i; j++ )
-                                vertArrayOffset += numEnvVertices[j];
-
-                            if ( verbose >= 1 )
-                                fprintf( outStream,
-                                    "envVertArray offset = %d\n",
-                                    vertArrayOffset );
-
-                            // get the weights of the envelope vertices
-                            SAA_ctrlVertexGetEnvelopeWeights(
-                                    scene, model, &envelopes[i],
-                                    numEnvVertices[i],
-                                    &envVertices[vertArrayOffset], weights );
-
-                            // Get the name of the envelope model
-                            if ( use_prefix )
-                            {
-                                // Get the FULL name of the envelope
-                                envName = GetFullName( scene, &envelopes[i] );
-                            }
-                            else
-                            {
-                                // Get the name of the envelope
-                                envName = GetName( scene, &envelopes[i] );
-                            }
-
-                            if ( verbose >= 1 )
-                                fprintf( outStream, "envelope name %s\n", envName );
-
-                            // find out if envelope geometry is poly or nurb
-                            // SAA_modelGetType( scene, FindModelByName(
-                            // envName, scene, models, numModels ), &type );
-
-                            SAA_modelGetType( scene, &envelopes[i], &type );
-
-                            if ( verbose >= 1 )
-                            {
-                                fprintf( outStream, "envelope model type ");
-
-                                if ( type == SAA_MSMSH )
-                                        fprintf( outStream, "MESH\n" );
-                                else if ( type == SAA_MNSRF )
-                                        fprintf( outStream, "NURBS\n" );
-                                else
-                                        fprintf( outStream, "OTHER\n" );
-                           }
-
-                            int *envVtxIndices = NULL;
-                            envVtxIndices = (int *)malloc(sizeof(int)*numEnvVertices[i]);
-
-                            // Get the envelope vertex indices
-                            SAA_ctrlVertexGetIndices( scene, &envelopes[i],                                     numEnvVertices[i],
-                                &envVertices[vertArrayOffset], envVtxIndices );
-
-                            // find out how many vertices the model has
-                            int modelNumVert;
-
-                            SAA_modelGetNbVertices( scene, &envelopes[i], &modelNumVert );
-
-                            SAA_DVector *modelVertices = NULL;
-                            modelVertices = (SAA_DVector *)malloc(sizeof(SAA_DVector)*modelNumVert);
-
-                            // get the model vertices
-                            SAA_modelGetVertices( scene, &envelopes[i],
-                                SAA_GEOM_ORIGINAL, 0, modelNumVert,
-                                modelVertices );
-
-                            // create array of global model coords
-                            SAA_DVector *globalModelVertices = NULL;
-                            globalModelVertices = (SAA_DVector *)malloc(sizeof(SAA_DVector)*modelNumVert);
-                            float        matrix[4][4];
-
-                            // tranform local model vert coords to global
-
-                            // first get the global matrix
-                            SAA_modelGetMatrix( scene, &envelopes[i],                                                 SAA_COORDSYS_GLOBAL,  matrix );
-
-                            // populate array of global model verts
-                            for ( j = 0; j < modelNumVert; j++ )
-                            {
-                                _VCT_X_MAT( globalModelVertices[j],
-                                    modelVertices[j], matrix );
-                            }
-
-                            // find the egg vertex pool that corresponds to
-                            // this envelope model
-                            EggVertexPool *envPool =
-                                (EggVertexPool *)(_data.pools.FindName( envName ));
-                            // If we are outputting triangles: create an array
-                            // that maps from a referenced vertex in the
-                            // envelope to a corresponding vertex in the egg
-                            // vertex pool if ( (type == SAA_MNSRF) &&
-                            // !make_nurbs )
-                            if ( !make_nurbs || (type == SAA_MSMSH) )
-                            {
-                                vpoolMap = FindClosestTriVert( envPool,
-                                    globalModelVertices, modelNumVert );
-                            }
-
-
-                            if ( envPool != NULL )
-                            {
-
-                            // find the egg joint that corresponds to this
-                            // model
-                            EggJoint *joint =
-                                (EggJoint *)(skeleton->FindDescendent( name ));
-
-                            // this doesn't seem to be necessary 4799 EggJoint
-                            // *parent = (EggJoint *)joint->parent;
-                            // assert(parent->IsA(NT_EggJoint));
-
-                            // for every envelope vertex
-                            for (j = 0; j < numEnvVertices[i]; j++)
-                            {
-                                double scaledWeight =  weights[j]/ 100.0f;
-
-                                // make sure its in legal range
-                                if (( envVtxIndices[j] < modelNumVert )
-                                    && ( envVtxIndices[j] >= 0 ))
-                                {
-                                  if ( (type == SAA_MNSRF) && make_nurbs )
-                                  {
-                                    // assign all referenced control vertices
-                                    joint->AddVertex( envPool->Vertex(envVtxIndices[j]), scaledWeight );
-
-                                    if ( verbose >= 2 )
-                                        fprintf( outStream,
-                                            "%d: adding vref to cv %d with weight %f\n",
-                                            j, envVtxIndices[j], scaledWeight );
-
-                                    envPool->Vertex(envVtxIndices[j])->AddJoint( joint, scaledWeight );
-                                    // set flag to show this vertex has been
-                                    // assigned
-                                    envPool->Vertex(envVtxIndices[j])->multipleJoints = 1;
-                                  }
-                                  else
-                                  {
-                                    // assign all the tri verts associated
-                                    // with this control vertex to joint
-                                    for ( k = 0; k < envPool->NumVertices(); k++ )
-                                    {
-                                      if ( vpoolMap[k] == envVtxIndices[j] )
-                                      {
-
-                                        // add each vert in pool to last joint
-                                        // for soft skinning
-                                        joint->AddVertex(envPool->Vertex(k),
-                                            scaledWeight);
-
-                                        if ( verbose >= 2 )
-                                            fprintf( outStream,
-                                                "%d: adding vref from cv %d to vert %d with weight %f(vpool)\n",
-                                                j, envVtxIndices[j], k, scaledWeight );
-
-                                        envPool->Vertex(k)->AddJoint( joint, scaledWeight );
-                                        // set flag to show this vertex has
-                                        // been assigned
-                                        envPool->Vertex(k)->multipleJoints = 1;
-                                      }
-                                    }
-                                 }
-                                }
-                                else
-                                    if ( verbose >= 2 )
-                                        fprintf( outStream,
-                                            "%d: Omitted vref from cv %d with weight %f (out of range 0 to %d )\n",
-                                            j, envVtxIndices[j], scaledWeight, modelNumVert );
-                            }
-
-                            }
-                            else
-                                if ( verbose >= 2 )
-                                    fprintf( outStream, "Couldn't find vpool %s!\n", envName );
-
-                            // free( modelVertices ); free(
-                            // globalModelVertices ); free( envVtxIndices );
-                            // free( envName );
-                            } //if (weights)
-                            // free( weights );
-
-                        } // for i
-
-                    } // if (envVertices != NULL)
-                    else
-                        fprintf( outStream, "Not enough memory for envelope vertices...\n");
-                    // free( envVertices );
-                    } // if (totalEnvVertices)
-                    else
-                        if ( verbose >= 1 )
-                            fprintf( outStream, "No envelope vertices present...\n");
-
-                    // free( numEnvVertices );
-
-            } // if (numEnvVertices != NULL)
-
-          } // if (hasEnvVertices)
-
-        } // if (envelopes != NULL)
-        else
-            fprintf( outStream, "Not enough memory for envelopes...\n" );
-
-        // free( envelopes );
-
-    } //if (numEnv)
-
-    else
-        if ( verbose >= 1 )
-            fprintf( outStream, "Skeleton member has no envelopes...\n" );
-}
-
-
-/**
- * Given a model, make sure all its vertices have been soft assigned.  If not
- * hard assign to the last joint we saw.
- */
-void soft2egg::
-CleanUpSoftSkin( SAA_Scene *scene, SAA_Elem *model, char *name )
-{
-    static EggJoint *joint;
-    SAA_Elem        parent;
-    SAA_ModelType     type;
-    SAA_Boolean        skel;
-
-    // find out what type of node we're dealing with
-    SAA_modelGetType( scene, model, &type );
-
-    char   *parentName;
-    int        level;
-    SAA_Elem    *searchNode = model;
-
-    if ( verbose >= 1 )
-        fprintf( outStream, "\nCleaning up model %s\n", name );
-
-    // this step is weird - I think I want it here but it seems to break some
-    // models.  Files like props-props_wh_cookietime.3-0 in
-    // fulrndpubvrmlchipchips_adventurecharzone1roomswarehouse_final need to
-    // do the "if (skel)" bit.
-
-    // am I a skeleton too?
-    SAA_modelIsSkeleton( scene, model, &skel );
-
-    // if not look for the last skeleton part
-    if ( skel )
-        parentName = name;
-    else do
-    {
-        SAA_elementGetHierarchyLevel( scene, searchNode, &level );
-
-        // make sure we don't try to get the root's parent
-        if ( level )
-        {
-            SAA_modelGetParent( scene, searchNode, &parent );
-
-            if ( use_prefix )
-            {
-                // Get the FULL name of the parent
-                parentName = GetFullName( scene, &parent );
-            }
-            else
-            {
-                // Get the name of the parent
-                parentName = GetName( scene, &parent );
-            }
-
-            SAA_modelGetType( scene, &parent, &type );
-
-            SAA_modelIsSkeleton( scene, &parent, &skel );
-
-            if ( verbose >= 1 )
-                fprintf( outStream, "model %s, level %d, type %d, skel %d\n",
-                    parentName, level, type, skel );
-
-            searchNode = &parent;
-        }
-        else
-        {
-            // we reached the root of the tree
-            parentName = NULL;
-            if ( verbose >= 1 )
-                fprintf( outStream, "at root of tree! level %d\n", level );
-            break;
-        }
-
-    // look until parent is a joint or acts like one
-    } while ( !skel && ( strstr( parentName,"joint") == NULL ));
-
-    EggJoint    *thisJoint = NULL;
-
-    if ( parentName != NULL )
-    {
-        if ( verbose >= 1 )
-        {
-            fprintf( outStream, "found model parent joint %s\n", parentName);
-            fprintf( outStream, "looking for joint %s\n", parentName );
-        }
-        thisJoint = (EggJoint *)(skeleton->FindDescendent( parentName ));
-    }
-    else
-        if ( verbose >= 1 )
-                fprintf( outStream, "Couldn't find parent joint!\n");
-
-    if ( thisJoint != NULL )
-    {
-        joint = thisJoint;
-        if ( verbose >= 1 )
-            fprintf( outStream, "setting joint to %s\n", parentName );
-
-        // find the vpool for this model
-        EggVertexPool *vPool =
-            (EggVertexPool *)(_data.pools.FindName( name ));
-
-        if (vPool != NULL)
-        {
-            int i;
-            double membership;
-            int numVerts = vPool->NumVertices() ;
-
-
-            if ( verbose >= 1 )
-                fprintf( outStream, "found vpool %s w/ %d verts\n",
-                name, numVerts );
-
-            for ( i = 0; i < numVerts; i++ )
-            {
-                if ( vPool->Vertex(i)->multipleJoints != 1 )
-                {
-                    if ( verbose >= 1 )
-                    {
-                        fprintf( outStream, "vpool %s vert %d", name, i );
-                        fprintf( outStream, " not assigned!\n" );
-                    }
-
-                    // hard skin this vertex
-                    joint->AddVertex( vPool->Vertex(i), 1.0f );
-                }
-                else
-                {
-                    membership = vPool->Vertex(i)->NetMembership();
-
-
-                    if ( verbose >= 1 )
-                    {
-                        fprintf( outStream, "vpool %s vert %d", name,
-                            i );
-                        fprintf( outStream, " has membership %f\n",
-                            membership );
-                    }
-
-                    if ( membership == 0 )
-                    {
-                        if ( verbose >= 1 )
-                            fprintf( outStream, "adding full weight..\n" );
-
-                        // hard skin this vertex
-                        joint->AddVertex( vPool->Vertex(i), 1.0f );
-                    }
-                }
-            }
-        }
-        else
-            if ( verbose >= 1 )
-                fprintf( outStream, "couldn't find vpool %s\n", name );
-    }
-    else
-    {
-        if ( parentName != NULL )
-            if ( verbose >= 1 )
-                fprintf( outStream, "Couldn't find joint %s\n", parentName );
-    }
-}
-
-/**
- * Given a scene and a skeleton part ,get all the position, rotation, and
- * scale for the skeleton part for this frame and write them out as Egg
- * animation tables.
- */
-void soft2egg::
-MakeAnimTable( SAA_Scene *scene, SAA_Elem *skeletonPart, char *name )
-{
-
-    if ( skeletonPart != NULL )
-    {
-        float    i,j,k;
-        float    h,p,r;
-        float    x,y,z;
-        int         size;
-        SAA_Boolean globalFlag = FALSE;
-        SAA_Boolean bigEndian;
-
-        if ( verbose >= 1 )
-            fprintf( outStream, "\n\nanimating child %s\n", name );
-
-        SAA_elementGetUserDataSize( scene, skeletonPart, "GLOBAL", &size );
-
-        if ( size != 0 )
-            SAA_elementGetUserData( scene, skeletonPart, "GLOBAL",
-                sizeof( SAA_Boolean), &bigEndian, (void *)&globalFlag );
-
-        if ( globalFlag )
-        {
-            if ( verbose >= 1 )
-                fprintf( outStream, " using global matrix\n" );
-
-            // get SAA orientation
-            SAA_modelGetRotation( scene, skeletonPart, SAA_COORDSYS_GLOBAL,
-                &p, &h, &r );
-
-            // get SAA translation
-            SAA_modelGetTranslation( scene, skeletonPart, SAA_COORDSYS_GLOBAL,
-                &x, &y, &z );
-
-            // get SAA scaling
-            SAA_modelGetScaling( scene, skeletonPart, SAA_COORDSYS_GLOBAL,
-                &i, &j, &k );
-        }
-        else
-        {
-            if ( verbose >= 1 )
-                fprintf( outStream, "using local matrix\n" );
-
-            // get SAA orientation
-            SAA_modelGetRotation( scene, skeletonPart, SAA_COORDSYS_LOCAL,
-                &p, &h, &r );
-
-            // get SAA translation
-            SAA_modelGetTranslation( scene, skeletonPart, SAA_COORDSYS_LOCAL,
-                &x, &y, &z );
-
-            // get SAA scaling
-            SAA_modelGetScaling( scene, skeletonPart, SAA_COORDSYS_LOCAL,
-                &i, &j, &k );
-        }
-
-
-        if ( verbose >= 2 )
-            fprintf( outStream, "\nanim data: %f %f %f\n\t%f %f %f\n\t%f %f %f\n",
-                i, j, k, h, p, r, x, y, z );
-
-        // find the appropriate anim table for this skeleton part
-        AnimGroup     *thisGroup;
-        XfmSAnimTable *thisTable;
-
-        // find the anim table associated with this group
-        thisGroup = (AnimGroup *)(animRoot->FindDescendent( name ));
-        if ( verbose >= 2 )
-            fprintf( outStream, "\nlooking for anim group %s\n", name );
-        if ( thisGroup != NULL )
-        {
-            thisTable = (XfmSAnimTable *)(thisGroup->FindDescendent( "xform" ));
-
-            if ( thisTable != NULL )
-            {
-                thisTable->sub_tables[0].AddElement( i );
-                thisTable->sub_tables[1].AddElement( j );
-                thisTable->sub_tables[2].AddElement( k );
-                thisTable->sub_tables[3].AddElement( p );
-                thisTable->sub_tables[4].AddElement( h );
-                thisTable->sub_tables[5].AddElement( r );
-                thisTable->sub_tables[6].AddElement( x );
-                thisTable->sub_tables[7].AddElement( y );
-                thisTable->sub_tables[8].AddElement( z );
-            }
-            else
-                fprintf( outStream, "Couldn't allocate anim table\n" );
-        }
-        else
-            if ( verbose >= 2 )
-                fprintf( outStream, "Couldn't find anim group  %s\n",  name );
-    }
-    else
-    {
-        if ( verbose >= 2 )
-            fprintf( outStream, "Cannot build anim table - no skeleton\n" );
-    }
-}
-
-/**
- * Given a scene, a model , the vertices of its original shape and its name
- * find the difference between the geometry of its key shapes and the models
- * original geometry and add morph vertices to the egg data to reflect these
- * changes.
- */
-void soft2egg::
-MakeVertexOffsets( SAA_Scene *scene, SAA_Elem *model, SAA_ModelType type,
-    int numShapes, int numOrigVert, SAA_DVector *originalVerts, float
-    matrix[4][4], char *name )
-{
-    int i, j;
-    int offset;
-    int    numCV;
-    char *mTableName;
-    SAA_DVector *shapeVerts = NULL;
-    SAA_DVector *uniqueVerts = NULL;
-
-    if ( (type == SAA_MNSRF) && make_nurbs )
-        SAA_nurbsSurfaceSetStep( scene, model, nurbs_step, nurbs_step );
-
-    SAA_modelGetNbVertices( scene, model, &numCV );
-
-    // get the shape verts
-    uniqueVerts = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numCV);
-    SAA_modelGetVertices( scene, model, SAA_GEOM_ORIGINAL, 0,
-        numCV, uniqueVerts );
-
-    if ( verbose >= 2 )
-        fprintf( outStream, "%d CV's\n", numCV );
-
-    if ( verbose >= 2 )
-    {
-        for ( i = 0; i < numCV; i++ )
-            fprintf( outStream, "uniqueVerts[%d] = %f %f %f %f\n", i,
-                uniqueVerts[i].x, uniqueVerts[i].y,
-                uniqueVerts[i].z,  uniqueVerts[i].w );
-    }
-
-    // iterate through for each key shape (except original)
-    for ( i = 1; i < numShapes; i++ )
-    {
-        mTableName = MakeTableName( name, i );
-
-        if ( verbose >= 1 )
-        {
-            fprintf( outStream, "\nMaking geometry offsets for %s...\n",
-                mTableName );
-
-            if ( (type == SAA_MNSRF) && make_nurbs )
-                fprintf( outStream, "calculating NURBS morphs...\n" );
-            else
-                fprintf( outStream, "calculating triangle morphs...\n" );
-        }
-
-        // get the shape verts
-        shapeVerts = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numCV);
-        SAA_modelGetVertices( scene, model, SAA_GEOM_SHAPE, i+1,
-            numCV, shapeVerts );
-
-        if ( verbose >= 2 )
-        {
-            for ( j=0; j < numCV; j++ )
-            {
-                fprintf( outStream, "shapeVerts[%d] = %f %f %f\n", j,
-                    shapeVerts[j].x, shapeVerts[j].y, shapeVerts[j].z );
-            }
-        }
-
-        // find the appropriate vertex pool
-        EggVertexPool *vPool =
-            (EggVertexPool *)(_data.pools.FindName( name ));
-
-        // for every original vertex, compare to the corresponding key shape
-        // vertex and see if a vertex offset is needed
-        for ( j=0; j < numOrigVert; j++ )
-        {
-            double    dx, dy, dz;
-
-            if ( (type == SAA_MNSRF) && make_nurbs )
-            {
-                // dx = shapeVerts[j].x -
-                // (originalVerts[j].xoriginalVerts[j].w); dy =
-                // shapeVerts[j].y - (originalVerts[j].yoriginalVerts[j].w);
-                // dz = shapeVerts[j].z -
-                // (originalVerts[j].zoriginalVerts[j].w);
-                dx = shapeVerts[j].x - originalVerts[j].x;
-                dy = shapeVerts[j].y - originalVerts[j].y;
-                dz = shapeVerts[j].z - originalVerts[j].z;
-            }
-            else
-            {
-                // we need to map from original vertices to triangle shape
-                // vertices here
-                offset = findShapeVert( originalVerts[j], uniqueVerts,
-                    numCV );
-
-                dx = shapeVerts[offset].x - originalVerts[j].x;
-                dy = shapeVerts[offset].y - originalVerts[j].y;
-                dz = shapeVerts[offset].z - originalVerts[j].z;
-            }
-
-            if ( verbose >= 2 )
-            {
-                fprintf( outStream, "oVert[%d] = %f %f %f %f\n", j,
-                    originalVerts[j].x, originalVerts[j].y,
-                    originalVerts[j].z,  originalVerts[j].w );
-
-                if ( (type == SAA_MNSRF) && make_nurbs )
-                {
-                    fprintf( outStream, "global shapeVerts[%d] = %f %f %f %f\n",                        j, shapeVerts[j].x, shapeVerts[j].y,
-                        shapeVerts[j].z, shapeVerts[j].w );
-                }
-                else
-                {
-                    fprintf( outStream,
-                        "global shapeVerts[%d] = %f %f %f\n", offset,
-                        shapeVerts[offset].x,
-                        shapeVerts[offset].y,
-                        shapeVerts[offset].z );
-                }
-
-                fprintf( outStream, "%d: dx = %f, dy = %f, dz = %f\n", j,
-                    dx, dy, dz );
-            }
-
-            // if change isn't negligible, make a morph vertex entry
-            double total = fabs(dx)+fabs(dy)+fabs(dz);
-            if ( total > 0.00001 )
-            {
-                if ( vPool != NULL )
-                {
-                    // create offset
-                    EggMorphOffset *dxyz =
-                        new EggMorphOffset( mTableName, dx, dy, dz );
-
-                    EggVertex *eggVert;
-
-                    // get the appropriate egg vertex
-                    eggVert = vPool->Vertex(j);
-
-                    // add the offset to the vertex
-                    eggVert->morphs.push_back( *dxyz );
-                }
-                else
-                    fprintf( outStream, "Error: couldn't find vertex pool %s\n", name );
-            } // if total
-        } //for j
-    } //for i
-}
-
-
-/**
- * Given a scene, a model, a name and a frame time, determine what type of
- * shape interpolation is used and call the appropriate function to extract
- * the shape weight info for this frame...
- */
-void soft2egg::
-MakeMorphTable( SAA_Scene *scene, SAA_Elem *model, SAA_Elem *models,
-    int numModels, char *name, float time )
-{
-    int         numShapes;
-    SAA_AnimInterpType    type;
-
-    // Get the number of key shapes
-    SAA_modelGetNbShapes( scene, model, &numShapes );
-
-    if ( numShapes > 0 )
-    {
-        if ( verbose >= 1 )
-            fprintf( outStream, "MakeMorphTable: %s: num shapes: %d\n",
-                name, numShapes);
-
-        SAA_modelGetShapeInterpolation( scene, model, &type );
-
-        if ( type == SAA_ANIM_LINEAR || type == SAA_ANIM_CARDINAL )
-        {
-            MakeLinearMorphTable( scene, model, numShapes, name, time );
-        }
-        else     // must be weighted...
-        {
-            // check first for expressions
-            MakeExpressionMorphTable( scene, model, models, numModels,
-                numShapes, name, time );
-        }
-
-    }
-}
-
-
-/**
- * Given a scene, a model, its name, and the time, get the shape fcurve for
- * the model and determine the shape weights for the given time and use them
- * to populate the morph table.
- */
-void soft2egg::
-MakeLinearMorphTable( SAA_Scene *scene, SAA_Elem *model, int numShapes,
-    char *name, float time )
-{
-    int            i;
-    SAA_Elem     fcurve;
-    float        curveVal;
-    SAnimTable *thisTable;
-    char          *tableName;
-
-    if ( verbose >= 1 )
-        fprintf( outStream, "linear interp, getting fcurve\n" );
-
-    SAA_modelFcurveGetShape( scene, model, &fcurve );
-
-    SAA_fcurveEval( scene, &fcurve, time, &curveVal );
-
-    if ( verbose >= 2 )
-        fprintf( outStream, "at time %f, fcurve for %s = %f\n", time,
-            name, curveVal );
-
-    float nextVal = 0.0f;
-
-    // populate morph table values for this frame
-    for ( i = 1; i < numShapes; i++ )
-    {
-        // derive table name from the model name
-        tableName = MakeTableName( name, i );
-
-        if ( verbose >= 2 )
-            fprintf( outStream, "Linear: looking for table '%s'\n", tableName );
-
-        // find the morph table associated with this key shape
-        thisTable = (SAnimTable *)(morphRoot->FindDescendent( tableName ));
-
-        if ( thisTable != NULL )
-        {
-            if ( i == (int)curveVal )
-            {
-                if ( curveVal - i == 0 )
-                {
-                    thisTable->AddElement( 1.0f );
-                    if ( verbose >= 2 )
-                        fprintf( outStream, "adding element 1.0f\n" );
-                }
-                else
-                {
-                    thisTable->AddElement( 1.0f - (curveVal - i) );
-                    nextVal = curveVal - i;
-                    if ( verbose >= 2 )
-                        fprintf( outStream, "adding element %f\n",                                                 1.0f - (curveVal - i) );
-                }
-            }
-            else
-            {
-                if ( nextVal )
-                {
-                    thisTable->AddElement( nextVal );
-                    nextVal = 0.0f;
-                    if ( verbose >= 2 )
-                        fprintf( outStream, "adding element %f\n", nextVal );
-                }
-                else
-                {
-                    thisTable->AddElement( 0.0f );
-                    if ( verbose >= 2 )
-                        fprintf( outStream, "adding element 0.0f\n" );
-                }
-            }
-
-            if ( verbose >= 2 )
-                fprintf( outStream, " to '%s'\n", tableName );
-        }
-        else
-            fprintf( outStream, "%d: Couldn't find table '%s'\n",
-                i, tableName );
-    }
-
-}
-
-/**
- * Given a scene, a model, a list of all models in the scene, the number of
- * models in the scece, the number of key shapes for this model, the name of
- * the model and the current time, determine what method of controlling the
- * shape weights is used and call the appropriate routine.
- */
-void soft2egg::
-MakeWeightedMorphTable( SAA_Scene *scene, SAA_Elem *model, SAA_Elem *models,
-    int numModels,  int numShapes, char *name, float time )
-{
-    SI_Error     result;
-    SAA_Elem    *weightCurves;
-    float         curveVal;
-    SAnimTable *thisTable;
-    char          *tableName;
-
-    // allocate array of weight curves (one for each shape)
-    weightCurves = ( SAA_Elem *)malloc( sizeof( SAA_Elem ) * numShapes );
-
-    result = SAA_modelFcurveGetShapeWeights(
-        scene, model, numShapes, weightCurves );
-
-    if ( result == SI_SUCCESS )
-    {
-        for ( int i = 1; i < numShapes; i++ )
-        {
-                                                SAA_fcurveEval( scene, &weightCurves[i], time, &curveVal );
-
-                                                // make sure soft gave us a
-                                                // reasonable number
-                                                if (!isNum(curveVal))
-                                                        curveVal = 0.0f;
-
-                                                if ( verbose >= 2 )
-                                                                fprintf( outStream, "at time %f, weightCurve[%d] for %s = %f\n",                     time, i, name, curveVal );
-
-
-            // derive table name from the model name
-            tableName = MakeTableName( name, i );
-
-                                                // find and populate shape
-                                                // table
-            if ( verbose >= 2 )
-                fprintf( outStream, "Weight: looking for table '%s'\n",
-                                                                tableName );
-
-            // find the morph table associated with this key shape
-            thisTable = (SAnimTable *)(morphRoot->FindDescendent( tableName ));
-
-            if ( thisTable != NULL )
-            {
-                thisTable->AddElement( curveVal );
-                if ( verbose >= 2 )
-                    fprintf( outStream, "adding element %f\n", curveVal );
-            }
-            else
-                fprintf( outStream, "%d: Couldn't find table '%s'\n",
-                    i, tableName );
-        }
-    }
-}
-
-
-/**
- * Given a scene, a model and its number of key shapes generate a morph table
- * describing transitions btwn the key shapes by evaluating the positions of
- * the controlling sliders.
- */
-void soft2egg::
-MakeExpressionMorphTable( SAA_Scene *scene, SAA_Elem *model, SAA_Elem *models,
-    int numModels,  int numShapes, char *name, float time )
-{
-    int            j;
-    SAnimTable *thisTable;
-    char          *tableName;
-    char          *sliderName;
-    char        *track;
-    int            numExp;
-    SAA_Elem   *expressions;
-    float        expVal;
-    float        sliderVal;
-
-    // populate morph table values for this frame
-
-    // compose track name
-    track = NULL;
-
-    // find how many expressions for this shape
-    SAA_elementGetNbExpressions( scene, model, track, FALSE, &numExp );
-
-    if ( verbose >= 2 )
-        fprintf( outStream, "%s has %d RHS expressions\n", name, numExp );
-
-    if ( numExp )
-    {
-        // get the expressions for this shape
-        expressions = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numExp);
-
-        if ( verbose >= 1 )
-            fprintf( outStream, "getting %d RHS expressions...\n", numExp );
-
-        result = SAA_elementGetExpressions( scene, model, track, FALSE,
-            numExp, expressions );
-
-        if ( !result )
-        {
-            for ( j = 1; j < numExp; j++ )
-            {
-                if ( verbose >= 2 )
-                {
-                // debug see what we got
-                int numvars;
-
-                SAA_expressionGetNbVars( scene, &expressions[j], &numvars );
-
-                int *varnamelen;
-                int *varstrlen;
-                int  expstrlen;
-
-                varnamelen = (int *)malloc(sizeof(int)*numvars);
-                varstrlen = (int *)malloc(sizeof(int)*numvars);
-
-                SAA_expressionGetStringLengths( scene, &expressions[j],
-                    numvars, varnamelen, varstrlen, &expstrlen );
-
-                int *varnamesizes;
-                int *varstrsizes;
-
-                varnamesizes = (int *)malloc(sizeof(int)*numvars);
-                varstrsizes = (int *)malloc(sizeof(int)*numvars);
-
-                for ( int k = 0; k < numvars; k++ )
-                {
-                    varnamesizes[k] = varnamelen[k] + 1;
-                    varstrsizes[k] = varstrlen[k] + 1;
-                }
-
-                int expstrsize = expstrlen + 1;
-
-                char **varnames;
-                char **varstrs;
-
-                varnames = (char **)malloc(sizeof(char *)*numvars);
-                varstrs = (char **)malloc(sizeof(char *)*numvars);
-
-                for ( k = 0; k < numvars; k++ )
-                {
-                    varnames[k] = (char *)malloc(sizeof(char)*
-                        varnamesizes[k]);
-
-                    varstrs[k] = (char *)malloc(sizeof(char)*
-                        varstrsizes[k]);
-                }
-
-                char *expstr = (char *)malloc(sizeof(char)* expstrsize );
-
-                SAA_expressionGetStrings( scene, &expressions[j], numvars,
-                    varnamesizes, varstrsizes, expstrsize, varnames,
-                    varstrs, expstr );
-
-                if ( verbose >= 2 )
-                {
-                    fprintf( outStream, "expression = '%s'\n", expstr );
-                    fprintf( outStream, "has %d variables\n", numvars );
-                }
-                } //if verbose
-
-                if ( verbose >= 2 )
-                    fprintf( outStream, "evaling expression...\n" );
-
-                SAA_expressionEval( scene, &expressions[j], time, &expVal );
-
-                if ( verbose >= 2 )
-                    fprintf( outStream, "time %f: exp val %f\n",
-                        time, expVal );
-
-                // derive table name from the model name
-                tableName = MakeTableName( name, j );
-
-                if ( verbose >= 2 )
-                    fprintf( outStream, "Exp: looking for table '%s'\n",
-                        tableName );
-
-                // find the morph table associated with this key shape
-                thisTable = (SAnimTable *)
-                    (morphRoot->FindDescendent( tableName ));
-
-                if ( thisTable != NULL )
-                {
-                    thisTable->AddElement( expVal );
-                    if ( verbose >= 1 )
-                        fprintf( outStream, "%d: adding element %f to %s\n",
-                            j, expVal, tableName );
-                    fflush( outStream );
-                }
-                else
-                {
-                    fprintf( outStream, "%d: Couldn't find table '%s'", j,
-                            tableName );
-
-                    fprintf( outStream, " for value %f\n", expVal );
-                }
-            }
-        }
-        else
-            fprintf( outStream, "couldn't get expressions!!!\n" );
-    }
-    else
-        // no expression, use weight curves
-        MakeWeightedMorphTable( scene, model, models, numModels,
-            numShapes, name, time );
-
-}
-
-
-/**
- * Given a scene, a POLYGON model, and the name of the that model, get the u
- * and v offsets for the current frame.
- */
-void soft2egg::
-MakeTexAnim( SAA_Scene *scene, SAA_Elem *model, char *modelName )
-{
-    if ( verbose >= 1 )
-        fprintf( outStream, "\n\nmaking texture animation for %s...\n",
-            modelName );
-
-    // get the color of the surface
-    int         numMats;
-    pfVec4        Color;
-    SAA_Elem    *materials;
-    void        *relinfo;
-
-    SAA_modelRelationGetMatNbElements( scene, model, FALSE, &relinfo,
-        &numMats );
-
-    if ( verbose >= 2 )
-        fprintf( outStream, "surface has %d materials\n", numMats );
-
-    if ( numMats )
-    {
-        float r,g,b,a;
-
-        materials = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numMats);
-
-        SAA_modelRelationGetMatElements( scene, model, relinfo,
-            numMats, materials );
-
-        SAA_materialGetDiffuse( scene, &materials[0], &r, &g, &b );
-        SAA_materialGetTransparency( scene, &materials[0], &a );
-        Color.set( r, g, b, 1.0f - a );
-
-        int numTexLoc = 0;
-        int numTexGlb = 0;
-
-        // ASSUME only one texture per material
-        SAA_Elem tex;
-
-        // find out how many local textures per surface ASSUME it only has one
-        // material
-        SAA_materialRelationGetT2DLocNbElements( scene, &materials[0],
-            FALSE, &relinfo, &numTexLoc );
-
-        // if present, get local textures
-        if ( numTexLoc )
-        {
-            if ( verbose >= 1 )
-                fprintf( outStream, "%s had %d local tex\n", modelName,
-                    numTexLoc );
-
-            // get the referenced texture
-            SAA_materialRelationGetT2DLocElements( scene, &materials[0],
-                TEX_PER_MAT, &tex );
-
-        }
-        // if no locals, try to get globals
-        else
-        {
-            SAA_modelRelationGetT2DGlbNbElements( scene, model,
-                FALSE, &relinfo, &numTexGlb );
-
-            if ( numTexGlb )
-            {
-                if ( verbose >= 1 )
-                    fprintf( outStream, "%s had %d global tex\n", modelName, numTexGlb );
-
-                // get the referenced texture
-                SAA_modelRelationGetT2DGlbElements( scene,
-                    model, TEX_PER_MAT, &tex );
-            }
-        }
-
-        // add tex ref's if we found any textures
-        if ( numTexLoc || numTexGlb)
-        {
-            char    *fullTexName = NULL;
-            char    *texName = NULL;
-            char    *uniqueTexName = NULL;
-            int      texNameLen;
-
-            // get its name
-            SAA_texture2DGetPicNameLength( scene, &tex, &texNameLen);
-            fullTexName = (char *)malloc(sizeof(char)*++texNameLen);
-            SAA_texture2DGetPicName( scene, &tex, texNameLen,
-                fullTexName );
-
-            // append unique identifier to texname for this particular object
-            uniqueTexName = (char *)malloc(sizeof(char)*
-                (strlen(modelName)+strlen(texName)+3) );
-            sprintf( uniqueTexName, "%s-%s", modelName, texName );
-            if ( verbose >= 2 )
-                fprintf( outStream, "referencing tref %s\n",
-                    uniqueTexName );
-
-            float uScale;
-            float vScale;
-            float uOffset;
-            float vOffset;
-            SAA_Boolean    uv_swap = FALSE;
-
-            // get texture offset info
-            SAA_texture2DGetUScale( scene, &tex, &uScale );
-            SAA_texture2DGetVScale( scene, &tex, &vScale );
-            SAA_texture2DGetUOffset( scene, &tex, &uOffset );
-            SAA_texture2DGetVOffset( scene, &tex, &vOffset );
-            SAA_texture2DGetUVSwap( scene, &tex, &uv_swap );
-
-
-            if ( verbose >= 2 )
-            {
-                fprintf( outStream, "tex uScale: %f\n", uScale );
-                fprintf( outStream, "tex vScale: %f\n", vScale );
-                fprintf( outStream, "tex uOffset: %f\n", uOffset );
-                fprintf( outStream, "tex vOffset: %f\n", vOffset );
-                if ( uv_swap )
-                    fprintf( outStream, "nurbTex u & v swapped!\n" );
-                else
-                    fprintf( outStream, "nurbTex u & v NOT swapped\n" );
-            }
-
-
-            // find the vpool for this model
-            EggVertexPool *vPool =
-                (EggVertexPool *)(_data.pools.FindName( modelName ));
-
-            // if we found the pool
-            if ( vPool != NULL )
-            {
-                // generate duv's for model
-                float oldOffsets[4];
-                double u, v, du, dv;
-                int        size;
-                SAA_Boolean bigEndian;
-
-                SAA_elementGetUserDataSize( scene, model, "TEX_OFFSETS",                                 &size );
-
-                if ( size != 0 )
-                {
-                    // remember original texture offsets future reference
-                    SAA_elementGetUserData( scene, model, "TEX_OFFSETS",
-                        size, &bigEndian, (void *)&oldOffsets );
-
-                    // get the original scales and offsets
-                    u = oldOffsets[0];
-                    v = oldOffsets[1];
-
-                    du = u - uOffset;
-                    dv = v - vOffset;
-
-                    if ( verbose >= 1 )
-                    {
-                        fprintf( outStream, "original u = %f, v = %f\n",
-                            u, v );
-                        fprintf( outStream, "u = %f, v = %f\n",
-                            uOffset, vOffset );
-                        fprintf( outStream, "du = %f, dv = %f\n",
-                            du, dv );
-                    }
-
-                    strstream uName, vName;
-
-                    // create duv target names
-                    uName << modelName << ".u" << ends;
-                    vName << modelName << ".v" << ends;
-
-                    // find the appropriate table to store the duv animation
-                    // info into
-                    SAnimTable *thisTable;
-
-                    // find the duv U table associated with this model
-                    thisTable = (SAnimTable *)(morphRoot->FindDescendent(
-                        uName.str() ));
-
-                    if ( thisTable != NULL )
-                    {
-                        thisTable->AddElement( du );
-                        if ( verbose >= 1 )
-                            fprintf( outStream, "adding element %f to %s\n",
-                                du, uName.str() );
-                    }
-                    else
-                        fprintf( outStream, "Couldn't find uTable %s\n",
-                            uName.str() );
-
-                    // find the duv V table associated with this model
-                    thisTable = (SAnimTable *)(morphRoot->FindDescendent(
-                        vName.str() ));
-
-                    if ( thisTable != NULL )
-                    {
-                        thisTable->AddElement( dv );
-                        if ( verbose >= 1 )
-                            fprintf( outStream, "adding element %f to %s\n",
-                                dv, uName.str() );
-                    }
-                    else
-                        fprintf( outStream, "Couldn't find vTable %s\n",
-                            uName.str() );
-                }
-            }
-            else
-                if ( verbose >= 2 )
-                    fprintf( outStream, "Couldn't find vpool %s\n", modelName );
-        }
-
-        // free( materials );
-    }
-}
-#endif
-
-/**
- * Instantiate converter and process a file
- */
-EXPCL_MISC SI_Error soft2egg(int argc, char *argv[]) {
-  // pass control to the c++ system
-  init_soft2egg(argc, argv);
-  return SI_SUCCESS;
-}
-#ifdef __cplusplus
-}
-#endif

+ 0 - 44
pandatool/src/softegg/softEggGroupUserData.I

@@ -1,44 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file softEggGroupUserData.I
- * @author masad
- * @date 2003-09-25
- */
-
-/**
- *
- */
-INLINE SoftEggGroupUserData::
-SoftEggGroupUserData() {
-  _vertex_color = false;
-  _double_sided = false;
-}
-
-
-/**
- *
- */
-INLINE SoftEggGroupUserData::
-SoftEggGroupUserData(const SoftEggGroupUserData &copy) :
-  EggUserData(copy),
-  _vertex_color(copy._vertex_color),
-  _double_sided(copy._double_sided)
-{
-}
-
-
-/**
- *
- */
-INLINE void SoftEggGroupUserData::
-operator = (const SoftEggGroupUserData &copy) {
-  EggUserData::operator = (copy);
-  _vertex_color = copy._vertex_color;
-  _double_sided = copy._double_sided;
-}

+ 0 - 16
pandatool/src/softegg/softEggGroupUserData.cxx

@@ -1,16 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file softEggGroupUserData.cxx
- * @author masad
- * @date 2003-09-25
- */
-
-#include "softEggGroupUserData.h"
-
-TypeHandle SoftEggGroupUserData::_type_handle;

+ 0 - 53
pandatool/src/softegg/softEggGroupUserData.h

@@ -1,53 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file softEggGroupUserData.h
- * @author masad
- * @date 2003-09-25
- */
-
-#ifndef SOFTEGGGROUPUSERDATA_H
-#define SOFTEGGGROUPUSERDATA_H
-
-#include "pandatoolbase.h"
-#include "eggUserData.h"
-
-/**
- * This class contains extra user data which is piggybacked onto EggGroup
- * objects for the purpose of the softimage converter.
- */
-class SoftEggGroupUserData : public EggUserData {
-public:
-  INLINE SoftEggGroupUserData();
-  INLINE SoftEggGroupUserData(const SoftEggGroupUserData &copy);
-  INLINE void operator = (const SoftEggGroupUserData &copy);
-
-  bool _vertex_color;
-  bool _double_sided;
-
-public:
-  static TypeHandle get_class_type() {
-    return _type_handle;
-  }
-  static void init_type() {
-    EggUserData::init_type();
-    register_type(_type_handle, "SoftEggGroupUserData",
-                  EggUserData::get_class_type());
-  }
-  virtual TypeHandle get_type() const {
-    return get_class_type();
-  }
-  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
-
-private:
-  static TypeHandle _type_handle;
-};
-
-#include "softEggGroupUserData.I"
-
-#endif

+ 0 - 1310
pandatool/src/softegg/softNodeDesc.cxx

@@ -1,1310 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file softNodeDesc.cxx
- * @author masad
- * @date 2003-10-03
- */
-
-#include "softNodeDesc.h"
-#include "config_softegg.h"
-#include "eggGroup.h"
-#include "eggXfmSAnim.h"
-#include "eggSAnimData.h"
-#include "softToEggConverter.h"
-#include "dcast.h"
-
-using std::endl;
-
-TypeHandle SoftNodeDesc::_type_handle;
-
-/**
- *
- */
-SoftNodeDesc::
-SoftNodeDesc(SoftNodeDesc *parent, const std::string &name) :
-  Namable(name),
-  _parent(parent)
-{
-  _model = nullptr;
-  _egg_group = nullptr;
-  _egg_table = nullptr;
-  _anim = nullptr;
-  _joint_type = JT_none;
-
-  // Add ourselves to our parent.
-  if (_parent != nullptr) {
-    softegg_cat.spam() << "parent name " << _parent->get_name();
-    _parent->_children.push_back(this);
-  }
-
-  // set the _parentJoint to Null
-  _parentJoint = nullptr;
-
-  fullname = nullptr;
-
-  numTexLoc = 0;
-  numTexGlb = 0;
-
-  uScale = nullptr;
-  vScale = nullptr;
-  uOffset = nullptr;
-  vOffset = nullptr;
-
-  valid;
-  uv_swap;
-  // SAA_Boolean visible;
-  numTexTri = nullptr;
-  textures = nullptr;
-  materials = nullptr;
-  triangles = nullptr;
-  gtype = SAA_GEOM_ORIGINAL;
-}
-
-/**
- *
- */
-SoftNodeDesc::
-~SoftNodeDesc() {
-  // I think it is a mistake to try to delete this.  This was one member of an
-  // entire array allocated at once; you can't delete individual elements of
-  // an array.
-
-  // Screw cleanup, anyway--we'll just let the array leak.
-  /*
-  if (_model != (SAA_Elem *)NULL) {
-    delete _model;
-  }
-  */
-}
-
-/**
- * Indicates an associated between the SoftNodeDesc and some SAA_Elem
- * instance.
- */
-void SoftNodeDesc::
-set_model(SAA_Elem *model) {
-  _model = model;
-}
-
-/**
- * Sometimes, parent is not known at node creation As soon as it is known, set
- * the parent
- */
-void SoftNodeDesc::
-set_parent(SoftNodeDesc *parent) {
-  if (_parent) {
-    softegg_cat.spam() << endl;
-    /*
-    softegg_cat.spam() << " expected _parent to be null!?\n";
-    if (_parent == parent)
-      softegg_cat.spam() << " parent already set\n";
-    else {
-      softegg_cat.spam() << " current parent " << _parent->get_name() << " new parent "
-           << parent << endl;
-    }
-    */
-    return;
-  }
-  _parent = parent;
-  softegg_cat.spam() << " set parent to " << _parent->get_name() << endl;
-
-  // Add ourselves to our parent.
-  _parent->_children.push_back(this);
-}
-
-/**
- * Sometimes, parent is not known at node creation As soon as it is known, set
- * the parent
- */
-void SoftNodeDesc::
-force_set_parent(SoftNodeDesc *parent) {
-  if (_parent)
-    softegg_cat.spam() << " current parent " << _parent->get_name();
-
-  _parent = parent;
-
-  if (_parent)
-    softegg_cat.spam() << " new parent " << _parent->get_name() << endl;
-
-  // Add ourselves to our parent.
-  _parent->_children.push_back(this);
-}
-
-/**
- * Returns true if a Soft dag path has been associated with this node, false
- * otherwise.
- */
-bool SoftNodeDesc::
-has_model() const {
-  return (_model != nullptr);
-}
-
-/**
- * Returns the SAA_Elem * associated with this node.  It is an error to call
- * this unless has_model() returned true.
- */
-SAA_Elem *SoftNodeDesc::
-get_model() const {
-  nassertr(_model != nullptr, _model);
-  return _model;
-}
-
-/**
- * Returns true if the node should be treated as a joint by the converter.
- */
-bool SoftNodeDesc::
-is_joint() const {
-  // return _joint_type == JT_joint || _joint_type == JT_pseudo_joint;
-  return _joint_type == JT_joint;
-}
-
-/**
- * Returns true if the node should be treated as a junk by the converter.
- */
-bool SoftNodeDesc::
-is_junk() const {
-  return _joint_type == JT_junk;
-}
-
-/**
- * sets the _joint_type to JT_joint
- */
-void SoftNodeDesc::
-set_joint() {
-  _joint_type = JT_joint;
-}
-/**
- * Returns true if the node is the parent or ancestor of a joint.
- */
-bool SoftNodeDesc::
-is_joint_parent() const {
-  return _joint_type == JT_joint_parent;
-}
-
-/**
- * Recursively clears the egg pointers from this node and all children.
- */
-void SoftNodeDesc::
-clear_egg() {
-  _egg_group = nullptr;
-  _egg_table = nullptr;
-  _anim = nullptr;
-
-  Children::const_iterator ci;
-  for (ci = _children.begin(); ci != _children.end(); ++ci) {
-    SoftNodeDesc *child = (*ci);
-    child->clear_egg();
-  }
-}
-
-/**
- * Indicates that this node has at least one child that is a joint or a
- * pseudo-joint.
- */
-void SoftNodeDesc::
-mark_joint_parent() {
-  if (_joint_type == JT_none) {
-    _joint_type = JT_joint_parent;
-    softegg_cat.spam() << " marked parent " << get_name();
-  }
-  else
-    softegg_cat.spam() << " ?parent " << get_name() << " joint type " << _joint_type;
-
-  if (_parent != nullptr) {
-    _parent->mark_joint_parent();
-  }
-  softegg_cat.spam() << endl;
-}
-
-/**
- * Walks the hierarchy, if a node is joint, make sure all its parents are
- * marked JT_joint_parent
- */
-void SoftNodeDesc::
-check_joint_parent() {
-  Children::const_iterator ci;
-  for (ci = _children.begin(); ci != _children.end(); ++ci) {
-    SoftNodeDesc *child = (*ci);
-    if (child->is_joint()) {
-      softegg_cat.spam() << "child " << child->get_name();
-      mark_joint_parent();
-    }
-    child->check_joint_parent();
-  }
-}
-
-/**
- * check to see if this is a branch we don't want to descend - this will
- * prevent creating geometry for animation control structures
- */
-void SoftNodeDesc::
-check_junk(bool parent_junk) {
-  const char *name = get_name().c_str();
-
-  if (parent_junk) {
-    _joint_type = JT_junk;
-    softegg_cat.spam() << "junk node " << get_name() << endl;
-  }
-  if ( (strstr(name, "con-") != nullptr) ||
-       (strstr(name, "con_") != nullptr) ||
-       (strstr(name, "fly_") != nullptr) ||
-       (strstr(name, "fly-") != nullptr) ||
-       (strstr(name, "camRIG") != nullptr) ||
-       (strstr(name, "cam_rig") != nullptr) ||
-       (strstr(name, "bars") != nullptr) )
-    {
-      _joint_type = JT_junk;
-      softegg_cat.spam() << "junk node " << get_name() << endl;
-      parent_junk = true;
-      Children::const_iterator ci;
-      for (ci = _children.begin(); ci != _children.end(); ++ci) {
-        SoftNodeDesc *child = (*ci);
-        softegg_cat.spam() << child->get_name() << ",";
-      }
-      softegg_cat.spam() << endl;
-    }
-  Children::const_iterator ci;
-  for (ci = _children.begin(); ci != _children.end(); ++ci) {
-    SoftNodeDesc *child = (*ci);
-    child->check_junk(parent_junk);
-  }
-}
-
-/**
- * check to see if this is a selected branch we want to descend - this will
- * prevent creating geometry for other parts
- */
-bool SoftNodeDesc::
-is_partial(char *search_prefix) {
-  const char *name = fullname;
-
-  // if no search prefix then return false
-  if (!search_prefix)
-    return false;
-  // if name is search_prefix, return false
-  if (strstr(name, search_prefix) != nullptr) {
-    softegg_cat.debug() << "matched " << name << " ";
-    return false;
-  }
-  // if name is not search_prefix, look in its parent
-  if (strstr(name, search_prefix) == nullptr) {
-    softegg_cat.debug() << "node " << name << " ";
-    if (_parent)
-      return _parent->is_partial(search_prefix);
-  }
-  // neither name nor its parent is search_prefix
-  return true;
-}
-
-/**
- * Go through the ancestors and figure out who is the immediate _parentJoint
- * of this node
- */
-void SoftNodeDesc::
-set_parentJoint(SAA_Scene *scene, SoftNodeDesc *lastJoint) {
-  if (is_junk())
-    return;
-  // set its parent joint to the lastJoint
-  _parentJoint = lastJoint;
-  softegg_cat.spam() << get_name() << ": parent joint set to :" << lastJoint;
-  if (lastJoint)
-    softegg_cat.spam() << "(" << lastJoint->get_name() << ")";
-  softegg_cat.spam() << endl;
-
-  // is this node a joint?
-  SAA_Boolean isSkeleton = false;
-  if (has_model())
-    SAA_modelIsSkeleton( scene, get_model(), &isSkeleton );
-
-  // if  already a joint or name has "joint" in it
-  const char *name = get_name().c_str();
-  if (is_joint() || isSkeleton || strstr(name, "joint") != nullptr) {
-    lastJoint = this;
-  }
-  if ( _parentJoint && strstr( _parentJoint->get_name().c_str(), "scale" ) != nullptr ) {
-    // make sure _parentJoint didn't have the name "joint" in it
-    if (strstr(_parentJoint->get_name().c_str(), "joint") == nullptr) {
-      _parentJoint = nullptr;
-      // _parentJoint = lastJoint = NULL;
-      softegg_cat.spam() << "scale joint flag set!\n";
-    }
-  }
-
-  // look in the children
-  Children::const_iterator ci;
-  for (ci = _children.begin(); ci != _children.end(); ++ci) {
-    SoftNodeDesc *child = (*ci);
-    child->set_parentJoint(scene, lastJoint);
-  }
-}
-
-/**
- * Walks the hierarchy, looking for non-joint nodes that are both children and
- * parents of a joint.  These nodes are deemed to be pseudo joints, since the
- * converter must treat them as joints.
- */
-void SoftNodeDesc::
-check_pseudo_joints(bool joint_above) {
-  if (_joint_type == JT_joint_parent && joint_above) {
-    // This is one such node: it is the parent of a joint (JT_joint_parent is
-    // set), and it is the child of a joint (joint_above is set).
-    _joint_type = JT_pseudo_joint;
-    softegg_cat.debug() << "pseudo " << get_name() << " case1\n";
-  }
-
-  if (_joint_type == JT_joint) {
-    // If this node is itself a joint, then joint_above is true for all child
-    // nodes.
-    joint_above = true;
-  }
-
-  // Don't bother traversing further if _joint_type is none or junk, since
-  // that means this node has no joint children.
-  if (_joint_type != JT_none && _joint_type != JT_junk) {
-
-    bool any_joints = false;
-    Children::const_iterator ci;
-    for (ci = _children.begin(); ci != _children.end(); ++ci) {
-      SoftNodeDesc *child = (*ci);
-      child->check_pseudo_joints(joint_above);
-      if (child->is_joint()) {
-        softegg_cat.spam() << get_name() << " any_joint true by " << child->get_name() << endl;
-        any_joints = true;
-      }
-    }
-
-    // If any children qualify as joints, then any sibling nodes that are
-    // parents of joints are also elevated to joints.
-    if (any_joints) {
-      bool all_joints = true;
-      for (ci = _children.begin(); ci != _children.end(); ++ci) {
-        SoftNodeDesc *child = (*ci);
-        if (child->_joint_type == JT_joint_parent) {
-          child->_joint_type = JT_pseudo_joint;
-          softegg_cat.debug() << "pseudo " << child->get_name() << " case2 by parent " << get_name() << "\n";
-        } else if (child->_joint_type == JT_none || child->_joint_type == JT_junk) {
-          all_joints = false;
-        }
-      }
-
-      if (all_joints || any_joints) {
-        // Finally, if all children or at least one is a joint, then we are
-        // too.
-        if (_joint_type == JT_joint_parent) {
-          _joint_type = JT_pseudo_joint;
-          softegg_cat.debug() << "pseudo " << get_name() << " case3\n";
-        }
-      }
-    }
-  }
-  else
-    softegg_cat.spam() << "found null joint " << get_name() << endl;
-}
-
-/**
- * Extracts the transform on the indicated Soft node, and applies it to the
- * corresponding Egg node.
- */
-void SoftNodeDesc::
-get_transform(SAA_Scene *scene, EggGroup *egg_group, bool global) {
-  // Get the model's matrix
-  int scale_joint = 0;
-
-  if (!global && _parentJoint && !stec.flatten && !scale_joint) {
-
-    SAA_modelGetMatrix( scene, get_model(), SAA_COORDSYS_LOCAL,  matrix );
-    softegg_cat.debug() << get_name() << " using local matrix :parent ";
-
-  } else {
-
-    SAA_modelGetMatrix( scene, get_model(), SAA_COORDSYS_GLOBAL,  matrix );
-    softegg_cat.debug() << get_name() << " using global matrix :parent ";
-
-  }
-
-  if (_parentJoint && !stec.flatten)
-    softegg_cat.debug() << _parentJoint->get_name() << endl;
-  else
-    softegg_cat.debug() << _parentJoint << endl;
-
-
-  softegg_cat.spam() << "model matrix = " << matrix[0][0] << " " << matrix[0][1] << " " << matrix[0][2] << " " << matrix[0][3] << "\n";
-  softegg_cat.spam() << "model matrix = " << matrix[1][0] << " " << matrix[1][1] << " " << matrix[1][2] << " " << matrix[1][3] << "\n";
-  softegg_cat.spam() << "model matrix = " << matrix[2][0] << " " << matrix[2][1] << " " << matrix[2][2] << " " << matrix[2][3] << "\n";
-  softegg_cat.spam() << "model matrix = " << matrix[3][0] << " " << matrix[3][1] << " " << matrix[3][2] << " " << matrix[3][3] << "\n";
-
-  if (!global && is_joint()) {
-    LMatrix4d m4d(matrix[0][0], matrix[0][1], matrix[0][2], matrix[0][3],
-                  matrix[1][0], matrix[1][1], matrix[1][2], matrix[1][3],
-                  matrix[2][0], matrix[2][1], matrix[2][2], matrix[2][3],
-                  matrix[3][0], matrix[3][1], matrix[3][2], matrix[3][3]);
-    if (!m4d.almost_equal(LMatrix4d::ident_mat(), 0.0001)) {
-      egg_group->set_transform3d(m4d);
-      softegg_cat.spam() << "set transform in egg_group\n";
-    }
-  }
-  return;
-}
-
-/**
- * Extracts the transform on the indicated Soft node, as appropriate for a
- * joint in an animated character, and applies it to the indicated node.  This
- * is different from get_transform() in that it does not respect the
- * _transform_type flag, and it does not consider the relative transforms
- * within the egg file.  more added functionality: now fills in components of
- * anim (EffXfmSAnim) class (masad).
- */
-void SoftNodeDesc::
-get_joint_transform(SAA_Scene *scene,  EggGroup *egg_group, EggXfmSAnim *anim, bool global) {
-  // SI_Error result;
-  SAA_Elem *skeletonPart = _model;
-  const char *name = get_name().c_str();
-
-  if ( skeletonPart != nullptr ) {
-    PN_stdfloat i,j,k;
-    PN_stdfloat h,p,r;
-    PN_stdfloat x,y,z;
-    int scale_joint = 0;
-
-    softegg_cat.spam() << "\n\nanimating child " << name << endl;
-
-    if (_parentJoint && !stec.flatten && !scale_joint ) {
-      softegg_cat.debug() << "using local matrix\n";
-
-      // get SAA orientation
-      SAA_modelGetRotation( scene, skeletonPart, SAA_COORDSYS_LOCAL,
-                            &p, &h, &r );
-
-      // get SAA translation
-      SAA_modelGetTranslation( scene, skeletonPart, SAA_COORDSYS_LOCAL,
-                               &x, &y, &z );
-
-      // get SAA scaling
-      SAA_modelGetScaling( scene, skeletonPart, SAA_COORDSYS_LOCAL,
-                           &i, &j, &k );
-    } else {
-      softegg_cat.debug() << " using global matrix\n";
-
-      // get SAA orientation
-      SAA_modelGetRotation( scene, skeletonPart, SAA_COORDSYS_GLOBAL,
-                            &p, &h, &r );
-
-      // get SAA translation
-      SAA_modelGetTranslation( scene, skeletonPart, SAA_COORDSYS_GLOBAL,
-                               &x, &y, &z );
-
-      // get SAA scaling
-      SAA_modelGetScaling( scene, skeletonPart, SAA_COORDSYS_GLOBAL,
-                           &i, &j, &k );
-    }
-
-    softegg_cat.spam() << "\nanim data: " << i << " " << j << " " << k << endl;
-    softegg_cat.spam() << "\t" << p << " " << h << " " << r << endl;
-    softegg_cat.spam() << "\t" << x << " " << y << " " << z << endl;
-
-    // Encode the component multiplication ordering in the egg file.
-    // SoftImage always uses this order, regardless of the setting of temp-
-    // hpr-fix.
-    anim->set_order("sphrt");
-
-    // Add each component by their names
-    anim->add_component_data("i", i);
-    anim->add_component_data("j", j);
-    anim->add_component_data("k", k);
-    anim->add_component_data("p", p);
-    anim->add_component_data("h", h);
-    anim->add_component_data("r", r);
-    anim->add_component_data("x", x);
-    anim->add_component_data("y", y);
-    anim->add_component_data("z", z);
-  }
-  else {
-    softegg_cat.debug() << "Cannot build anim table - no skeleton\n";
-  }
-}
-
-/**
- * Converts the indicated Soft polyset to a bunch of EggPolygons and parents
- * them to the indicated egg group.
- */
-void SoftNodeDesc::
-load_poly_model(SAA_Scene *scene, SAA_ModelType type) {
-  SI_Error result;
-  const char *name = get_name().c_str();
-
-  int i;
-  int id = 0;
-
-  // if making a pose - get deformed geometry
-  if ( stec.make_pose )
-    gtype = SAA_GEOM_DEFORMED;
-
-  // If the model is a PATCH in soft, set its step before tesselating
-  else if ( type == SAA_MPTCH )
-    SAA_patchSetStep( scene, _model, stec.nurbs_step, stec.nurbs_step );
-
-  // Get the number of triangles
-  result = SAA_modelGetNbTriangles( scene, _model, gtype, id, &numTri);
-  softegg_cat.spam() << "triangles: " << numTri << "\n";
-
-  if ( result != SI_SUCCESS ) {
-    softegg_cat.spam() << "Error: couldn't get number of triangles!\n";
-    softegg_cat.debug() << "\tbailing on model: " << name << "\n";
-    return;
-  }
-
-  // check to see if surface is also skeleton...
-  SAA_Boolean isSkeleton = FALSE;
-
-  SAA_modelIsSkeleton( scene, _model, &isSkeleton );
-
-  // check to see if this surface is used as a skeleton or is animated via
-  // constraint only ( these nodes are tagged by the animator with the keyword
-  // "joint" somewhere in the nodes name)
-  softegg_cat.spam() << "is Skeleton? " << isSkeleton << "\n";
-
-  /*************************************************************************************/
-
-  // model is not a null and has no triangles!
-  if ( !numTri ) {
-    softegg_cat.spam() << "no triangles!\n";
-  }
-  else {
-    // allocate array of triangles
-    triangles = (SAA_SubElem *) new SAA_SubElem[numTri];
-    if (!triangles) {
-      softegg_cat.info() << "Not enough Memory for triangles...\n";
-      exit(1);
-    }
-    // triangulate model and read the triangles into array
-    SAA_modelGetTriangles( scene, _model, gtype, id, numTri, triangles );
-    softegg_cat.spam() << "got triangles\n";
-
-    /***********************************************************************************/
-
-    // allocate array of materials (Asad: it gives a warning if try to get one
-    // triangle at a time...investigate later read each triangle's material
-    // into array
-    materials = (SAA_Elem*) new SAA_Elem[numTri];
-    SAA_triangleGetMaterials( scene, _model, numTri, triangles, materials );
-    if (!materials) {
-      softegg_cat.info() << "Not enough Memory for materials...\n";
-      exit(1);
-    }
-    softegg_cat.spam() << "got materials\n";
-
-    /***********************************************************************************/
-
-    // allocate array of textures per triangle
-    numTexTri = new int[numTri];
-    const void *relinfo;
-
-    // find out how many local textures per triangle
-    for (i = 0; i < numTri; i++) {
-      result = SAA_materialRelationGetT2DLocNbElements( scene, &materials[i], FALSE,
-                                                        &relinfo, &numTexTri[i] );
-      // polytex
-      if ( result == SI_SUCCESS )
-        numTexLoc += numTexTri[i];
-    }
-
-    // don't need this anymore... free( numTexTri );
-
-    // get local textures if present
-    if ( numTexLoc ) {
-      softegg_cat.spam() << "numTexLoc = " << numTexLoc << endl;
-
-      // allocate arrays of texture info
-      uScale = new PN_stdfloat[numTri];
-      vScale = new PN_stdfloat[numTri];
-      uOffset = new PN_stdfloat[numTri];
-      vOffset = new PN_stdfloat[numTri];
-      texNameArray = new char *[numTri];
-      uRepeat = new int[numTri];
-      vRepeat = new int[numTri];
-
-      // ASSUME only one texture per material
-      textures = new SAA_Elem[numTri];
-
-      for ( i = 0; i < numTri; i++ ) {
-        // and read all referenced local textures into array
-        SAA_materialRelationGetT2DLocElements( scene, &materials[i],
-                                               TEX_PER_MAT , &textures[i] );
-
-        // initialize the array value
-        texNameArray[i] = nullptr;
-        // initialize the repeats
-        uRepeat[i] = vRepeat[i] = 0;
-
-        // see if this triangle has texture info
-        if (numTexTri[i] == 0)
-          continue;
-
-        // check to see if texture is present
-        result = SAA_elementIsValid( scene, &textures[i], &valid );
-
-        if ( result != SI_SUCCESS )
-          softegg_cat.spam() << "SAA_elementIsValid failed!!!!\n";
-
-        // texture present - get the name and uv info
-        if ( valid ) {
-          // according to drose, we don't need to convert .pic files to .rgb,
-          // panda can now read the .pic files.
-          texNameArray[i] = stec.GetTextureName(scene, &textures[i]);
-
-          softegg_cat.spam() << " tritex[" << i << "] named: " << texNameArray[i] << endl;
-
-          SAA_texture2DGetUVSwap( scene, &textures[i], &uv_swap );
-
-          if ( uv_swap == TRUE )
-            softegg_cat.spam() << " swapping u and v...\n" ;
-
-          SAA_texture2DGetUScale( scene, &textures[i], &uScale[i] );
-          SAA_texture2DGetVScale( scene, &textures[i], &vScale[i] );
-          SAA_texture2DGetUOffset( scene, &textures[i], &uOffset[i] );
-          SAA_texture2DGetVOffset( scene, &textures[i], &vOffset[i] );
-
-          softegg_cat.spam() << "tritex[" << i << "] uScale: " << uScale[i] << " vScale: " << vScale[i] << endl;
-          softegg_cat.spam() << " uOffset: " << uOffset[i] << " vOffset: " << vOffset[i] << endl;
-
-          SAA_texture2DGetRepeats( scene, &textures[i], &uRepeat[i], &vRepeat[i] );
-          softegg_cat.spam() << "uRepeat = " << uRepeat[i] << ", vRepeat = " << vRepeat[i] << endl;
-        }
-        else {
-          softegg_cat.spam() << "Invalid texture...\n";
-          softegg_cat.spam() << " tritex[" << i << "] named: (null)\n";
-        }
-      }
-    }
-    else { // if no local textures, try to get global textures
-      SAA_modelRelationGetT2DGlbNbElements( scene, _model,
-                                            FALSE, &relinfo, &numTexGlb );
-      if ( numTexGlb ) {
-        // ASSUME only one texture per model
-        textures = new SAA_Elem;
-        // get the referenced texture
-        SAA_modelRelationGetT2DGlbElements( scene, _model,
-                                            TEX_PER_MAT, textures );
-        softegg_cat.spam() << "numTexGlb = " << numTexGlb << endl;
-        // check to see if texture is present
-        SAA_elementIsValid( scene, textures, &valid );
-        if ( valid ) {  // texture present - get the name and uv info
-          SAA_texture2DGetUVSwap( scene, textures, &uv_swap );
-
-          if ( uv_swap == TRUE )
-            softegg_cat.spam() << " swapping u and v...\n";
-
-          // according to drose, we don't need to convert .pic files to .rgb,
-          // panda can now read the .pic files.
-          texNameArray = new char *[1];
-          *texNameArray = stec.GetTextureName(scene, textures);
-
-          uRepeat = new int;
-          vRepeat = new int;
-
-          softegg_cat.spam() << " global tex named: " << *texNameArray << endl;
-
-          // allocate arrays of texture info
-          uScale = new PN_stdfloat;
-          vScale = new PN_stdfloat;
-          uOffset = new PN_stdfloat;
-          vOffset = new PN_stdfloat;
-
-          SAA_texture2DGetUScale( scene, textures, uScale );
-          SAA_texture2DGetVScale( scene, textures, vScale );
-          SAA_texture2DGetUOffset( scene, textures, uOffset );
-          SAA_texture2DGetVOffset( scene, textures, vOffset );
-
-          softegg_cat.spam() << " global tex uScale: " << *uScale << " vScale: " << *vScale << endl;
-          softegg_cat.spam() << "            uOffset: " << *uOffset << " vOffset: " << *vOffset << endl;
-
-          SAA_texture2DGetRepeats(  scene, textures, uRepeat, vRepeat );
-          softegg_cat.spam() << "uRepeat = " << *uRepeat << ", vRepeat = " << *vRepeat << endl;
-        }
-        else {
-          softegg_cat.spam() << "Invalid Texture...\n";
-        }
-      }
-    }
-  }
-  softegg_cat.spam() << "got textures" << endl;
-}
-
-/**
- * Converts the indicated Soft polyset to a bunch of EggPolygons and parents
- * them to the indicated egg group.
- */
-void SoftNodeDesc::
-load_nurbs_model(SAA_Scene *scene, SAA_ModelType type) {
-  SI_Error result;
-  const char *name = get_name().c_str();
-
-  // if making a pose - get deformed geometry
-  if ( stec.make_pose )
-    gtype = SAA_GEOM_DEFORMED;
-
-  // If the model is a NURBS in soft, set its step before tesselating
-  if ( type == SAA_MNSRF )
-    SAA_nurbsSurfaceSetStep( scene, _model, stec.nurbs_step, stec.nurbs_step );
-
-  // get the materials
-  /***********************************************************************************/
-  const void *relinfo;
-
-  SAA_modelRelationGetMatNbElements( scene, get_model(), FALSE, &relinfo,
-                                     &numNurbMats );
-
-  softegg_cat.spam() << "nurbs surf has " << numNurbMats << " materials\n";
-
-  if ( numNurbMats ) {
-    materials = new SAA_Elem[numNurbMats];
-    if (!materials) {
-      softegg_cat.info() << "Out Of Memory on allocating materials\n";
-      exit(1);
-    }
-
-    SAA_modelRelationGetMatElements( scene, get_model(), relinfo,
-                                     numNurbMats, materials );
-
-    softegg_cat.spam() << "got materials\n";
-
-    // get the textures
-    /***********************************************************************************/
-    numNurbTexLoc = 0;
-    numNurbTexGlb = 0;
-
-    // find out how many local textures per NURBS surface ASSUME it only has
-    // one material
-    SAA_materialRelationGetT2DLocNbElements( scene, &materials[0], FALSE, &relinfo, &numNurbTexLoc );
-
-    // if present, get local textures
-    if ( numNurbTexLoc ) {
-      softegg_cat.spam() << name << " had " << numNurbTexLoc << " local tex\n";
-      nassertv(numNurbTexLoc == 1);
-
-      textures = new SAA_Elem[numNurbTexLoc];
-
-      // get the referenced texture
-      SAA_materialRelationGetT2DLocElements( scene, &materials[0], TEX_PER_MAT, &textures[0] );
-
-    }
-    // if no locals, try to get globals
-    else {
-      SAA_modelRelationGetT2DGlbNbElements( scene, get_model(), FALSE, &relinfo, &numNurbTexGlb );
-
-      if ( numNurbTexGlb ) {
-        softegg_cat.spam() << name << " had " << numNurbTexGlb << " global tex\n";
-        nassertv(numNurbTexGlb == 1);
-
-        textures = new SAA_Elem[numNurbTexGlb];
-
-        // get the referenced texture
-        SAA_modelRelationGetT2DGlbElements( scene, get_model(), TEX_PER_MAT, &textures[0] );
-      }
-    }
-
-    if ( numNurbTexLoc || numNurbTexGlb) {
-
-      // allocate the texture name array
-      texNameArray = new char *[1];
-      // allocate arrays of texture info
-      uScale = new PN_stdfloat;
-      vScale = new PN_stdfloat;
-      uOffset = new PN_stdfloat;
-      vOffset = new PN_stdfloat;
-      uRepeat = new int;
-      vRepeat = new int;
-
-      // check to see if texture is present
-      result = SAA_elementIsValid( scene, &textures[0], &valid );
-
-      if ( result != SI_SUCCESS )
-        softegg_cat.spam() << "SAA_elementIsValid failed!!!!\n";
-
-      // texture present - get the name and uv info
-      if ( valid ) {
-        // according to drose, we don't need to convert .pic files to .rgb,
-        // panda can now read the .pic files.
-        texNameArray[0] = stec.GetTextureName(scene, &textures[0]);
-
-        softegg_cat.spam() << " tritex[0] named: " << texNameArray[0] << endl;
-
-        SAA_texture2DGetUVSwap( scene, &textures[0], &uv_swap );
-
-        if ( uv_swap == TRUE )
-          softegg_cat.spam() << " swapping u and v...\n" ;
-
-        SAA_texture2DGetUScale( scene, &textures[0], uScale );
-        SAA_texture2DGetVScale( scene, &textures[0], vScale );
-        SAA_texture2DGetUOffset( scene, &textures[0], uOffset );
-        SAA_texture2DGetVOffset( scene, &textures[0], vOffset );
-
-        softegg_cat.spam() << "tritex[0] uScale: " << *uScale << " vScale: " << *vScale << endl;
-        softegg_cat.spam() << " uOffset: " << *uOffset << " vOffset: " << *vOffset << endl;
-
-        SAA_texture2DGetRepeats( scene, &textures[0], uRepeat, vRepeat );
-        softegg_cat.spam() << "uRepeat = " << *uRepeat << ", vRepeat = " << *vRepeat << endl;
-      }
-      else {
-        softegg_cat.spam() << "Invalid texture...\n";
-        softegg_cat.spam() << " tritex[0] named: (null)\n";
-      }
-    }
-
-    softegg_cat.spam() << "got textures\n";
-  }
-}
-
-/**
- * given a vertex, find its corresponding shape vertex and return its index.
- */
-int SoftNodeDesc::
-find_shape_vert(LPoint3d p3d, SAA_DVector *vertices, int numVert) {
-  int i, found = 0;
-
-  for (i = 0; i < numVert && !found ; i++) {
-    if ((p3d[0] == vertices[i].x) &&
-        (p3d[1] == vertices[i].y) &&
-        (p3d[2] == vertices[i].z)) {
-      found = 1;
-      softegg_cat.spam() << "found shape vert at index " << i << endl;
-    }
-  }
-
-  if (!found )
-    i = -1;
-  else
-    i--;
-
-  return i;
-}
-
-/**
- * Given a scene, a model , the vertices of its original shape and its name
- * find the difference between the geometry of its key shapes and the models
- * original geometry and add morph vertices to the egg data to reflect these
- * changes.
- */
-void SoftNodeDesc::
-make_vertex_offsets(int numShapes) {
-  int i, j;
-  int offset;
-  int numCV;
-  char tableName[_MAX_PATH];
-  SAA_DVector *shapeVerts = nullptr;
-  SAA_DVector *uniqueVerts = nullptr;
-  SAA_Elem *model = get_model();
-  SAA_Scene *scene = &stec.scene;
-
-  EggVertexPool *vpool = nullptr;
-  std::string vpool_name = get_name() + ".verts";
-  EggNode *t = stec._tree.get_egg_root()->find_child(vpool_name);
-  if (t)
-    DCAST_INTO_V(vpool, t);
-
-  int numOrigVert = (int) vpool->size();
-  EggVertexPool::iterator vi;
-
-  if ((type == SAA_MNSRF) && stec.make_nurbs)
-    SAA_nurbsSurfaceSetStep( scene, model, stec.nurbs_step, stec.nurbs_step );
-
-  SAA_modelGetNbVertices( scene, model, &numCV );
-
-  // get the shape verts
-  uniqueVerts = new SAA_DVector[numCV];
-  SAA_modelGetVertices( scene, model, SAA_GEOM_ORIGINAL, 0,
-                        numCV, uniqueVerts );
-
-  softegg_cat.spam() << numCV << " CV's\n";
-
-  for ( i = 0; i < numCV; i++ )
-    // convert vertices to global
-    _VCT_X_MAT( uniqueVerts[i], uniqueVerts[i], matrix);
-    softegg_cat.spam() << "uniqueVerts[" << i << "] = " << uniqueVerts[i].x << " " << uniqueVerts[i].y
-         << " " << uniqueVerts[i].z << " " << uniqueVerts[i].w << endl;
-
-  // iterate through for each key shape (except original)
-  for ( i = 1; i < numShapes; i++ ) {
-
-    sprintf(tableName, "%s.%d", get_name().c_str(), i);
-
-    softegg_cat.spam() << "\nMaking geometry offsets for " << tableName << "...\n";
-
-    if ((type == SAA_MNSRF) && stec.make_nurbs)
-      softegg_cat.spam() << "calculating NURBS morphs...\n";
-    else
-      softegg_cat.spam() << "calculating triangle morphs...\n";
-
-    // get the shape verts
-    shapeVerts = new SAA_DVector[numCV];
-    SAA_modelGetVertices( scene, model, SAA_GEOM_SHAPE, i+1, numCV, shapeVerts );
-
-    for ( j=0; j < numCV; j++ ) {
-      // convert vertices to global
-      _VCT_X_MAT( shapeVerts[j], shapeVerts[j], matrix);
-
-      softegg_cat.spam() << "shapeVerts[" << j << "] = " << shapeVerts[j].x << " "
-           << shapeVerts[j].y << " " << shapeVerts[j].z << endl;
-    }
-    softegg_cat.spam() << endl;
-
-    // for every original vertex, compare to the corresponding key shape
-    // vertex and see if a vertex offset is needed
-    j = 0;
-    for (vi = vpool->begin(); vi != vpool->end(); ++vi, ++j) {
-
-      double dx, dy, dz;
-      EggVertex *vert = (*vi);
-      LPoint3d p3d = vert->get_pos3();
-
-      softegg_cat.spam() << "oVert[" << j << "] = " <<  p3d[0] << " " <<  p3d[1] << " " <<  p3d[2] << endl;
-      if ((type == SAA_MNSRF) && stec.make_nurbs) {
-        dx = shapeVerts[j].x - p3d[0];
-        dy = shapeVerts[j].y - p3d[1];
-        dz = shapeVerts[j].z - p3d[2];
-
-        softegg_cat.spam() << "global shapeVerts[" << j << "] = " << shapeVerts[j].x << " "
-             << shapeVerts[j].y << " " << shapeVerts[j].z << " " << shapeVerts[j].w << endl;
-      }
-      else {
-        // we need to map from original vertices to triangle shape vertices
-        // here
-        offset = find_shape_vert(p3d, uniqueVerts, numCV);
-
-        dx = shapeVerts[offset].x - p3d[0];
-        dy = shapeVerts[offset].y - p3d[1];
-        dz = shapeVerts[offset].z - p3d[2];
-
-        softegg_cat.spam() << "global shapeVerts[" << offset << "] = " << shapeVerts[offset].x << " "
-             << shapeVerts[offset].y << " " << shapeVerts[offset].z << endl;
-      }
-
-      softegg_cat.spam() << j << ": dx = " << dx << ", dy = " << dy << ", dz = " << dz << endl;
-
-      // if change isn't negligible, make a morph vertex entry
-      double total = fabs(dx)+fabs(dy)+fabs(dz);
-      if ( total > 0.00001 ) {
-        if ( vpool != nullptr ) {
-          // create offset
-          LVector3d p(dx, dy, dz);
-          EggMorphVertex *dxyz = new EggMorphVertex(tableName, p);
-          // add the offset to the vertex
-          vert->_dxyzs.insert(*dxyz);
-        }
-        else
-          softegg_cat.spam() << "Error: couldn't find vertex pool " << vpool_name << endl;
-
-      } // if total
-    } //for j
-  } //for i
-}
-
-/**
- * Given a scene, a model, a name and a frame time, determine what type of
- * shape interpolation is used and call the appropriate function to extract
- * the shape weight info for this frame...
- */
-void SoftNodeDesc::
-make_morph_table(  PN_stdfloat time ) {
-  int numShapes;
-  SAA_Elem *model = nullptr;
-  SAA_AnimInterpType type;
-  SAA_Scene *scene = &stec.scene;
-
-  if (has_model())
-    model = get_model();
-  else
-    return;
-
-  // Get the number of key shapes
-  SAA_modelGetNbShapes( scene, model, &numShapes );
-
-  if ( numShapes <= 0 ) {
-    return;
-  }
-
-  stec.has_morph = true;
-
-  softegg_cat.spam() << "make_morph_table: " << get_name() << " : num shapes: " << numShapes << endl;
-
-  SAA_modelGetShapeInterpolation( scene, model, &type );
-
-  if ( type == SAA_ANIM_LINEAR || type == SAA_ANIM_CARDINAL ) {
-    softegg_cat.spam() << "linear morph" << endl;
-    make_linear_morph_table( numShapes, time );
-  }
-  else {    // must be weighted...
-    // check first for expressions
-    softegg_cat.spam() << "expression morph" << endl;
-    make_expression_morph_table( numShapes, time );
-  }
-}
-
-/**
- * Given a scene, a model, its name, and the time, get the shape fcurve for
- * the model and determine the shape weights for the given time and use them
- * to populate the morph table.
- */
-void SoftNodeDesc::
-make_linear_morph_table(int numShapes, PN_stdfloat time) {
-  int i;
-  PN_stdfloat curveVal;
-  char tableName[_MAX_PATH];
-  SAA_Elem fcurve;
-  // SAnimTable *thisTable;
-  EggSAnimData *anim;
-  SAA_Elem *model = get_model();
-  SAA_Scene *scene = &stec.scene;
-
-  softegg_cat.spam() << "linear interp, getting fcurve\n";
-
-  SAA_modelFcurveGetShape( scene, model, &fcurve );
-
-  SAA_fcurveEval( scene, &fcurve, time, &curveVal );
-
-  softegg_cat.spam() << "at time " << time << ", fcurve for " << get_name() << " = " << curveVal << endl;
-
-  PN_stdfloat nextVal = 0.0f;
-
-  // populate morph table values for this frame
-  for ( i = 1; i < numShapes; i++ ) {
-    // derive table name from the model name
-    sprintf(tableName, "%s.%d", get_name().c_str(), i);
-
-    softegg_cat.spam() << "Linear: looking for table '" << tableName << "'\n";
-
-    // find the morph table associated with this key shape
-    anim = stec.find_morph_table(tableName);
-
-    if ( anim != nullptr ) {
-      if ( i == (int)curveVal ) {
-        if ( curveVal - i == 0 ) {
-          anim->add_data(1.0f );
-          softegg_cat.spam() << "adding element 1.0f\n";
-        }
-        else {
-          anim->add_data(1.0f - (curveVal - i));
-          nextVal = curveVal - i;
-          softegg_cat.spam() << "adding element " << 1.0f - (curveVal - i) << endl;
-        }
-      }
-      else {
-        if ( nextVal ) {
-          anim->add_data(nextVal );
-          nextVal = 0.0f;
-          softegg_cat.spam() << "adding element " << nextVal << endl;
-        }
-        else {
-          anim->add_data(0.0f);
-          softegg_cat.spam() << "adding element 0.0f\n";
-        }
-      }
-
-      softegg_cat.spam() <<" to '" << tableName << "'\n";
-    }
-    else
-      softegg_cat.spam() << i << " : Couldn't find table '" << tableName << "'\n";
-  }
-}
-
-/**
- * Given a scene, a model, a list of all models in the scene, the number of
- * models in the scece, the number of key shapes for this model, the name of
- * the model and the current time, determine what method of controlling the
- * shape weights is used and call the appropriate routine.
- */
-void SoftNodeDesc::
-make_weighted_morph_table(int numShapes, PN_stdfloat time) {
-  PN_stdfloat curveVal;
-  SI_Error result;
-  char tableName[_MAX_PATH];
-  SAA_Elem *weightCurves;
-  // SAnimTable *thisTable;
-  EggSAnimData *anim;
-  SAA_Elem *model = get_model();
-  SAA_Scene *scene = &stec.scene;
-
-  // allocate array of weight curves (one for each shape)
-  weightCurves = new SAA_Elem[numShapes];
-
-  result = SAA_modelFcurveGetShapeWeights(scene, model, numShapes, weightCurves);
-
-  if ( result == SI_SUCCESS ) {
-    for ( int i = 1; i < numShapes; i++ ) {
-      SAA_fcurveEval( scene, &weightCurves[i], time, &curveVal );
-
-      // make sure soft gave us a reasonable number if (!isNum(curveVal))
-      // curveVal = 0.0f;
-
-      softegg_cat.spam() << "at time " << time << ", weightCurve[" << i << "] for " << get_name() << " = " << curveVal << endl;
-
-      // derive table name from the model name
-      sprintf(tableName, "%s.%d", get_name().c_str(), i);
-
-      // find and populate shape table
-      softegg_cat.spam() << "Weight: looking for table '" << tableName << "'\n";
-
-      // find the morph table associated with this key shape
-      anim = stec.find_morph_table(tableName);
-
-      if ( anim != nullptr ) {
-        anim->add_data(curveVal);
-        softegg_cat.spam() << "adding element " << curveVal << endl;
-      }
-      else
-        softegg_cat.spam() << i << " : Couldn't find table '" << tableName << "'\n";
-    }
-  }
-}
-
-/**
- * Given a scene, a model and its number of key shapes generate a morph table
- * describing transitions btwn the key shapes by evaluating the positions of
- * the controlling sliders.
- */
-void SoftNodeDesc::
-make_expression_morph_table(int numShapes, PN_stdfloat time)
-{
-  // int j;
-  int numExp;
-  char *track;
-  // PN_stdfloat expVal; PN_stdfloat sliderVal; char *tableName; char
-  // *sliderName; SAnimTable *thisTable;
-  SAA_Elem *expressions;
-  SI_Error result;
-
-  SAA_Elem *model = get_model();
-  SAA_Scene *scene = &stec.scene;
-
-  // populate morph table values for this frame
-
-  // compose track name
-  track = nullptr;
-
-  // find how many expressions for this shape
-  SAA_elementGetNbExpressions( scene, model, track, FALSE, &numExp );
-
-  softegg_cat.spam() << get_name() << " has " << numExp << " RHS expressions\n";
-
-  if ( numExp ) {
-    // get the expressions for this shape
-    expressions = new SAA_Elem[numExp];
-    softegg_cat.spam() << "getting " << numExp << " RHS expressions...\n";
-
-    result = SAA_elementGetExpressions( scene, model, track, FALSE,
-                                        numExp, expressions );
-    /*
-    if ( !result ) {
-      for ( j = 1; j < numExp; j++ ) {
-        if ( verbose >= 2 )
-                {
-                // debug see what we got
-                int numvars;
-
-                SAA_expressionGetNbVars( scene, &expressions[j], &numvars );
-
-                int *varnamelen;
-                int *varstrlen;
-                int  expstrlen;
-
-                varnamelen = (int *)malloc(sizeof(int)*numvars);
-                varstrlen = (int *)malloc(sizeof(int)*numvars);
-
-                SAA_expressionGetStringLengths( scene, &expressions[j],
-                    numvars, varnamelen, varstrlen, &expstrlen );
-
-                int *varnamesizes;
-                int *varstrsizes;
-
-                varnamesizes = (int *)malloc(sizeof(int)*numvars);
-                varstrsizes = (int *)malloc(sizeof(int)*numvars);
-
-                for ( int k = 0; k < numvars; k++ )
-                {
-                    varnamesizes[k] = varnamelen[k] + 1;
-                    varstrsizes[k] = varstrlen[k] + 1;
-                }
-
-                int expstrsize = expstrlen + 1;
-
-                char **varnames;
-                char **varstrs;
-
-                varnames = (char **)malloc(sizeof(char *)*numvars);
-                varstrs = (char **)malloc(sizeof(char *)*numvars);
-
-                for ( k = 0; k < numvars; k++ )
-                {
-                    varnames[k] = (char *)malloc(sizeof(char)*
-                        varnamesizes[k]);
-
-                    varstrs[k] = (char *)malloc(sizeof(char)*
-                        varstrsizes[k]);
-                }
-
-                char *expstr = (char *)malloc(sizeof(char)* expstrsize );
-
-                SAA_expressionGetStrings( scene, &expressions[j], numvars,
-                    varnamesizes, varstrsizes, expstrsize, varnames,
-                    varstrs, expstr );
-
-                if ( verbose >= 2 )
-                {
-                    fprintf( outStream, "expression = '%s'\n", expstr );
-                    fprintf( outStream, "has %d variables\n", numvars );
-                }
-                } //if verbose
-
-                if ( verbose >= 2 )
-                    fprintf( outStream, "evaling expression...\n" );
-
-                SAA_expressionEval( scene, &expressions[j], time, &expVal );
-
-                if ( verbose >= 2 )
-                    fprintf( outStream, "time %f: exp val %f\n",
-                        time, expVal );
-
-                // derive table name from the model name
-                tableName = MakeTableName( name, j );
-
-                if ( verbose >= 2 )
-                    fprintf( outStream, "Exp: looking for table '%s'\n",
-                        tableName );
-
-                // find the morph table associated with this key shape
-                anim = (SAnimTable *)
-                    (morphRoot->FindDescendent( tableName ));
-
-                if ( anim != NULL )
-                {
-                    anim->AddElement( expVal );
-                    if ( verbose >= 1 )
-                        fprintf( outStream, "%d: adding element %f to %s\n",
-                            j, expVal, tableName );
-                    fflush( outStream );
-                }
-                else
-                {
-                    fprintf( outStream, "%d: Couldn't find table '%s'", j,
-                            tableName );
-
-                    fprintf( outStream, " for value %f\n", expVal );
-                }
-            }
-        }
-        else
-            fprintf( outStream, "couldn't get expressions!!!\n" );
-    */
-  }
-  else {
-    softegg_cat.spam() << "weighted morph" << endl;
-    // no expression, use weight curves
-    make_weighted_morph_table(numShapes, time );
-  }
-}

+ 0 - 159
pandatool/src/softegg/softNodeDesc.h

@@ -1,159 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file softNodeDesc.h
- * @author masad
- * @date 2003-10-03
- */
-
-#ifndef SOFTNODEDESC_H
-#define SOFTNODEDESC_H
-
-#ifdef _MIN
-#undef _MIN
-#endif
-#ifdef _MAX
-#undef _MAX
-#endif
-
-#include "pandatoolbase.h"
-
-#include "eggVertex.h"
-#include "eggVertexPool.h"
-#include "referenceCount.h"
-#include "pointerTo.h"
-#include "namable.h"
-
-#include <SAA.h>
-
-class EggGroup;
-class EggTable;
-class EggXfmSAnim;
-
-/**
- * Describes a single instance of a node aka element in the Soft scene graph,
- * relating it to the corresponding egg structures (e.g.  node, group, or
- * table entry) that will be created.
- */
-class SoftNodeDesc : public ReferenceCount, public Namable {
-public:
-  SoftNodeDesc(SoftNodeDesc *parent=nullptr, const std::string &name = std::string());
-  ~SoftNodeDesc();
-
-  void set_parent(SoftNodeDesc *parent);
-  void force_set_parent(SoftNodeDesc *parent);
-  void set_model(SAA_Elem *model);
-  bool has_model() const;
-  SAA_Elem *get_model() const;
-
-  bool is_joint() const;
-  bool is_junk() const;
-  void set_joint();
-  bool is_joint_parent() const;
-  bool is_partial(char *search_prefix);
-
-  SoftNodeDesc *_parent;
-  SoftNodeDesc *_parentJoint; // keep track of who is your parent joint
-  typedef pvector< PT(SoftNodeDesc) > Children;
-  Children _children;
-
-private:
-  void clear_egg();
-  void mark_joint_parent();
-  void check_joint_parent();
-  void check_junk(bool parent_junk);
-  void check_pseudo_joints(bool joint_above);
-
-  void set_parentJoint(SAA_Scene *scene, SoftNodeDesc *lastJoint);
-
-  SAA_ModelType type;
-
-  SAA_Elem *_model;
-
-  EggGroup *_egg_group;
-  EggTable *_egg_table;
-  EggXfmSAnim *_anim;
-
-  enum JointType {
-    JT_none,         // Not a joint.
-    JT_joint,        // An actual joint in Soft.
-    JT_pseudo_joint, // Not a joint in Soft, but treated just like a
-                     // joint for the purposes of the converter.
-    JT_joint_parent, // A parent or ancestor of a joint or pseudo joint.
-    JT_junk,         // originated from con-/fly-/car_rig/bars etc.
-  };
-  JointType _joint_type;
-
-public:
-
-  char **texNameArray;
-  int *uRepeat, *vRepeat;
-  PN_stdfloat matrix[4][4];
-
-  const char *fullname;
-
-  int numTri;
-  // int numShapes;
-  int numTexLoc;
-  int numTexGlb;
-  int *numTexTri;
-
-  // if the node is a MNSRF
-  int numNurbTexLoc;
-  int numNurbTexGlb;
-  int numNurbMats;
-
-  PN_stdfloat *uScale;
-  PN_stdfloat *vScale;
-  PN_stdfloat *uOffset;
-  PN_stdfloat *vOffset;
-
-  SAA_Boolean valid;
-  SAA_Boolean uv_swap;
-  // SAA_Boolean visible;
-  SAA_Elem *textures;
-  SAA_Elem *materials;
-  SAA_SubElem *triangles;
-  SAA_GeomType gtype;
-
-  EggGroup *get_egg_group()const {return _egg_group;}
-
-  void get_transform(SAA_Scene *scene, EggGroup *egg_group, bool global);
-  void get_joint_transform(SAA_Scene *scene, EggGroup *egg_group, EggXfmSAnim *anim, bool global);
-  void load_poly_model(SAA_Scene *scene, SAA_ModelType type);
-  void load_nurbs_model(SAA_Scene *scene, SAA_ModelType type);
-
-  void make_morph_table(PN_stdfloat time);
-  void make_linear_morph_table(int numShapes, PN_stdfloat time);
-  void make_weighted_morph_table(int numShapes, PN_stdfloat time);
-  void make_expression_morph_table(int numShapes, PN_stdfloat time);
-
-  void make_vertex_offsets(int numShapes);
-  int find_shape_vert(LPoint3d p3d, SAA_DVector *vertices, int numVert);
-
-  static TypeHandle get_class_type() {
-    return _type_handle;
-  }
-  static void init_type() {
-    ReferenceCount::init_type();
-    Namable::init_type();
-    register_type(_type_handle, "SoftNodeDesc",
-                  ReferenceCount::get_class_type(),
-                  Namable::get_class_type());
-  }
-
-private:
-  static TypeHandle _type_handle;
-
-  friend class SoftNodeTree;
-};
-
-class SoftToEggConverter;
-extern SoftToEggConverter stec;
-
-#endif

+ 0 - 561
pandatool/src/softegg/softNodeTree.cxx

@@ -1,561 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file softNodeTree.cxx
- * @author masad
- * @date 2003-09-26
- */
-
-// Includes
-
-#include "softNodeTree.h"
-#include "softEggGroupUserData.h"
-#include "config_softegg.h"
-#include "eggGroup.h"
-#include "eggTable.h"
-#include "eggXfmSAnim.h"
-#include "eggData.h"
-#include "softToEggConverter.h"
-#include "dcast.h"
-
-#include <SAA.h>
-
-using std::endl;
-
-/**
- *
- */
-SoftNodeTree::
-SoftNodeTree() {
-  _root = new SoftNodeDesc(nullptr, "----root");
-  _root->fullname = "----root";
-  _fps = 0.0;
-  _use_prefix = 0;
-  _search_prefix = nullptr;
-  _egg_data = nullptr;
-  _egg_root = nullptr;
-  _skeleton_node = nullptr;
-}
-/**
- * Given an element, return a copy of the element's name WITHOUT prefix.
- */
-char *SoftNodeTree::
-GetName( SAA_Scene *scene, SAA_Elem *element ) {
-  int nameLen;
-  char *name;
-
-  // get the name
-  SAA_elementGetNameLength( scene, element, &nameLen );
-  name = new char[++nameLen];
-  SAA_elementGetName( scene, element, nameLen, name );
-
-  return name;
-}
-
-/**
- * Given an element, return a copy of the element's name complete with prefix.
- */
-char *SoftNodeTree::
-GetFullName( SAA_Scene *scene, SAA_Elem *element )
-{
-  int nameLen, prefixLen;
-  char *name, *prefix;
-
-  // get the name length
-  SAA_elementGetNameLength( scene, element, &nameLen );
-  // get the prefix length
-  SAA_elementGetPrefixLength( scene, element, &prefixLen );
-  // allocate the array to hold name
-  name = new char[++nameLen];
-  // allocate the array to hold prefix and length + hyphen
-  prefix = new char[++prefixLen + nameLen + 4];
-  // get the name
-  SAA_elementGetName( scene, element, nameLen, name );
-  // get the prefix
-  SAA_elementGetPrefix( scene, element, prefixLen, prefix );
-  // add 'em together
-  strcat(prefix, "-");
-  strcat(prefix, name);
-
-  // return string
-  return prefix;
-}
-
-/**
- * Given an element, return a string containing the contents of its MODEL NOTE
- * entry
- */
-char *SoftNodeTree::
-GetModelNoteInfo( SAA_Scene *scene, SAA_Elem *model ) {
-  int size;
-  char *modelNote = nullptr;
-  SAA_Boolean bigEndian;
-
-  SAA_elementGetUserDataSize( scene, model, "MNOT", &size );
-
-  if ( size != 0 ) {
-    // allocate modelNote string
-    modelNote = new char[size + 1];
-
-    // get ModelNote data from this model
-    SAA_elementGetUserData( scene, model, "MNOT", size,
-                            &bigEndian, (void *)modelNote );
-
-    // strip off newline, if present
-    char *eol = (char *)memchr( modelNote, '\n', size );
-    if ( eol != nullptr)
-      *eol = '\0';
-    else
-      modelNote[size] = '\0';
-
-    softegg_cat.spam() << "\nmodelNote = " << modelNote << endl;
-  }
-
-  return modelNote;
-}
-
-/**
- * Given a string, return a copy of the string up to the first occurence of
- * '-'.
- */
-char *SoftNodeTree::
-GetRootName( const char *name ) {
-  const char *hyphen;
-  char *root;
-  int len;
-
-  hyphen = strchr( name, '-' );
-  len = hyphen-name;
-
-  if ( (hyphen != nullptr) && len ) {
-    root = new char[len+1];
-    strncpy( root, name, len );
-    root[len] = '\0';
-  }
-  else {
-    root = new char[strlen(name)+1];
-    strcpy( root, name );
-  }
-  return( root );
-}
-
-/**
- * Walks through the complete Soft hierarchy and builds up the corresponding
- * tree.
- */
-bool SoftNodeTree::
-build_complete_hierarchy(SAA_Scene &scene, SAA_Database &database) {
-  SI_Error status;
-  SoftNodeDesc *node;
-
-  // Get the entire Soft scene.
-  int numModels;
-  SAA_Elem *models;
-
-  SAA_sceneGetNbModels( &scene, &numModels );
-  softegg_cat.spam() << "Scene has " << numModels << " model(s)...\n";
-
-  // This while loop walks through the entire Soft hierarchy, one node at a
-  // time.
-  bool all_ok = true;
-  if ( numModels ) {
-    // allocate array of models
-    models = (SAA_Elem *) new SAA_Elem[numModels];
-    if ( models != nullptr ) {
-      if ((status = SAA_sceneGetModels( &scene, numModels, models )) != SI_SUCCESS) {
-        return false;
-      }
-      for ( int i = 0; i < numModels; i++ ) {
-        int level;
-        status = SAA_elementGetHierarchyLevel( &scene, &models[i], &level );
-        softegg_cat.spam() << "model[" << i << "]" << endl;
-        softegg_cat.spam() << " level " << level << endl;
-        softegg_cat.spam() << " status is " << status << "\n";
-
-        node = build_node(&scene, &models[i]);
-        if (!level && node)
-          node->set_parent(_root);
-      }
-    }
-  }
-
-  softegg_cat.spam() << "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj\n";
-
-  // check the nodes that are junk for animationartist control purposes
-  _root->check_junk(false);
-
-  softegg_cat.spam() << "jpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjp\n";
-
-  // check the nodes that are parent of ancestors of a joint
-  _root->check_joint_parent();
-
-  softegg_cat.spam() << "pppppppppppppppppppppppppppppppppppppppppppppppppppppppp\n";
-
-  // check the nodes that are pseudo joints
-  _root->check_pseudo_joints(false);
-
-  softegg_cat.spam() << "========================================================\n";
-
-  // find _parentJoint for each node
-  _root->set_parentJoint(&scene, nullptr);
-
-  return all_ok;
-}
-#if 0
-/**
- * Walks through the selected subset of the Soft hierarchy (or the complete
- * hierarchy, if nothing is selected) and builds up the corresponding tree.
- */
-bool SoftNodeTree::
-build_selected_hierarchy(char *scene_name) {
-  MStatus status;
-
-  MItDag dag_iterator(MItDag::kDepthFirst, MFn::kTransform, &status);
-  if (!status) {
-    status.perror("MItDag constructor");
-    return false;
-  }
-
-  // Get only the selected geometry.
-  MSelectionList selection;
-  status = MGlobal::getActiveSelectionList(selection);
-  if (!status) {
-    status.perror("MGlobal::getActiveSelectionList");
-    return false;
-  }
-
-  // Get the selected geometry only if the selection is nonempty; otherwise,
-  // get the whole scene anyway.
-  if (selection.isEmpty()) {
-    softegg_cat.info()
-      << "Selection list is empty.\n";
-    return build_complete_hierarchy();
-  }
-
-  bool all_ok = true;
-  unsigned int length = selection.length();
-  for (unsigned int i = 0; i < length; i++) {
-    MDagPath root_path;
-    status = selection.getDagPath(i, root_path);
-    if (!status) {
-      status.perror("MSelectionList::getDagPath");
-    } else {
-      // Now traverse through the selected dag path and all nested dag paths.
-      dag_iterator.reset(root_path);
-      while (!dag_iterator.isDone()) {
-        MDagPath dag_path;
-        status = dag_iterator.getPath(dag_path);
-        if (!status) {
-          status.perror("MItDag::getPath");
-        } else {
-          build_node(dag_path);
-        }
-
-        dag_iterator.next();
-      }
-    }
-  }
-
-  if (all_ok) {
-    _root->check_pseudo_joints(false);
-  }
-
-  return all_ok;
-}
-#endif
-/**
- * Returns the total number of nodes in the hierarchy, not counting the root
- * node.
- */
-int SoftNodeTree::
-get_num_nodes() const {
-  return _nodes.size();
-}
-
-/**
- * Returns the nth node in the hierarchy, in an arbitrary ordering.
- */
-SoftNodeDesc *SoftNodeTree::
-get_node(int n) const {
-  nassertr(n >= 0 && n < (int)_nodes.size(), nullptr);
-  return _nodes[n];
-}
-
-/**
- * Returns the node named 'name' in the hierarchy, in an arbitrary ordering.
- */
-SoftNodeDesc *SoftNodeTree::
-get_node(std::string name) const {
-  NodesByName::const_iterator ni = _nodes_by_name.find(name);
-  if (ni != _nodes_by_name.end())
-    return (*ni).second;
-  return nullptr;
-}
-
-/**
- * Removes all of the references to generated egg structures from the tree,
- * and prepares the tree for generating new egg structures.
- */
-void SoftNodeTree::
-clear_egg(EggData *egg_data, EggGroupNode *egg_root,
-          EggGroupNode *skeleton_node) {
-  _root->clear_egg();
-  _egg_data = egg_data;
-  _egg_root = egg_root;
-  _skeleton_node = skeleton_node;
-}
-
-/**
- * Returns the EggGroupNode corresponding to the group or joint for the
- * indicated node.  Creates the group node if it has not already been created.
- */
-EggGroup *SoftNodeTree::
-get_egg_group(SoftNodeDesc *node_desc) {
-  nassertr(_egg_root != nullptr, nullptr);
-
-  // lets print some relationship
-  softegg_cat.spam() << " group " << node_desc->get_name() << "(" << node_desc->_egg_group << ")";
-  if (node_desc->_parent)
-    softegg_cat.spam() << " parent " << node_desc->_parent->get_name() << "(" << node_desc->_parent << ")";
-  else
-    softegg_cat.spam() << " parent " << node_desc->_parent;
-  softegg_cat.spam() << endl;
-
-  if (node_desc->_egg_group == nullptr) {
-    // We need to make a new group node.
-    EggGroup *egg_group;
-
-    egg_group = new EggGroup(node_desc->get_name());
-    if (node_desc->is_joint()) {
-      egg_group->set_group_type(EggGroup::GT_joint);
-    }
-
-    if (stec.flatten || (!node_desc->_parentJoint || node_desc->_parentJoint == _root)) {
-      // The parent is the root.
-      softegg_cat.spam() << "came hereeeee\n";
-      _egg_root->add_child(egg_group);
-    } else {
-      // The parent is another node.
-      EggGroup *parent_egg_group = get_egg_group(node_desc->_parentJoint);
-      parent_egg_group->add_child(egg_group);
-    }
-
-    node_desc->_egg_group = egg_group;
-  }
-
-  return node_desc->_egg_group;
-}
-
-/**
- * Returns the EggTable corresponding to the joint for the indicated node.
- * Creates the table node if it has not already been created.
- */
-EggTable *SoftNodeTree::
-get_egg_table(SoftNodeDesc *node_desc) {
-  nassertr(_skeleton_node != nullptr, nullptr);
-  nassertr(node_desc->is_joint(), nullptr);
-
-  // lets print some relationship
-  softegg_cat.spam() << " group " << node_desc->get_name() << "(" << node_desc->_egg_group << ")";
-  if (node_desc->_parent)
-    softegg_cat.spam() << " parent " << node_desc->_parent->get_name() << "(" << node_desc->_parent << ")";
-  else
-    softegg_cat.spam() << " parent " << node_desc->_parent;
-  softegg_cat.spam() << endl;
-
-  if (node_desc->_egg_table == nullptr) {
-    softegg_cat.spam() << "creating a new table\n";
-    // We need to make a new table node.  nassertr(node_desc->_parent !=
-    // (SoftNodeDesc *)NULL, NULL);
-
-    EggTable *egg_table = new EggTable(node_desc->get_name());
-    node_desc->_anim = new EggXfmSAnim("xform", _egg_data->get_coordinate_system());
-    node_desc->_anim->set_fps(_fps);
-    egg_table->add_child(node_desc->_anim);
-
-    if (stec.flatten || (!node_desc->_parentJoint || node_desc->_parentJoint == _root)) {
-      // if (!node_desc->_parent->is_joint()) { The parent is not a joint; put
-      // it at the top.
-      _skeleton_node->add_child(egg_table);
-    } else {
-      // The parent is another joint.
-      EggTable *parent_egg_table = get_egg_table(node_desc->_parentJoint);
-      parent_egg_table->add_child(egg_table);
-    }
-
-    node_desc->_egg_table = egg_table;
-  }
-
-  return node_desc->_egg_table;
-}
-
-/**
- * Returns the anim table corresponding to the joint for the indicated node.
- * Creates the table node if it has not already been created.
- */
-EggXfmSAnim *SoftNodeTree::
-get_egg_anim(SoftNodeDesc *node_desc) {
-  get_egg_table(node_desc);
-  return node_desc->_anim;
-}
-
-/**
- * Sets joint information for MNILL node
- */
-void SoftNodeTree::
-handle_null(SAA_Scene *scene, SoftNodeDesc *node_desc, const char *node_name) {
-  const char *name = node_name;
-  SAA_AlgorithmType    algo;
-  SAA_Elem *model = node_desc->get_model();
-
-  SAA_modelGetAlgorithm( scene, model, &algo );
-  softegg_cat.spam() << " null algorithm: " << algo << endl;
-
-  if ( algo == SAA_ALG_INV_KIN ) {
-    // MakeJoint( &scene, lastJoint, lastAnim,  model, name );
-    node_desc->set_joint();
-    softegg_cat.spam() << " encountered IK root: " << name << endl;
-  }
-  else if ( algo == SAA_ALG_INV_KIN_LEAF ) {
-    // MakeJoint( &scene, lastJoint, lastAnim, model, name );
-    node_desc->set_joint();
-    softegg_cat.spam() << " encountered IK leaf: " << name << endl;
-  }
-  else if ( algo == SAA_ALG_STANDARD ) {
-    SAA_Boolean isSkeleton = FALSE;
-    softegg_cat.spam() << " encountered Standard null: " << name << endl;
-
-    SAA_modelIsSkeleton( scene, model, &isSkeleton );
-
-    // check to see if this NULL is used as a skeleton or is animated via
-    // constraint only ( these nodes are tagged by the animator with the
-    // keyword "joint" somewhere in the nodes name)
-    if ( isSkeleton || (strstr( name, "joint" ) != nullptr) ) {
-      // MakeJoint( &scene, lastJoint, lastAnim, model, name );
-      node_desc->set_joint();
-      softegg_cat.spam() << " animating Standard null!!!\n";
-      softegg_cat.spam() << "isSkeleton: " << isSkeleton << endl;
-    }
-  }
-  else
-    softegg_cat.spam() << " encountered some other NULL: " << algo << endl;
-}
-
-/**
- * Returns a pointer to the node corresponding to the indicated dag_path
- * object, creating it first if necessary.
- */
-SoftNodeDesc *SoftNodeTree::
-build_node(SAA_Scene *scene, SAA_Elem *model) {
-  char *name, *fullname;
-  std::string node_name;
-  int numChildren;
-  int thisChild;
-  SAA_Elem *children;
-  SAA_ModelType type;
-  SAA_Boolean isSkeleton = FALSE;
-
-  fullname = GetFullName(scene, model);
-  if (_use_prefix)
-    name = fullname;
-  else
-    name = GetName(scene, model);
-
-  node_name = name;
-
-  SoftNodeDesc *node_desc = r_build_node(nullptr, node_name);
-
-  node_desc->fullname = fullname;
-  node_desc->set_model(model);
-  SAA_modelIsSkeleton( scene, model, &isSkeleton );
-
-  // find out what type of node we're dealing with
-  SAA_modelGetType( scene, node_desc->get_model(), &type );
-
-  if (type == SAA_MJNT || isSkeleton || (strstr(node_desc->get_name().c_str(), "joint") != nullptr))
-    node_desc->set_joint();
-
-  // treat the MNILL differently, because it needs to detect and set some
-  // joints
-  if (type == SAA_MNILL)
-    handle_null(scene, node_desc, name);
-
-  if (node_desc->is_joint())
-    softegg_cat.spam() << "type: " << type << " isSkeleton: " << isSkeleton << endl;
-
-  // get to the children
-  SAA_modelGetNbChildren( scene, model, &numChildren );
-  softegg_cat.spam() << " Model " << node_name << " children: " << numChildren << endl;
-
-  if ( numChildren ) {
-    children = new SAA_Elem[numChildren];
-    SAA_modelGetChildren( scene, model, numChildren, children );
-    if (!children)
-      softegg_cat.info() << "Not enough Memory for children...\n";
-
-    for ( thisChild = 0; thisChild < numChildren; thisChild++ ) {
-      fullname = GetFullName(scene, &children[thisChild]);
-      if (_use_prefix)
-        node_name = fullname;
-      else
-        node_name = GetName(scene, &children[thisChild]);
-
-      softegg_cat.spam() << " building child " << thisChild << "...";
-
-      SoftNodeDesc *node_child = r_build_node(node_desc, node_name);
-
-      node_child->fullname = fullname;
-      node_child->set_model(&children[thisChild]);
-      SAA_modelIsSkeleton( scene, &children[thisChild], &isSkeleton );
-
-      // find out what type of node we're dealing with
-      SAA_modelGetType( scene, node_child->get_model(), &type );
-
-      if (type == SAA_MJNT || isSkeleton || (strstr(node_child->get_name().c_str(), "joint") != nullptr))
-        node_child->set_joint();
-
-      // treat the MNILL differently, because it needs to detect and set some
-      // joints
-      if (type == SAA_MNILL)
-        handle_null(scene, node_child, node_name.c_str());
-
-      if (node_child->is_joint())
-        softegg_cat.spam() << "type: " << type << " isSkeleton: " << isSkeleton << endl;
-    }
-  }
-  return node_desc;
-}
-
-/**
- * The recursive implementation of build_node().
- */
-SoftNodeDesc *SoftNodeTree::
-r_build_node(SoftNodeDesc *parent_node, const std::string &name) {
-  SoftNodeDesc *node_desc;
-
-  // If we have already encountered this pathname, return the corresponding
-  // SoftNodeDesc immediately.
-  NodesByName::const_iterator ni = _nodes_by_name.find(name);
-  if (ni != _nodes_by_name.end()) {
-    softegg_cat.spam() << "  already built node " << (*ni).first;
-    node_desc = (*ni).second;
-    node_desc->set_parent(parent_node);
-    return node_desc;
-  }
-
-  // Otherwise, we have to create it.  Do this recursively, so we create each
-  // node along the path.
-  node_desc = new SoftNodeDesc(parent_node, name);
-
-  softegg_cat.spam() << " node name : " << name << endl;
-  _nodes.push_back(node_desc);
-
-  _nodes_by_name.insert(NodesByName::value_type(name, node_desc));
-
-  return node_desc;
-}

+ 0 - 78
pandatool/src/softegg/softNodeTree.h

@@ -1,78 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file softNodeTree.h
- * @author masad
- * @date 2003-10-03
- */
-
-#ifndef SOFTNODETREE_H
-#define SOFTNODETREE_H
-
-#include "pandatoolbase.h"
-#include "softNodeDesc.h"
-
-#include <SAA.h>
-
-class EggGroup;
-class EggTable;
-class EggXfmSAnim;
-class EggData;
-class EggGroupNode;
-
-
-/**
- * Describes a complete tree of soft nodes for conversion.
- */
-class SoftNodeTree {
-public:
-  SoftNodeTree();
-  SoftNodeDesc *build_node(SAA_Scene *scene, SAA_Elem *model);
-  bool build_complete_hierarchy(SAA_Scene &scene, SAA_Database &database);
-  void handle_null(SAA_Scene *scene, SoftNodeDesc *node_desc, const char *node_name);
-  // bool build_selected_hierarchy(SAA_Scene *s, SAA_Database *d, char
-  // *scene_name);
-
-  int get_num_nodes() const;
-  SoftNodeDesc *get_node(int n) const;
-  SoftNodeDesc *get_node(std::string name) const;
-
-  char *GetRootName(const char *);
-  char *GetModelNoteInfo(SAA_Scene *, SAA_Elem *);
-  char *GetName(SAA_Scene *scene, SAA_Elem *element);
-  char *GetFullName(SAA_Scene *scene, SAA_Elem *element);
-
-  EggGroupNode *get_egg_root() {return _egg_root;}
-  EggGroup *get_egg_group(SoftNodeDesc *node_desc);
-  EggTable *get_egg_table(SoftNodeDesc *node_desc);
-  EggXfmSAnim *get_egg_anim(SoftNodeDesc *node_desc);
-
-  void clear_egg(EggData *egg_data, EggGroupNode *egg_root, EggGroupNode *skeleton_node);
-
-  PT(SoftNodeDesc) _root;
-  PN_stdfloat _fps;
-  int _use_prefix;
-  char *_search_prefix;
-
-
-private:
-
-  EggData *_egg_data;
-  EggGroupNode *_egg_root;
-  EggGroupNode *_skeleton_node;
-
-  SoftNodeDesc *r_build_node(SoftNodeDesc *parent_node, const std::string &path);
-
-  typedef pmap<std::string, SoftNodeDesc *> NodesByName;
-  NodesByName _nodes_by_name;
-
-  typedef pvector<SoftNodeDesc *> Nodes;
-  Nodes _nodes;
-};
-
-#endif

+ 0 - 2122
pandatool/src/softegg/softToEggConverter.cxx

@@ -1,2122 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file softToEggConverter.cxx
- * @author masad
- * @date 2003-09-25
- */
-
-#include "softToEggConverter.h"
-#include "config_softegg.h"
-#include "softEggGroupUserData.h"
-
-#include "eggData.h"
-#include "eggGroup.h"
-#include "eggTable.h"
-#include "eggVertex.h"
-#include "eggComment.h"
-#include "eggVertexPool.h"
-#include "eggNurbsSurface.h"
-#include "eggNurbsCurve.h"
-#include "eggPolygon.h"
-#include "eggPrimitive.h"
-#include "eggTexture.h"
-#include "eggTextureCollection.h"
-#include "eggXfmSAnim.h"
-#include "eggSAnimData.h"
-#include "string_utils.h"
-#include "dcast.h"
-
-using std::endl;
-using std::string;
-
-SoftToEggConverter stec;
-
-const int    TEX_PER_MAT = 1;
-
-/**
- *
- */
-SoftToEggConverter::
-SoftToEggConverter(const string &program_name) :
-  _program_name(program_name)
-{
-  _from_selection = false;
-  _polygon_output = false;
-  _polygon_tolerance = 0.01;
-  /*
-  _respect_maya_double_sided = maya_default_double_sided;
-  _always_show_vertex_color = maya_default_vertex_color;
-  */
-  _transform_type = TT_model;
-
-  database_name = nullptr;
-  scene_name = nullptr;
-  model_name = nullptr;
-  animFileName = nullptr;
-  eggFileName = nullptr;
-  tex_path = nullptr;
-  eggGroupName = nullptr;
-  tex_filename = nullptr;
-  search_prefix = nullptr;
-  result = SI_SUCCESS;
-
-  // skeleton = new EggGroup();
-  foundRoot = FALSE;
-  // animRoot = NULL; morphRoot = NULL;
-  geom_as_joint = 0;
-  make_anim = 0;
-  make_nurbs = 0;
-  make_poly = 0;
-  make_soft = 0;
-  make_morph = 1;
-  make_duv = 1;
-  make_dart = TRUE;
-  has_morph = 0;
-  make_pose = 0;
-  // animData.is_z_up = FALSE;
-  nurbs_step = 1;
-  anim_start = -1000;
-  anim_end = -1000;
-  anim_rate = 24;
-  pose_frame = -1;
-  verbose = 0;
-  flatten = 0;
-  shift_textures = 0;
-  ignore_tex_offsets = 0;
-  use_prefix = 0;
-}
-
-/**
- *
- */
-SoftToEggConverter::
-SoftToEggConverter(const SoftToEggConverter &copy) :
-  _from_selection(copy._from_selection),
-  /*
-  _maya(copy._maya),
-  */
-  _polygon_output(copy._polygon_output),
-  _polygon_tolerance(copy._polygon_tolerance),
-  /*
-  _respect_maya_double_sided(copy._respect_maya_double_sided),
-  _always_show_vertex_color(copy._always_show_vertex_color),
-  */
-  _transform_type(copy._transform_type)
-{
-}
-
-/**
- *
- */
-SoftToEggConverter::
-~SoftToEggConverter() {
-  /*
-  close_api();
-  */
-}
-/**
- * Displays the "what is this program" message, along with the usage message.
- * Should be overridden in base classes to describe the current program.
- */
-void SoftToEggConverter::
-Help()
-{
-    softegg_cat.info() <<
-      "soft2egg takes a SoftImage scene or model\n"
-      "and outputs its contents as an egg file\n";
-
-    Usage();
-}
-
-/**
- * Displays the usage message.
- */
-void SoftToEggConverter::
-Usage() {
-  softegg_cat.info()
-    << "\nUsage:\n"
-    // << _commandName << " [opts] (must specify -m or -s)\n\n"
-    << "soft" << " [opts] (must specify -m or -s)\n\n"
-    << "Options:\n";
-
-  ShowOpts();
-  softegg_cat.info() << "\n";
-}
-
-/**
- * Displays the valid options.  Should be extended in base classes to show
- * additional options relevant to the current program.
- */
-void SoftToEggConverter::
-ShowOpts()
-{
-  softegg_cat.info() <<
-    "  -r <path>  - Used to provide soft with the resource\n"
-    "               Defaults to '/ful/ufs/soft371_mips2/3D/rsrc'.\n"
-    "  -d <path>  - Database path.\n"
-    "  -s <scene> - Indicates that a scene will be converted.\n"
-    "  -m <model> - Indicates that a model will be converted.\n"
-    "  -t <path>  - Specify path to place converted textures.\n"
-    "  -T <name>  - Specify filename for texture map listing.\n"
-    "  -S <step>  - Specify step for nurbs surface triangulation.\n"
-    "  -M <name>  - Specify model output filename. Defaults to scene name.\n"
-    "  -A <name>  - Specify anim output filename. Defaults to scene name.\n"
-    "  -N <name>  - Specify egg group name.\n"
-    "  -k         - Enable soft assignment for geometry.\n"
-    "  -n         - Specify egg NURBS representation instead of poly's.\n"
-    "  -p         - Specify egg polygon output for geometry.\n"
-    "  -P <frame> - Specify frame number for static pose.\n"
-    "  -b <frame> - Specify starting frame for animation (default = first).\n"
-    "  -e <frame> - Specify ending frame for animation (default = last).\n"
-    "  -f <fps>   - Specify frame rate for animation playback.\n"
-    "  -a         - Compile animation tables if animation present.\n"
-    "  -F         - Ignore hierarchy and build a completely flat skeleton.\n"
-    "  -v <level> - Set debug level.\n"
-    "  -x         - Shift NURBS parameters to preserve Alias textures.\n"
-    "  -i         - Ignore Soft texture uv offsets.\n"
-    "  -u         - Use Soft prefix in model names.\n"
-    "  -c         - Cancel morph conversion.\n"
-    "  -C         - Cancel duv conversion.\n"
-    "  -D         - Don't make the output model a character.\n"
-    "  -o <prefix>- Convert only models with given prefix.\n";
-
-  // EggBase::ShowOpts();
-}
-
-/**
- * Calls getopt() to parse the command-line switches.  Calls HandleGetopts()
- * to interpret each switch.  Returns true if the parsing was successful;
- * false if there was an error.  Adjusts argc and argv to remove the switches
- * from the parameter list.
- */
-bool SoftToEggConverter::
-DoGetopts(int &argc, char **&argv) {
-  bool okflag = true;
-  int i = 0;
-  softegg_cat.info() << "argc " << argc << "\n";
-  if (argc <2) {
-    Usage();
-    okflag = false;
-  }
-  while( i < argc ) {
-    strcat(_commandLine, argv[i]);
-    strcat(_commandLine, " ");
-    ++i;
-  }
-  softegg_cat.info() << endl << _commandLine << endl;
-
-  i = 1;
-  while ((i < argc) && (argv[i][0] == '-') && okflag) {
-    softegg_cat.info() << "arg " << i << " is " << argv[i] << "\n";
-    okflag = HandleGetopts(i, argc, argv);
-  }
-  return okflag;
-}
-
-/**
- * increment idx based on what kind of option parsed Supported options are as
- * follows: r:d:s:m:t:P:b:e:f:T:S:M:A:N:v:o:FhknpaxiucCD
- */
-bool SoftToEggConverter::
-HandleGetopts(int &idx, int argc, char **argv)
-{
-  bool okflag = true;
-
-  char flag = argv[idx][1];    // skip the '-' from option
-
-  switch (flag)
-    {
-    case 'r':       // Set the resource path for soft.
-      if ( strcmp( argv[idx+1], "" ) ) {
-        // Get the path.
-        rsrc_path = argv[idx+1];
-        softegg_cat.info() << "using rsrc path " << rsrc_path << "\n";
-      }
-      ++idx;
-      break;
-
-    case 'd':       // Set the database path.
-      if ( strcmp( argv[idx+1], "" ) ) {
-        // Get the path.
-        database_name = argv[idx+1];
-        softegg_cat.info() << "using database " << database_name << "\n";
-      }
-      ++idx;
-      break;
-
-    case 's':     // Check if its a scene.
-      if ( strcmp( argv[idx+1], "" ) ) {
-        // Get scene name.
-        scene_name = argv[idx+1];
-        softegg_cat.info() << "loading scene " << scene_name << "\n";
-      }
-      ++idx;
-      break;
-
-    case 'm':     // Check if its a model.
-      if ( strcmp( argv[idx+1], "" ) ) {
-        // Get model name.
-        model_name = argv[idx+1];
-        softegg_cat.info() << "loading model " <<  model_name << endl;
-      }
-      ++idx;
-      break;
-
-    case 't':     // Get converted texture path.
-      if ( strcmp( argv[idx+1], "" ) ) {
-        // Get tex path name.
-        tex_path = argv[idx+1];
-        softegg_cat.info() << "texture path:  " << tex_path << endl;
-      }
-      ++idx;
-      break;
-
-    case 'T':      // Specify texture list filename.
-      if ( strcmp( argv[idx+1], "") ) {
-        // Get the name.
-        tex_filename = argv[idx+1];
-        softegg_cat.info() << "creating texture list file: " << tex_filename << endl;
-      }
-      ++idx;
-      break;
-
-    case 'S':     // Set NURBS step.
-      if ( strcmp( argv[idx+1], "" ) ) {
-        nurbs_step = atoi(argv[idx+1]);
-        softegg_cat.info() << "NURBS step:  " << nurbs_step << endl;
-      }
-      ++idx;
-      break;
-
-    case 'M':     // Set model output file name.
-      if ( strcmp( argv[idx+1], "" ) ) {
-        eggFileName = argv[idx+1];
-        softegg_cat.info() << "Model output filename:  " << eggFileName << endl;
-      }
-      ++idx;
-      break;
-
-    case 'A':     // Set anim output file name.
-      if ( strcmp( argv[idx+1], "" ) ) {
-        animFileName = argv[idx+1];
-        softegg_cat.info() << "Anim output filename:  " << animFileName << endl;
-      }
-      ++idx;
-      break;
-
-    case 'N':     // Set egg model name.
-      if ( strcmp( argv[idx+1], "" ) ) {
-        eggGroupName = argv[idx+1];
-        softegg_cat.info() << "Egg group name:  " << eggGroupName << endl;
-      }
-      ++idx;
-      break;
-
-    case 'o':     // Set search_prefix.
-      if ( strcmp( argv[idx+1], "" ) ) {
-        search_prefix = argv[idx+1];
-        softegg_cat.info() << "Only converting models with prefix:  " << search_prefix << endl;
-      }
-      ++idx;
-      break;
-
-    case 'h':    // print help message
-      Help();
-      exit(1);
-      break;
-
-    case 'c':    // Cancel morph animation conversion
-      make_morph = FALSE;
-      softegg_cat.info() << "canceling morph conversion\n";
-      break;
-
-    case 'C':    // Cancel uv animation conversion
-      make_duv = FALSE;
-      softegg_cat.info() << "canceling uv animation conversion\n";
-      break;
-
-    case 'D':    // Omit the Dart flag
-      make_dart = FALSE;
-      softegg_cat.info() << "making a non-character model\n";
-      break;
-
-    case 'k':    // Enable soft skinning
-      // make_soft = TRUE; fprintf( outStream, "enabling soft skinning\n" );
-      softegg_cat.info() << "-k flag no longer necessary\n";
-      break;
-
-    case 'n':    // Generate egg NURBS output
-      make_nurbs = TRUE;
-      softegg_cat.info() << "outputting egg NURBS info\n";
-      break;
-
-    case 'p':    // Generate egg polygon output
-      make_poly = TRUE;
-      softegg_cat.info() << "outputting egg polygon info\n";
-      break;
-
-    case 'P':    // Generate static pose from given frame
-      if ( strcmp( argv[idx+1], "" ) ) {
-        make_pose = TRUE;
-        pose_frame = atoi(argv[idx+1]);
-        softegg_cat.info() << "generating static pose from frame " << pose_frame << endl;
-      }
-      ++idx;
-      break;
-
-    case 'a':     // Compile animation tables.
-      make_anim = TRUE;
-      softegg_cat.info() << "attempting to compile anim tables\n";
-      break;
-
-    case 'F':     // Build a flat skeleton.
-      flatten = TRUE;
-      softegg_cat.info() << "building a flat skeleton!!!\n";
-      break;
-
-    case 'x':     // Shift NURBS parameters to preserve Alias textures.
-      shift_textures = TRUE;
-      softegg_cat.info() << "shifting NURBS parameters...\n";
-      break;
-
-    case 'i':     // Ignore Soft uv texture offsets
-      ignore_tex_offsets = TRUE;
-      softegg_cat.info() << "ignoring texture offsets...\n";
-      break;
-
-    case 'u':     // Use Soft prefix in model names
-      use_prefix = TRUE;
-      softegg_cat.info() << "using prefix in model names...\n";
-      break;
-
-
-    case 'v':     // print debug messages.
-      if ( strcmp( argv[idx+1], "" ) ) {
-        verbose = atoi(argv[idx+1]);
-        softegg_cat.info() << "using debug level " << verbose << endl;
-      }
-      ++idx;
-      break;
-
-    case 'b':     // Set animation start frame.
-      anim_start = atoi(argv[idx]+2);
-      softegg_cat.info() << "animation starting at frame:  " << anim_start << endl;
-      break;
-
-    case 'e':     /// Set animation end frame.
-      anim_end = atoi(argv[idx]+2);
-      softegg_cat.info() << "animation ending at frame:  " << anim_end << endl;
-      break;
-
-    case 'f':     /// Set animation frame rate.
-      if ( strcmp( argv[idx+1], "" ) ) {
-        anim_rate = atoi(argv[idx+1]);
-        softegg_cat.info() << "animation frame rate:  " << anim_rate << endl;
-      }
-      ++idx;
-      break;
-
-    default:
-      softegg_cat.info() << flag << " flag not supported\n";
-      okflag = false;
-    }
-  idx++;
-  return (okflag);
-}
-
-/**
- * Allocates and returns a new copy of the converter.
- */
-SomethingToEggConverter *SoftToEggConverter::
-make_copy() {
-  return new SoftToEggConverter(*this);
-}
-
-/**
- * Returns the English name of the file type this converter supports.
- */
-string SoftToEggConverter::
-get_name() const {
-  return "Soft";
-}
-
-/**
- * Returns the common extension of the file type this converter supports.
- */
-string SoftToEggConverter::
-get_extension() const {
-  return "mb";
-}
-
-/**
- * Returns the English name of the file type this converter supports.
- */
-SoftNodeDesc *SoftToEggConverter::
-find_node(string name) {
-  return _tree.get_node(name);
-}
-
-/**
- * Given a texture element, return texture name with given tex_path
- */
-char *SoftToEggConverter::
-GetTextureName( SAA_Scene *scene, SAA_Elem *texture ) {
-  char *fileName = new char[_MAX_PATH];
-  char tempName[_MAX_PATH];
-  SAA_texture2DGetPicName( scene, texture, _MAX_PATH, tempName );
-
-  if (tex_path) {
-    // softegg_cat.spam() << "tempName :" << tempName << endl;
-    strcpy(fileName, tex_path);
-
-    // do some processing on the name string
-    char *tmpName = nullptr;
-    tmpName = strrchr(tempName, '/');
-    if (tmpName)
-      tmpName++;
-    else
-      tmpName = tempName;
-
-    // softegg_cat.spam() << "tmpName : " << tmpName << endl;
-    strcat(fileName, "/");
-    strcat(fileName, tmpName);
-  }
-  else {
-    strcpy(fileName, tempName);
-  }
-
-  strcat(fileName, ".pic");
-  // softegg_cat.spam() << "fileName : " << fileName << endl;
-
-  return fileName;
-}
-
-/**
- * Handles the reading of the input file and converting it to egg.  Returns
- * true if successful, false otherwise.
- *
- * This is designed to be as generic as possible, generally in support of run-
- * time loading.  Also see convert_soft().
- */
-bool SoftToEggConverter::
-convert_file(const Filename &filename) {
-  if (!open_api()) {
-    softegg_cat.error()
-      << "Soft is not available.\n";
-    return false;
-  }
-  if (_character_name.empty()) {
-    _character_name = filename.get_basename_wo_extension();
-  }
-  return convert_soft(false);
-}
-
-/**
- * Fills up the egg_data structure according to the global soft model data.
- * Returns true if successful, false if there is an error.  If from_selection
- * is true, the converted geometry is based on that which is selected;
- * otherwise, it is the entire Soft scene.
- */
-bool SoftToEggConverter::
-convert_soft(bool from_selection) {
-  bool all_ok = true;
-
-  _from_selection = from_selection;
-  _textures.clear();
-
-  PT(EggData) egg_data = new EggData;
-  set_egg_data(egg_data);
-  softegg_cat.spam() << "eggData " << get_egg_data() << "\n";
-
-  // append the command line
-  softegg_cat.info() << _commandLine << endl;
-  get_egg_data()->insert(get_egg_data()->begin(), new EggComment("", _commandLine));
-
-  if (_egg_data->get_coordinate_system() != CS_default) {
-    softegg_cat.spam() << "coordinate system is not default\n";
-    exit(1);
-  }
-
-  _tree._use_prefix = use_prefix;
-  _tree._search_prefix = search_prefix;
-  all_ok = _tree.build_complete_hierarchy(scene, database);
-
-  // Lets see if we have gotten the hierarchy right _tree.print_hierarchy();
-  // exit(1);
-
-  char *root_name = _tree.GetRootName( eggFileName );
-
-  softegg_cat.debug() << "main group name: " << root_name << endl;
-  if (root_name)
-    _character_name = root_name;
-
-  if (make_poly || make_nurbs) {
-    // Specify that the texture names should be relative to the output file.
-    Filename output_filename(eggFileName);
-    _path_replace->_path_store = PS_relative;
-    _path_replace->_path_directory = output_filename.get_dirname();
-
-    if (!convert_char_model()) {
-      all_ok = false;
-    }
-
-    // generate soft skinning assignments if desired
-    if (!make_soft_skin()) {
-      all_ok = false;
-    }
-
-    // sometimes you need to hard assign some vertices
-    if (!cleanup_soft_skin()) {
-      all_ok = false;
-    }
-
-    // reparent_decals(get_egg_data());
-    softegg_cat.info() << "Converted Softimage file\n";
-
-    // write out the egg model file
-    _egg_data->write_egg(output_filename);
-    softegg_cat.info() << "Wrote Egg file " << output_filename << endl;
-  }
-  if (make_anim) {
-    if (!convert_char_chan()) {
-      all_ok = false;
-    }
-
-    // reparent_decals(get_egg_data());
-    softegg_cat.info() << "Converted Softimage file\n";
-
-    // write out the egg model file
-    _egg_data->write_egg(Filename(animFileName));
-    softegg_cat.info() << "Wrote Anim file " << animFileName << endl;
-  }
-  return all_ok;
-}
-
-/**
- * Attempts to open the Soft API if it was not already open, and returns true
- * if successful, or false if there is an error.
- */
-bool SoftToEggConverter::
-open_api() {
-  if ((scene_name == nullptr && model_name == nullptr) || database_name == nullptr) {
-    Usage();
-    exit( 1 );
-  }
-  if ((result = SAA_Init(rsrc_path, FALSE)) != SI_SUCCESS) {
-    softegg_cat.info() << "Error: Couldn't get resource path!\n";
-    exit( 1 );
-  }
-  // cout << "got past init" << endl;
-  if ((result = SAA_databaseLoad(database_name, &database)) != SI_SUCCESS) {
-    softegg_cat.info() << "Error: Couldn't load database!\n";
-    exit( 1 );
-  }
-  // cout << "got past database load" << endl;
-  if ((result = SAA_sceneGetCurrent(&scene)) != SI_SUCCESS) {
-    softegg_cat.info() << "Error: Couldn't get current scene!\n";
-    exit( 1 );
-  }
-  // cout << "got past get current" << endl;
-  if ((result = SAA_sceneLoad( &database, scene_name, &scene )) != SI_SUCCESS) {
-    softegg_cat.info() << "Error: Couldn't load scene " << scene_name << "!\n";
-    exit( 1 );
-  }
-  // cout << "got past scene load" << endl;
-  if ( SAA_updatelistGet( &scene ) == SI_SUCCESS ) {
-    PN_stdfloat time;
-
-    softegg_cat.info() << "setting Scene to frame " << pose_frame << "...\n";
-    // SAA_sceneSetPlayCtrlCurrentFrame( &scene, pose_frame );
-    SAA_frame2Seconds( &scene, pose_frame, &time );
-    SAA_updatelistEvalScene( &scene, time );
-    if ( make_pose )
-      SAA_sceneFreeze(&scene);
-  }
-
-  // if no egg filename specified, make up a name
-  if ( eggFileName == nullptr ) {
-    string madeName;
-    string tempName(scene_name);
-    string::size_type end = tempName.find(".dsc");
-    if (end != string::npos) {
-      madeName.assign(tempName.substr(0,end));
-      if ( make_nurbs )
-        madeName.insert(madeName.size(), "-nurb");
-      madeName.insert(madeName.size(), ".egg" );
-    }
-    eggFileName = new char[madeName.size()+1];
-    strcpy(eggFileName, madeName.c_str());
-
-    // if no anim filename specified, make up a name
-    if ( animFileName == nullptr ) {
-      madeName.assign(tempName.substr(0,end));
-      madeName.insert(madeName.size(), "-chan.egg");
-      animFileName = new char[strlen(scene_name)+ 10];
-      strcpy(animFileName, madeName.c_str());
-    }
-  }
-
-  return true;
-}
-
-/**
- * Closes the Soft API, if it was previously opened.  Caution!  Soft appears
- * to call exit() when its API is closed.
- */
-void SoftToEggConverter::
-close_api() {
-  // don't know yet
-}
-
-/**
- * Converts the file as an animatable character model, with joints and vertex
- * membership.
- */
-bool SoftToEggConverter::
-convert_char_model() {
-  softegg_cat.spam() << "character name " << _character_name << "\n";
-  EggGroup *char_node = new EggGroup(eggGroupName);
-  get_egg_data()->add_child(char_node);
-  char_node->set_dart_type(EggGroup::DT_default);
-
-  return convert_hierarchy(char_node);
-}
-
-/**
- * Given a tablename, it either creates a new eggSAnimData structure (if
- * doesn't exist) or locates it.
- */
-EggSAnimData *SoftToEggConverter::
-find_morph_table(char *name) {
-  EggSAnimData *anim = nullptr;
-  MorphTable::iterator mt;
-  for (mt = _morph_table.begin(); mt != _morph_table.end(); ++mt) {
-    anim = (*mt);
-    if (!strcmp(anim->get_name().c_str(), name))
-      return anim;
-  }
-
-  // create an entry
-  anim = new EggSAnimData(name);
-  anim->set_fps(_tree._fps);
-  _morph_table.push_back(anim);
-  morph_node->add_child(anim);
-  return anim;
-}
-
-/**
- * Converts the animation as a series of tables to apply to the character
- * model, as retrieved earlier via AC_model.
- */
-bool SoftToEggConverter::
-convert_char_chan() {
-  int start_frame = -1;
-  int end_frame = -1;
-  int frame_inc, frame;
-  double output_frame_rate = anim_rate;
-
-  PN_stdfloat time;
-
-  EggTable *root_table_node = new EggTable();
-  get_egg_data()->add_child(root_table_node);
-  EggTable *bundle_node = new EggTable(eggGroupName);
-  bundle_node->set_table_type(EggTable::TT_bundle);
-  root_table_node->add_child(bundle_node);
-  EggTable *skeleton_node = new EggTable("<skeleton>");
-  bundle_node->add_child(skeleton_node);
-
-  morph_node = new EggTable("morph");
-
-  // Set the frame rate before we start asking for anim tables to be created.
-  SAA_sceneGetPlayCtrlStartFrame(&scene, &start_frame);
-  SAA_sceneGetPlayCtrlEndFrame(&scene, &end_frame);
-  SAA_sceneGetPlayCtrlFrameStep( &scene, &frame_inc );
-  if (frame_inc != 1) // Hmmm...some files gave me frame_inc of 0, that can't be good
-    frame_inc = 1;
-
-  softegg_cat.info() << "animation start frame: " << start_frame << " end frame: " << end_frame << endl;
-  softegg_cat.info() << "animation frame inc: " << frame_inc << endl;
-
-  _tree._fps = output_frame_rate / frame_inc;
-  // _tree.clear_egg(get_egg_data(), NULL, root_node);
-  _tree.clear_egg(get_egg_data(), nullptr, skeleton_node);
-
-  // Now we can get the animation data by walking through all of the frames,
-  // one at a time, and getting the joint angles at each frame.
-
-  // This is just a temporary EggGroup to receive the transform for each joint
-  // each frame.
-  PT(EggGroup) tgroup = new EggGroup;
-
-  int num_nodes = _tree.get_num_nodes();
-  int i;
-
-  // MTime frame(start_frame, MTime::uiUnit()); MTime frame_stop(end_frame,
-  // MTime::uiUnit()); start at first frame and go to last
-  if (make_pose) {
-    start_frame = pose_frame;
-    end_frame = pose_frame;
-  }
-  if (anim_start > 0)
-    start_frame = anim_start;
-  if (anim_end > 0)
-    end_frame = anim_end;
-  for ( frame = start_frame; frame <= end_frame; frame += frame_inc) {
-    SAA_frame2Seconds( &scene, frame, &time );
-    // softegg_cat.spam() << "got time " << time << endl;
-    if (!make_pose) {
-      SAA_updatelistEvalScene( &scene, time );
-    }
-    softegg_cat.spam() << "\n> animating frame " << frame << endl;
-
-    // if (softegg_cat.is_debug()) { softegg_cat.debug(false)
-    softegg_cat.info() << "frame " << time << "\n";
-    // } else { We have to write to cerr instead of softegg_cat to allow
-    // flushing without writing a newline.  std::cerr << "." << std::flush; }
-    // MGlobal::viewFrame(frame);
-
-    for (i = 0; i < num_nodes; i++) {
-      SoftNodeDesc *node_desc = _tree.get_node(i);
-
-      if (node_desc->is_partial(search_prefix)) {
-        softegg_cat.debug() << endl;
-        continue;
-      }
-      if (make_morph) {
-        node_desc->make_morph_table(time);
-      }
-      if (node_desc->is_joint()) {
-        softegg_cat.spam() << "-----joint " << node_desc->get_name() << "\n";
-        EggXfmSAnim *anim = _tree.get_egg_anim(node_desc);
-        // following function fills in the anim structure
-        node_desc->get_joint_transform(&scene, tgroup, anim, TRUE);
-      }
-    }
-
-    // frame += frame_inc;
-  }
-
-  if (has_morph)
-    bundle_node->add_child(morph_node);
-
-  // Now optimize all of the tables we just filled up, for no real good
-  // reason, except that it makes the resulting egg file a little easier to
-  // read.
-  for (i = 0; i < num_nodes; i++) {
-    SoftNodeDesc *node_desc = _tree.get_node(i);
-    if (node_desc->is_partial(search_prefix))
-      continue;
-
-    if (node_desc->is_joint()) {
-      _tree.get_egg_anim(node_desc)->optimize();
-    }
-  }
-
-  softegg_cat.info(false)
-    << "\n";
-
-  return true;
-}
-
-/**
- * Generates egg structures for each node in the Soft hierarchy.
- */
-bool SoftToEggConverter::
-convert_hierarchy(EggGroupNode *egg_root) {
-  int num_nodes = _tree.get_num_nodes();
-
-  _tree.clear_egg(get_egg_data(), egg_root, nullptr);
-  softegg_cat.spam() << "num_nodes = " << num_nodes << endl;
-  for (int i = 0; i < num_nodes; i++) {
-    if (!process_model_node(_tree.get_node(i))) {
-      return false;
-    }
-    softegg_cat.debug() << i << endl;
-  }
-  return true;
-}
-
-/**
- * Converts the indicated Soft node (given a MDagPath, similar in concept to
- * Panda's NodePath) to the corresponding Egg structure.  Returns true if
- * successful, false if an error was encountered.
- */
-bool SoftToEggConverter::
-process_model_node(SoftNodeDesc *node_desc) {
-  EggGroup *egg_group = nullptr;
-  const char *name = nullptr;
-  char *fullname = nullptr;
-  SAA_ModelType type;
-
-  name = node_desc->get_name().c_str();
-  softegg_cat.debug() << "element name <" << name << ">\n";
-
-  if (node_desc->is_junk()) {
-    softegg_cat.spam() << "no processing, it is junk\n";
-    return true;
-  }
-
-  // split
-  if (node_desc->is_partial(search_prefix)) {
-    softegg_cat.debug() << endl;
-    return true;
-  }
-  else
-    softegg_cat.debug() << endl << name << ":being processed" << endl;
-
-  egg_group = _tree.get_egg_group(node_desc);
-
-  // find out what type of node we're dealing with
-  SAA_modelGetType( &scene, node_desc->get_model(), &type );
-
-  softegg_cat.debug() << "encountered ";
-  switch(type){
-  case SAA_MNILL:
-    softegg_cat.debug() << "null\n";
-    break;
-  case SAA_MPTCH:
-    softegg_cat.debug() << "patch\n";
-    break;
-  case SAA_MFACE:
-    softegg_cat.debug() << "face\n";
-    // break;
-  case SAA_MSMSH:
-    softegg_cat.debug() << "mesh\n";
-    node_desc->get_transform(&scene, egg_group, TRUE);
-    make_polyset(node_desc, egg_group, type);
-    break;
-  case SAA_MJNT:
-    softegg_cat.debug() << "joint";
-    softegg_cat.debug() << " joint type " << node_desc->is_joint() << endl;
-    break;
-  case SAA_MSPLN:
-    softegg_cat.debug() << "spline\n";
-    break;
-  case SAA_MMETA:
-    softegg_cat.debug() << "meta element\n";
-    break;
-  case SAA_MBALL:
-    softegg_cat.debug() << "meta ball\n";
-    break;
-  case SAA_MNCRV:
-    softegg_cat.debug() << "nurbs curve\n";
-    break;
-  case SAA_MNSRF:
-    softegg_cat.debug() << "nurbs surf\n";
-    node_desc->get_transform(&scene, egg_group, TRUE);
-    make_nurb_surface(node_desc, egg_group, type);
-    break;
-  default:
-    softegg_cat.debug() << "unknown type: " << type << "\n";
-  }
-
-  if (node_desc->is_joint())
-    node_desc->get_transform(&scene, egg_group, FALSE);
-
-  return true;
-}
-
-/**
- * Converts the indicated Soft polyset to a bunch of EggPolygons and parents
- * them to the indicated egg group.
- */
-void SoftToEggConverter::
-make_polyset(SoftNodeDesc *node_desc, EggGroup *egg_group, SAA_ModelType type) {
-  int id = 0;
-  int i, idx;
-  int numShapes;
-  SAA_Boolean valid;
-  SAA_Boolean visible;
-  PN_stdfloat *uCoords = nullptr;
-  PN_stdfloat *vCoords = nullptr;
-  string name = node_desc->get_name();
-
-  SAA_modelGetNodeVisibility( &scene, node_desc->get_model(), &visible );
-  softegg_cat.spam() << "model visibility: " << visible << endl;
-
-  // Only create egg polygon data if: the node is visible, and its not a NULL
-  // or a Joint, and we're outputing polys (or if we are outputing NURBS and
-  // the model is a poly mesh or a face)
-  if ( visible &&
-       (type != SAA_MNILL) &&
-       (type != SAA_MJNT) &&
-       ((make_poly ||
-         (make_nurbs && ((type == SAA_MSMSH) || (type == SAA_MFACE )) )) ||
-        (!make_poly && !make_nurbs && make_duv &&
-         ((type == SAA_MSMSH) || (type == SAA_MFACE )) ))
-       )
-    {
-      // Get the number of key shapes
-      SAA_modelGetNbShapes( &scene, node_desc->get_model(), &numShapes );
-      softegg_cat.spam() << "process_model_node: num shapes: " << numShapes << endl;
-
-      // load all node data from soft for this node_desc
-      node_desc->load_poly_model(&scene, type);
-
-      string vpool_name = name + ".verts";
-      EggVertexPool *vpool = new EggVertexPool(vpool_name);
-      vpool->set_highest_index(0);
-
-      // add the vertices in the _tree._root node, so that they will be
-      // written out first in egg file.  This solves a problem of soft-
-      // skinning trying to access vertex pool before it is defined.
-
-      _tree.get_egg_root()->insert(_tree.get_egg_root()->begin(), vpool);
-
-      // We will need to transform all vertices from world coordinate space
-      // into the vertex space appropriate to this node.  Usually, this is the
-      // same thing as world coordinate space, and this matrix will be
-      // identity; but if the node is under an instance (particularly, for
-      // instance, a billboard) then the vertex space will be different from
-      // world space.
-      LMatrix4d vertex_frame_inv = egg_group->get_vertex_frame_inv();
-
-      // Asad: change from soft2egg.c.  Here I am trying to get one triangles
-      // vertices not all
-      for (idx=0; idx<node_desc->numTri; ++idx) {
-        EggPolygon *egg_poly = new EggPolygon;
-        egg_group->add_child(egg_poly);
-
-        softegg_cat.spam() << "processing polygon " << idx << endl;
-
-        // Is this a double sided polygon?  meaning check for back face flag
-        char *modelNoteStr = _tree.GetModelNoteInfo( &scene, node_desc->get_model() );
-        if ( modelNoteStr != nullptr ) {
-          if ( strstr( modelNoteStr, "bface" ) != nullptr )
-            egg_poly->set_bface_flag(TRUE);
-        }
-
-        // read each triangle's control vertices into array
-        SAA_SubElem cvertices[3];
-        SAA_triangleGetCtrlVertices( &scene, node_desc->get_model(), node_desc->gtype, id, 1, node_desc->triangles+idx, cvertices );
-
-        // read control vertices in this triangle
-        SAA_DVector cvertPos[3];
-        SAA_ctrlVertexGetPositions( &scene, node_desc->get_model(), 3, cvertices, cvertPos);
-
-        // read indices of each vertices in this triangle
-        int indices[3];
-        indices[0] = indices[1] = indices[2] = 0;
-        SAA_ctrlVertexGetIndices( &scene, node_desc->get_model(), 3, cvertices, indices );
-
-        // read each control vertex's normals into an array
-        SAA_DVector normals[3];
-        SAA_ctrlVertexGetNormals( &scene, node_desc->get_model(), 3, cvertices, normals );
-        for (i=0; i<3; ++i)
-          softegg_cat.spam() << "normals[" << i <<"] = " << normals[i].x << " " <<  normals[i].y
-               << " " << normals[i].z << " " <<  normals[i].w << "\n";
-
-        // allocate arrays for u & v coords
-        if (node_desc->textures) {
-          if (node_desc->numTexLoc && node_desc->numTexTri[idx]) {
-            // allocate arrays for u & v coords I think there are one texture
-            // per triangle hence we need only 3 corrdinates
-            uCoords = new PN_stdfloat[3];
-            vCoords = new PN_stdfloat[3];
-
-            // read the u & v coords into the arrays
-            if ( uCoords != nullptr && vCoords != nullptr) {
-              for ( i = 0; i < 3; i++ )
-                uCoords[i] = vCoords[i] = 0.0f;
-
-              // TODO: investigate the coord_cnt parameter...
-              SAA_ctrlVertexGetUVTxtCoords( &scene, node_desc->get_model(), 3, cvertices,
-                                            3, uCoords, vCoords );
-            }
-            else
-              softegg_cat.info() << "Not enough Memory for texture coords...\n";
-
-#if 1
-            for ( i=0; i<3; i++ )
-              softegg_cat.spam() << "texcoords[" << i << "] = ( " << uCoords[i] << " , " << vCoords[i] <<" )\n";
-#endif
-          }
-          else if (node_desc->numTexGlb) {
-            // allocate arrays for u & v coords
-            uCoords = new PN_stdfloat[node_desc->numTexGlb*3];
-            vCoords = new PN_stdfloat[node_desc->numTexGlb*3];
-
-            for ( i = 0; i < node_desc->numTexGlb*3; i++ ) {
-              uCoords[i] = vCoords[i] = 0.0f;
-            }
-
-            // read the u & v coords into the arrays
-            if ( uCoords != nullptr && vCoords != nullptr) {
-              SAA_triCtrlVertexGetGlobalUVTxtCoords( &scene, node_desc->get_model(), 3, cvertices,
-                                                     node_desc->numTexGlb, node_desc->textures, uCoords, vCoords );
-            }
-            else
-              softegg_cat.info() << "Not enough Memory for texture coords...\n";
-          }
-        }
-
-        for ( i=0; i < 3; i++ ) {
-          EggVertex vert;
-
-          // There are some conversions needed from local matrix to global
-          // coords
-          SAA_DVector local = cvertPos[i];
-          SAA_DVector global = {0};
-
-          _VCT_X_MAT( global, local, node_desc->matrix );
-
-          softegg_cat.spam() << "indices[" << i << "] = " << indices[i] << "\n";
-          softegg_cat.spam() << "cvert[" << i << "] = " << cvertPos[i].x << " " << cvertPos[i].y
-                              << " " << cvertPos[i].z << " " << cvertPos[i].w << "\n";
-          softegg_cat.spam() << " global cvert[" << i << "] = " << global.x << " " << global.y
-                              << " " << global.z << " " << global.w << "\n";
-
-          // LPoint3d p3d(cvertPos[i].x, cvertPos[i].y, cvertPos[i].z);
-          LPoint3d p3d(global.x, global.y, global.z);
-          p3d = p3d * vertex_frame_inv;
-          vert.set_pos(p3d);
-
-          local = normals[i];
-          _VCT_X_MAT( global, local, node_desc->matrix );
-
-          softegg_cat.spam() << "normals[" << i <<"] = " << normals[i].x << " " <<  normals[i].y
-               << " " << normals[i].z << " " <<  normals[i].w << "\n";
-          softegg_cat.spam() << " global normals[" << i <<"] = " << global.x << " " <<  global.y
-               << " " << global.z << " " <<  global.w << "\n";
-
-          LVector3d n3d(global.x, global.y, global.z);
-          n3d = n3d * vertex_frame_inv;
-          vert.set_normal(n3d);
-
-          // if texture present set the texture coordinates
-          if (node_desc->textures) {
-            PN_stdfloat u, v;
-
-            if (uCoords && vCoords) {
-              u = uCoords[i];
-              v = 1.0f - vCoords[i];
-              softegg_cat.spam() << "texcoords[" << i << "] = " << u << " "
-                                 << v << endl;
-
-              vert.set_uv(LTexCoordd(u, v));
-              // vert.set_uv(LTexCoordd(uCoords[i], vCoords[i]));
-            }
-          }
-          vert.set_external_index(indices[i]);
-          egg_poly->add_vertex(vpool->create_unique_vertex(vert));
-
-          // check to see if material is present
-          PN_stdfloat r,g,b,a;
-          SAA_elementIsValid( &scene, &node_desc->materials[idx], &valid );
-          // material present - get the color
-          if ( valid ) {
-            SAA_materialGetDiffuse( &scene, &node_desc->materials[idx], &r, &g, &b );
-            SAA_materialGetTransparency( &scene, &node_desc->materials[idx], &a );
-            egg_poly->set_color(LColor(r, g, b, 1.0f - a));
-            softegg_cat.spam() << "color r = " << r << " g = " << g << " b = " << b << " a = " << 1.0f - a << "\n";
-          }
-          else {     // no material - default to white
-            egg_poly->set_color(LColor(1.0, 1.0, 1.0, 1.0));
-            softegg_cat.spam() << "default color\n";
-          }
-
-          /*
-          // keep a one to one copy in this node's vpool
-          EggVertex *t_vert = new EggVertex(vert);
-          if (!t_vert) {
-            softegg_cat.spam() << "out of memeory " << endl;
-            nassertv(t_vert != NULL);
-          }
-          node_desc->get_vpool()->add_vertex(t_vert, indices[i]);
-          */
-
-          softegg_cat.spam() << "\n";
-        }
-
-        // Now apply the shader.
-        if (node_desc->textures != nullptr) {
-          if (node_desc->numTexLoc && node_desc->numTexTri[idx]) {
-            if (!strstr(node_desc->texNameArray[idx], "noIcon"))
-              set_shader_attributes(node_desc, *egg_poly, idx);
-            else
-              softegg_cat.spam() << "texname :" << node_desc->texNameArray[idx] << endl;
-          }
-          else {
-            if (!strstr(node_desc->texNameArray[0], "noIcon"))
-              set_shader_attributes(node_desc, *egg_poly, 0);
-            else
-              softegg_cat.spam() << "texname :" << node_desc->texNameArray[0] << endl;
-        }
-      }
-      }
-      // if model has key shapes, generate vertex offsets
-      if ( numShapes > 0 && make_morph )
-        node_desc->make_vertex_offsets( numShapes);
-    }
-}
-
-/**
- * Converts the indicated Soft nurbs set to a bunch of EggPolygons and parents
- * them to the indicated egg group.
- */
-void SoftToEggConverter::
-make_nurb_surface(SoftNodeDesc *node_desc, EggGroup *egg_group, SAA_ModelType type) {
-  int id = 0;
-  int i, j, k;
-  int numShapes;
-  SAA_Boolean valid;
-  SAA_Boolean visible;
-  PN_stdfloat *uCoords = nullptr;
-  PN_stdfloat *vCoords = nullptr;
-  string name = node_desc->get_name();
-
-  SAA_modelGetNodeVisibility( &scene, node_desc->get_model(), &visible );
-  softegg_cat.spam() << "model visibility: " << visible << endl;
-  softegg_cat.spam() << "nurbs!!!surface!!!" << endl;
-
-  // check to see if its a nurbs surface
-  if ( (type == SAA_MNSRF) && ( visible ) && (( make_nurbs )
-                                              || ( !make_nurbs && !make_poly &&  make_duv )) )
-    {
-      // Get the number of key shapes
-      SAA_modelGetNbShapes( &scene, node_desc->get_model(), &numShapes );
-      softegg_cat.spam() << "process_model_node: num shapes: " << numShapes << endl;
-
-      // load all node data from soft for this node_desc
-      node_desc->load_nurbs_model(&scene, type);
-
-      string vpool_name = name + ".verts";
-      EggVertexPool *vpool = new EggVertexPool(vpool_name);
-      vpool->set_highest_index(0);
-
-      // add the vertices in the _tree._egg_root node, so that they will be
-      // written out first in egg file.  This solves a problem of soft-
-      // skinning trying to access vertex pool before it is defined.
-
-      // _tree.get_egg_root()->add_child(vpool);
-      _tree.get_egg_root()->insert(_tree.get_egg_root()->begin(), vpool);
-
-      // egg_group->add_child(vpool);
-
-      /*
-      // create a copy of vpool in node_desc which will be used later for
-      // soft_skinning
-      node_desc->create_vpool(vpool_name);
-      */
-
-      int uRows, vRows;
-      int uKnots, vKnots;
-      int uExtra, vExtra;
-      int uDegree, vDegree;
-      int uCurves, vCurves;
-
-      vector <double> Knots;
-
-      EggNurbsSurface *eggNurbs = new EggNurbsSurface( name );
-
-      // create nurbs representation of surface
-      SAA_nurbsSurfaceGetDegree( &scene, node_desc->get_model(), &uDegree, &vDegree );
-      softegg_cat.spam() << "nurbs degree: " << uDegree << " u, " << vDegree << " v\n";
-
-      SAA_nurbsSurfaceGetNbKnots( &scene, node_desc->get_model(), &uKnots, &vKnots );
-      softegg_cat.spam() << "nurbs knots: " << uKnots << " u, " << vKnots << " v\n";
-
-      SAA_Boolean uClosed = FALSE;
-      SAA_Boolean vClosed = FALSE;
-
-      SAA_nurbsSurfaceGetClosed( &scene, node_desc->get_model(), &uClosed, &vClosed);
-
-      uExtra = vExtra = 2;
-      if ( uClosed ) {
-        softegg_cat.spam() << "nurbs is closed in u...\n";
-        uExtra += 4;
-      }
-      if ( vClosed ) {
-        softegg_cat.spam() << "nurbs is closed in v...\n";
-        vExtra += 4;
-      }
-      eggNurbs->setup(uDegree+1, vDegree+1,
-                      uKnots + uExtra, vKnots + vExtra);
-
-      softegg_cat.spam() << "from eggNurbs: num u knots " << eggNurbs->get_num_u_knots() << endl;
-      softegg_cat.spam() << "from eggNurbs: num v knots " << eggNurbs->get_num_v_knots() << endl;
-      softegg_cat.spam() << "from eggNurbs: num u cvs " << eggNurbs->get_num_u_cvs() << endl;
-      softegg_cat.spam() << "from eggNurbs: num v cvs " << eggNurbs->get_num_v_cvs() << endl;
-
-      SAA_nurbsSurfaceGetNbVertices( &scene, node_desc->get_model(), &uRows, &vRows );
-      softegg_cat.spam() << "nurbs vertices: " << uRows << " u, " << vRows << " v\n";
-
-      SAA_nurbsSurfaceGetNbCurves( &scene, node_desc->get_model(), &uCurves, &vCurves );
-      softegg_cat.spam() << "nurbs curves: " << uCurves << " u, " << vCurves << " v\n";
-
-      if ( shift_textures ) {
-        if ( uClosed )
-          // shift starting point on NURBS surface for correct textures
-          SAA_nurbsSurfaceShiftParameterization( &scene, node_desc->get_model(), -2, 0 );
-
-        if ( vClosed )
-          // shift starting point on NURBS surface for correct textures
-          SAA_nurbsSurfaceShiftParameterization( &scene, node_desc->get_model(), 0, -2 );
-      }
-
-      SAA_nurbsSurfaceSetStep( &scene, node_desc->get_model(), nurbs_step, nurbs_step );
-
-      // Is this a double sided polygon?  meaning check for back face flag
-      char *modelNoteStr = _tree.GetModelNoteInfo( &scene, node_desc->get_model() );
-      if ( modelNoteStr != nullptr ) {
-        if ( strstr( modelNoteStr, "bface" ) != nullptr ) {
-          eggNurbs->set_bface_flag(TRUE);
-          softegg_cat.spam() << "Set backface flag\n";
-        }
-      }
-
-      double *uKnotArray = new double[uKnots];
-      double *vKnotArray = new double[vKnots];
-      result = SAA_nurbsSurfaceGetKnots( &scene, node_desc->get_model(), node_desc->gtype, 0,
-                                         uKnots, vKnots, uKnotArray, vKnotArray );
-
-      if (result != SI_SUCCESS) {
-        softegg_cat.spam() << "Couldn't get knots\n";
-        exit(1);
-      }
-
-      // Lets prepare the softimage knots and then assign to eggKnots
-      add_knots( Knots, uKnotArray, uKnots, uClosed, uDegree );
-      softegg_cat.spam() << "u knots: ";
-      for (i = 0; i < (int)Knots.size(); i++) {
-        softegg_cat.spam() << Knots[i] << " ";
-        eggNurbs->set_u_knot(i, Knots[i]);
-      }
-      softegg_cat.spam() << endl;
-
-      Knots.resize(0);
-      add_knots( Knots, vKnotArray, vKnots, vClosed, vDegree );
-      softegg_cat.spam() << "v knots: ";
-      for (i = 0; i < (int)Knots.size(); i++) {
-        softegg_cat.spam() << Knots[i] << " ";
-        eggNurbs->set_v_knot(i, Knots[i]);
-      }
-      softegg_cat.spam() << endl;
-
-      // lets get the number of vertices from softimage
-      int numVert;
-      SAA_modelGetNbVertices( &scene, node_desc->get_model(), &numVert );
-
-      softegg_cat.spam() << numVert << " CV's\n";
-
-      // get the CV's
-      SAA_DVector *vertices = nullptr;
-      vertices = new SAA_DVector[numVert];
-
-      SAA_modelGetVertices( &scene, node_desc->get_model(), node_desc->gtype, 0, numVert, vertices );
-
-      LMatrix4d vertex_frame_inv = egg_group->get_vertex_frame_inv();
-
-      // create the buffer for EggVertices
-      EggVertex *verts = new EggVertex[numVert];
-
-      softegg_cat.spam() << endl << eggNurbs->get_num_cvs() << endl << endl;
-
-      // for ( i = 0; i<eggNurbs->get_num_cvs(); i++ ) {
-      for ( k = 0; k<numVert; k++ ) {
-        SAA_DVector global;
-
-        /*
-        int ui = eggNurbs->get_u_index(i);
-        int vi = eggNurbs->get_v_index(i);
-
-        int k = vRows * ui + vi;
-
-        softegg_cat.spam() << i << ": ui " << ui << ", vi " << vi << ", k " << k << endl;
-
-        softegg_cat.spam() << "original cv[" << k << "] = "
-             << vertices[k].x << " " << vertices[k].y << " "
-             << vertices[k].z << " " << vertices[k].w << endl;
-        */
-
-        // convert to global coords
-        _VCT_X_MAT( global, vertices[k], node_desc->matrix );
-
-        // preserve original weight
-        global.w = vertices[k].w;
-
-        // normalize coords to weight
-        global.x *= global.w;
-        global.y *= global.w;
-        global.z *= global.w;
-
-        /*
-        softegg_cat.spam() << "global cv[" << k << "] = "
-             << global.x << " " << global.y << " "
-             << global.x << " " << global.w << endl;
-        */
-
-        LPoint4d p4d(global.x, global.y, global.z, global.w);
-        p4d = p4d * vertex_frame_inv;
-        verts[k].set_pos(p4d);
-
-        // check to see if material is present
-        if (node_desc->numNurbMats) {
-          PN_stdfloat r,g,b,a;
-          SAA_elementIsValid( &scene, &node_desc->materials[0], &valid );
-          // material present - get the color
-          if ( valid ) {
-            SAA_materialGetDiffuse( &scene, &node_desc->materials[0], &r, &g, &b );
-            SAA_materialGetTransparency( &scene, &node_desc->materials[0], &a );
-            verts[k].set_color(LColor(r, g, b, 1.0f - a));
-            // softegg_cat.spam() << "color r = " << r << " g = " << g << " b
-            // = " << b << " a = " << a << "\n";
-          }
-          else {     // no material - default to white
-            verts[k].set_color(LColor(1.0, 1.0, 1.0, 1.0));
-            softegg_cat.spam() << "default color\n";
-          }
-        }
-        vpool->add_vertex(verts+k, k);
-        eggNurbs->add_vertex(vpool->get_vertex(k));
-
-        if ( uClosed ) {
-          // add first uDegree verts to end of row
-          if ( (k % uRows) == ( uRows - 1) ) {
-            for ( i = 0; i < uDegree; i++ ) {
-              // add vref's to NURBS info
-              eggNurbs->add_vertex( vpool->get_vertex(i+((k/uRows)*uRows)) );
-            }
-          }
-        }
-      }
-
-      // check to see if the NURB is closed in v
-      if ( vClosed && !uClosed ) {
-        // add first vDegree rows of verts to end of list
-        for ( int i = 0; i < vDegree*uRows; i++ )
-          eggNurbs->add_vertex( vpool->get_vertex(i) );
-      }
-      // check to see if the NURB is closed in u and v
-      else if ( vClosed && uClosed ) {
-        // add the first (degree) v verts and a few extra - for good measure
-        for ( i = 0; i < vDegree; i++ ) {
-          // add first vDegree rows of verts to end of list
-          for ( j = 0; j < uRows; j++ )
-            eggNurbs->add_vertex( vpool->get_vertex(j+(i*uRows)) );
-
-          // if u is closed to we have added uDegree verts onto the ends of
-          // the rows - add them here too
-          for ( k = 0; k < uDegree; k++ )
-            eggNurbs->add_vertex( vpool->get_vertex(k+(i*uRows)+((k/uRows)*uRows)) );
-        }
-      }
-
-      // We add the NURBS to the group down here, after all of the vpools for
-      // the trim curves have been added.
-      egg_group->add_child(eggNurbs);
-
-      // Now apply the shader.
-      if (node_desc->textures != nullptr) {
-        if (!strstr(node_desc->texNameArray[0], "noIcon"))
-          set_shader_attributes(node_desc, *eggNurbs, 0);
-        else
-          softegg_cat.spam() << "texname :" << node_desc->texNameArray[0] << endl;
-      }
-
-      // if model has key shapes, generate vertex offsets
-      if ( numShapes > 0 && make_morph )
-        node_desc->make_vertex_offsets( numShapes);
-    }
-}
-
-/**
- * Given a parametric surface, and its knots, create the appropriate egg
- * structure by filling in Soft's implicit knots and assigning the rest to
- * eggKnots.
- */
-void SoftToEggConverter::
-add_knots( vector <double> &eggKnots, double *knots, int numKnots, SAA_Boolean closed, int degree ) {
-
-  int k = 0;
-  double lastKnot = knots[0];
-  double    *newKnots;
-
-  // add initial implicit knot(s)
-  if ( closed ) {
-    int i = 0;
-    newKnots = new double[degree];
-
-    // need to add (degree) number of knots
-    for ( k = numKnots - 1; k >= numKnots - degree; k-- ) {
-      // we have to know these in order to calculate next knot value so hold
-      // them in temp array
-      newKnots[i] =  lastKnot - (knots[k] - knots[k-1]);
-      lastKnot = newKnots[i];
-      i++;
-    }
-    for ( k = degree - 1; k >= 0; k-- ) {
-      eggKnots.push_back( newKnots[k] );
-      softegg_cat.spam() << "knots[" << k << "] = " << newKnots[k] << endl;
-    }
-  }
-  else {
-    eggKnots.push_back( knots[k] );
-    softegg_cat.spam() << "knots[" << k << "] = " << knots[k] << endl;
-  }
-
-  // add the regular complement of knots
-  for (k = 0; k < numKnots; k++) {
-    eggKnots.push_back( knots[k] );
-    softegg_cat.spam() << "knots[" << k+1 << "] = " << knots[k] << endl;
-  }
-
-  lastKnot = knots[numKnots-1];
-
-  // add trailing implicit knots
-  if ( closed ) {
-    // need to add (degree) number of knots
-    for ( k = 1; k <= degree; k++ ) {
-      eggKnots.push_back( lastKnot + (knots[k] - knots[k-1]) );
-      softegg_cat.spam() << "knots[" << k << "] = " << lastKnot + (knots[k] - knots[k-1]) << endl;
-      lastKnot = lastKnot + (knots[k] - knots[k-1]);
-    }
-  }
-  else {
-    eggKnots.push_back( knots[k-1] );
-    softegg_cat.spam() << "knots[" << k+1 << "] = " << knots[k-1] << endl;
-  }
-}
-
-/**
- * Given an egg vertex pool, map each vertex therein to a vertex within an
- * array of SAA model vertices of size numVert.  Mapping is done by closest
- * proximity.
- */
-int *SoftToEggConverter::
-FindClosestTriVert( EggVertexPool *vpool, SAA_DVector *vertices, int numVert ) {
-  int i,j;
-  int *vertMap = nullptr;
-  int vpoolSize = (int)vpool->size();
-  PN_stdfloat closestDist;
-  PN_stdfloat thisDist;
-  int closest;
-
-  vertMap = new int[vpoolSize];
-  i = 0;
-  EggVertexPool::iterator vi;
-  for (vi = vpool->begin(); vi != vpool->end(); ++vi, ++i) {
-    EggVertex *vert = (*vi);
-    softegg_cat.spam() << "vert external index = " << vert->get_external_index() << endl;
-    // softegg_cat.spam() << "found vert " << vert << endl; softegg_cat.spam()
-    // << "vert [" << i << "] " << vpool->get_vertex(i+1);
-    LPoint3d p3d = vert->get_pos3();
-
-    // find closest model vertex
-    for ( j = 0; j < numVert; j++ ) {
-      // calculate distance
-      thisDist = sqrtf(
-                       powf( p3d[0] - vertices[j].x , 2 ) +
-                       powf( p3d[1] - vertices[j].y , 2 ) +
-                       powf( p3d[2] - vertices[j].z , 2 ) );
-
-      // remember this if its the closest so far
-      if ( !j || ( thisDist < closestDist ) ) {
-        closest = j;
-        closestDist = thisDist;
-      }
-    }
-
-    vertMap[i] = closest;
-    softegg_cat.spam() << "mapping v " << i << " of " << vpoolSize-1 << ":( "
-                       << p3d[0] << " "
-                       << p3d[1] << " "
-                       << p3d[2] << ")\n";
-
-    softegg_cat.spam() << "    to cv " << closest << " of " << numVert-1 << ":( "
-                       << vertices[closest].x << " "
-                       << vertices[closest].y << " "
-                       << vertices[closest].z << " )\tdelta = " << closestDist << endl;
-  }
-  return vertMap;
-}
-
-/**
- * make soft skin assignments to the mesh finally call cleanup_soft_skin to
- * clean it up
- */
-bool SoftToEggConverter::
-make_soft_skin() {
-  int num_nodes = _tree.get_num_nodes();
-  SoftNodeDesc *node_desc;
-  SAA_Boolean isSkeleton;
-
-  softegg_cat.spam() << endl << "----------------------------------------------------------------" << endl;
-
-  for (int i = 0; i < num_nodes; i++) {
-    node_desc = _tree.get_node(i);
-    SAA_modelIsSkeleton( &scene, node_desc->get_model(), &isSkeleton );
-
-    softegg_cat.spam() << "??checking node " << node_desc->get_name() << " isSkel " << isSkeleton << " isJoint " << node_desc->is_joint() << endl;
-    if (isSkeleton && node_desc->is_joint()) {
-
-      if (node_desc->is_partial(search_prefix))
-          continue;
-
-      // Now that we've added all the polygons (and created all the vertices),
-      // go back through the vertex pool and set up the appropriate joint
-      // membership for each of the vertices.
-
-      // check for envelops
-      int numEnv;
-      SAA_ModelType type;
-      SAA_Elem *envelopes;
-      SAA_Elem *model = node_desc->get_model();
-      EggGroup *joint = nullptr;
-      EggVertexPool *vpool;
-
-      SAA_skeletonGetNbEnvelopes( &scene, model, &numEnv );
-      if ( numEnv == 0 ) {
-        softegg_cat.spam() << "no soft skinning for joint " << node_desc->get_name() << endl;
-        continue;
-      }
-
-      // it's got envelopes - must be soft skinned
-      softegg_cat.spam() << endl << "found skeleton part( " << node_desc->get_name() << ")!\n";
-      softegg_cat.spam() << "numEnv = " << numEnv << endl;
-      // allocate envelope array
-      envelopes = new SAA_Elem[numEnv];
-      if ( envelopes == nullptr ) {
-        softegg_cat.info() << "Out Of Memory" << endl;
-        exit(1);
-      }
-      int thisEnv;
-      SAA_EnvType envType;
-      bool hasEnvVertices = 0;
-
-      SAA_skeletonGetEnvelopes( &scene, model, numEnv, envelopes );
-      for ( thisEnv = 0; thisEnv < numEnv; thisEnv++ ) {
-        softegg_cat.spam() << "env[" << thisEnv << "]: ";
-        SAA_envelopeGetType( &scene, &envelopes[thisEnv], &envType );
-
-        if ( envType == SAA_ENVTYPE_NONE ) {
-          softegg_cat.spam() << "envType = none\n";
-        }
-        else if ( envType == SAA_ENVTYPE_FLXLCL ) {
-          softegg_cat.spam() << "envType = flexible, local\n";
-          hasEnvVertices = 1;
-        }
-        else if ( envType == SAA_ENVTYPE_FLXGLB ) {
-          softegg_cat.spam() << "envType = flexible, global\n";
-          hasEnvVertices = 1;
-        }
-        else if ( envType == SAA_ENVTYPE_RGDGLB ) {
-          softegg_cat.spam() << "envType = rigid, global\n";
-          hasEnvVertices = 1;
-        }
-        else {
-          softegg_cat.spam() << "envType = unknown\n";
-        }
-
-      }
-      if ( !hasEnvVertices )
-        continue;
-
-      SAA_SubElem *envVertices = nullptr;
-      int *numEnvVertices;
-      int i,j,k;
-
-      numEnvVertices = new int[numEnv];
-
-      if ( numEnvVertices != nullptr ) {
-        SAA_envelopeGetNbCtrlVertices( &scene, model, numEnv, envelopes, numEnvVertices );
-        int totalEnvVertices = 0;
-        for( i = 0; i < numEnv; i++ ) {
-          totalEnvVertices += numEnvVertices[i];
-          softegg_cat.spam() << "numEnvVertices[" << i << "] = " << numEnvVertices[i] << endl;
-        }
-        softegg_cat.spam() << "total env verts = " << totalEnvVertices << endl;
-        if ( totalEnvVertices == 0 )
-          continue;
-
-        envVertices = new SAA_SubElem[totalEnvVertices];
-        if ( envVertices != nullptr ) {
-          result = SAA_envelopeGetCtrlVertices( &scene, model,
-                                                numEnv, envelopes, numEnvVertices, envVertices);
-          if (result != SI_SUCCESS) {
-            softegg_cat.spam() << "error: GetCtrlVertices\n";
-            exit(1);
-          }
-          // loop through for each envelope
-          for ( i = 0; i < numEnv; i++ ) {
-            PN_stdfloat *weights = nullptr;
-            int vertArrayOffset = 0;
-            softegg_cat.spam() << "envelope[" << i << "]: ";
-            weights = new PN_stdfloat[numEnvVertices[i]];
-            if ( weights ) {
-              char *envName;
-              int *vpoolMap = nullptr;
-              for ( j = 0; j < i; j++ )
-                vertArrayOffset += numEnvVertices[j];
-              softegg_cat.spam() << "envVertArray offset = " << vertArrayOffset;
-
-              /*
-              if (vertArrayOffset == totalEnvVertices) {
-                softegg_cat.spam() << endl;                  vpoolMap = FindClosestTriVert( vpool, globalModelVertices, modelNumVert );
-
-                break;
-              }
-              */
-
-              // get the weights of the envelope vertices
-              result = SAA_ctrlVertexGetEnvelopeWeights( &scene, model, &envelopes[i],
-                                                         numEnvVertices[i],
-                                                         &envVertices[vertArrayOffset], weights );
-
-              // Get the name of the envelope model
-              if ( use_prefix ) {
-                // Get the FULL name of the envelope
-                envName = _tree.GetFullName( &scene, &envelopes[i] );
-              }
-              else {
-                // Get the name of the envelope
-                envName = _tree.GetName( &scene, &envelopes[i] );
-              }
-
-              softegg_cat.spam() << " envelop name is [" << envName << "]" << endl;
-
-              if (result != SI_SUCCESS) {
-                softegg_cat.spam() << "warning: this envelop doesn't have any weights\n";
-                continue;
-              }
-
-              result = SAA_modelGetType( &scene, &envelopes[i], &type );
-              if (result != SI_SUCCESS) {
-                softegg_cat.debug() << "choked on get type\n";
-                exit(1);
-              }
-
-              softegg_cat.spam() << "envelope model type ";
-              if ( type == SAA_MSMSH )
-                softegg_cat.spam() << "MESH\n";
-              else if ( type == SAA_MNSRF )
-                softegg_cat.spam() << "NURBS\n";
-              else
-                softegg_cat.spam() << "OTHER\n";
-
-              int *envVtxIndices = nullptr;
-              envVtxIndices = new int[numEnvVertices[i]];
-
-              // Get the envelope vertex indices
-              result = SAA_ctrlVertexGetIndices( &scene, &envelopes[i], numEnvVertices[i],
-                                                 &envVertices[vertArrayOffset], envVtxIndices );
-
-              if (result != SI_SUCCESS) {
-                softegg_cat.debug() << "error: choked on get indices\n";
-                exit(1);
-              }
-
-              // find out how many vertices the model has
-              int modelNumVert;
-
-              SAA_modelGetNbVertices( &scene, &envelopes[i], &modelNumVert );
-
-              SAA_DVector *modelVertices = nullptr;
-              modelVertices = new SAA_DVector[modelNumVert];
-
-              // get the model vertices
-              SAA_modelGetVertices( &scene, &envelopes[i],
-                                    SAA_GEOM_ORIGINAL, 0, modelNumVert,
-                                    modelVertices );
-
-              // create array of global model coords
-              SAA_DVector *globalModelVertices = nullptr;
-              globalModelVertices = new SAA_DVector[modelNumVert];
-              PN_stdfloat matrix[4][4];
-
-              // tranform local model vert coords to global
-
-              // first get the global matrix
-              SAA_modelGetMatrix( &scene, &envelopes[i], SAA_COORDSYS_GLOBAL,  matrix );
-
-              // populate array of global model verts
-              for ( j = 0; j < modelNumVert; j++ ) {
-                _VCT_X_MAT( globalModelVertices[j],
-                            modelVertices[j], matrix );
-              }
-
-              // Get the vpool
-              string s_name = envName;
-              SoftNodeDesc *mesh_node = find_node(s_name);
-              if (!mesh_node) {
-                softegg_cat.debug() << "error: node " << s_name << " not found in tree\n";
-                exit(1);
-              }
-              string vpool_name = s_name + ".verts";
-              EggNode *t = _tree.get_egg_root()->find_child(vpool_name);
-              if (t)
-                DCAST_INTO_R(vpool, t, nullptr);
-
-              // find the mapping of the vertices that match this envelop
-              if (vpool) {
-                softegg_cat.spam() << "found vpool of size " << vpool->size() << endl;
-                if ( !make_nurbs || (type == SAA_MSMSH) ) {
-                  vpoolMap = FindClosestTriVert( vpool, globalModelVertices, modelNumVert );
-                }
-              }
-              else {
-                softegg_cat.debug() << "warning: vpool " << vpool_name << " not found\n";
-                continue; // could be because of not visible
-              }
-
-              joint = node_desc->get_egg_group();
-              // for every envelope vertex
-              for (j = 0; j < numEnvVertices[i]; j++) {
-                double scaledWeight =  weights[j]/ 100.0f;
-
-                // make sure its in legal range
-                if (( envVtxIndices[j] < modelNumVert )
-                    && ( envVtxIndices[j] >= 0 )) {
-                  if ( (type == SAA_MNSRF) && make_nurbs ) {
-                    // assign all referenced control vertices
-                    EggVertex *vert = vpool->get_vertex(envVtxIndices[j]);
-                    if (!vert) {
-                      softegg_cat.debug() << "possible error: index " << envVtxIndices[j] << ": vert is " << vert << endl;
-                      continue;
-                    }
-                    joint->ref_vertex( vert, scaledWeight );
-                    softegg_cat.spam() << j << ": adding vref to cv " << envVtxIndices[j]
-                         << " with weight " << scaledWeight << endl;
-
-                    /*
-                    envPool->Vertex(envVtxIndices[j])->AddJoint( joint, scaledWeight );
-                    // set flag to show this vertex has been assigned
-                    envPool->Vertex(envVtxIndices[j])->multipleJoints = 1;
-                    */
-                  }
-                  else {
-                    // assign all the tri verts associated with this control
-                    // vertex to joint
-                    softegg_cat.spam() << j << "--trying to find " << envVtxIndices[j] << endl;
-                    for ( k = 0; k < (int)vpool->size(); k++ ) {
-                      if ( vpoolMap[k] == envVtxIndices[j] ) {
-                        EggVertex *vert = vpool->get_vertex(k+1);
-                        // EggVertex *vert =
-                        // mesh_node->get_vpool()->get_vertex(vpoolMap[k]+1);
-                        if (!vert) {
-                          softegg_cat.debug() << "possible error: index " << k+1 << ": vert is " << vert << endl;
-                          break;
-                        }
-
-                        joint->ref_vertex(vert, scaledWeight);
-                        softegg_cat.spam() << j << ": adding vref from cv " << envVtxIndices[j]
-                             << " to vert " << k+1 << " with weight " << scaledWeight
-                             << "(vpool)\n";
-                        /*
-                          envPool->Vertex(k)->AddJoint( joint, scaledWeight );
-                          // set flag to show this vertex has been assigned
-                          envPool->Vertex(k)->multipleJoints = 1;
-                        */
-                      }
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-  return true;
-}
-/**
- * Given a model, make sure all its vertices have been soft assigned.  If not
- * hard assign to the last joint we saw.
- */
-bool SoftToEggConverter::
-cleanup_soft_skin()
-{
-  int num_nodes = _tree.get_num_nodes();
-  SoftNodeDesc *node_desc;
-
-  softegg_cat.spam() << endl << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << endl;
-
-  for (int i = 0; i < num_nodes; i++) {
-    node_desc = _tree.get_node(i);
-    if (node_desc->is_partial(search_prefix))
-      continue;
-
-    SAA_Elem *model = node_desc->get_model();
-    EggGroup *joint = nullptr;
-    EggVertexPool *vpool = nullptr;
-    SAA_ModelType type;
-
-    // find out what type of node we're dealing with
-
-    SAA_modelGetType( &scene, model, &type );
-
-    softegg_cat.debug() << "Cleaning up model------- " << node_desc->get_name() << endl;
-
-    // this step is weird - I think I want it here but it seems to break some
-    // models.  Files like props-props_wh_cookietime.3-0 in
-    // fulrndpubvrmlchipchips_adventurecharzone1roomswarehouse_final need to
-    // do the "if (skel)" bit.
-
-    // find the vpool for this model
-    string vpool_name = node_desc->get_name() + ".verts";
-    EggNode *t = _tree.get_egg_root()->find_child(vpool_name);
-    if (t)
-      DCAST_INTO_R(vpool, t, nullptr);
-
-    if (!vpool) {
-      // softegg_cat.spam() << "couldn't find vpool " << vpool_name << endl;
-      continue;
-    }
-
-    int numVerts = (int)vpool->size();
-    softegg_cat.spam() << "found vpool " << vpool_name << " w/ " << numVerts << " verts\n";
-
-    // if this node is a joint, then these vertices belong to this joint
-    if (node_desc->is_joint())
-      joint = node_desc->get_egg_group();
-    else {
-      // find the closest _parentJoint
-      SoftNodeDesc *parentJ = node_desc;
-      while( parentJ && !parentJ->_parentJoint) {
-        if ( parentJ->_parent) {
-          SAA_Boolean isSkeleton;
-          // softegg_cat.spam() << " checking parent " <<
-          // parentJ->_parent->get_name() << endl;
-          if (parentJ->_parent->has_model())
-            SAA_modelIsSkeleton( &scene, parentJ->_parent->get_model(), &isSkeleton );
-
-          if (isSkeleton) {
-            joint = parentJ->_parent->get_egg_group();
-            softegg_cat.spam() << "parent to " << parentJ->_parent->get_name() << endl;
-            break;
-          }
-
-          parentJ = parentJ->_parent;
-        }
-        else
-          break;
-      }
-      if (!joint && (!parentJ || !parentJ->_parentJoint)) {
-        softegg_cat.spam() << node_desc->get_name() << " has no _parentJoint?!" << endl;
-        continue;
-      }
-
-      if (!joint) {
-        softegg_cat.spam() << "parent joint to " << parentJ->_parentJoint->get_name() << endl;
-        joint = parentJ->_parentJoint->get_egg_group();
-      }
-    }
-    EggVertexPool::iterator vi;
-    double membership = 1.0f;
-    for ( vi = vpool->begin(); vi != vpool->end(); ++vi) {
-      EggVertex *vert = (*vi);
-
-      // if this vertex has not been soft assigned, then hard assign it to the
-      // parentJoint
-      if ( vert->gref_size() == 0 ) {
-
-        softegg_cat.spam() << "vert " << vert->get_external_index() << " not assigned!\n";
-
-        // hard skin this vertex
-        joint->ref_vertex( vert, 1.0f );
-      }
-    }
-  }
-  return true;
-}
-
-/**
- * Applies the known shader attributes to the indicated egg primitive.
- */
-void SoftToEggConverter::
-set_shader_attributes(SoftNodeDesc *node_desc, EggPrimitive &primitive, int idx) {
-  char *texName = node_desc->texNameArray[idx];
-  EggTexture tex(texName, "");
-
-  Filename filename = Filename::from_os_specific(texName);
-  Filename fullpath = _path_replace->match_path(filename, get_model_path());
-  tex.set_filename(_path_replace->store_path(fullpath));
-  tex.set_fullpath(fullpath);
-  // tex.set_format(EggTexture::F_rgb);
-  apply_texture_properties(tex, node_desc->uRepeat[idx], node_desc->vRepeat[idx]);
-
-  EggTexture *new_tex = _textures.create_unique_texture(tex, ~EggTexture::E_tref_name);
-  primitive.set_texture(new_tex);
-}
-
-/**
- * Applies all the appropriate texture properties to the EggTexture object,
- * including wrap modes and texture matrix.
- */
-void SoftToEggConverter::
-apply_texture_properties(EggTexture &tex, int uRepeat, int vRepeat) {
-  // Let's mipmap all textures by default.
-  tex.set_minfilter(EggTexture::FT_linear_mipmap_linear);
-  tex.set_magfilter(EggTexture::FT_linear);
-
-  EggTexture::WrapMode wrap_u = uRepeat > 0 ? EggTexture::WM_repeat : EggTexture::WM_clamp;
-  EggTexture::WrapMode wrap_v = vRepeat > 0 ? EggTexture::WM_repeat : EggTexture::WM_clamp;
-
-  tex.set_wrap_u(wrap_u);
-  tex.set_wrap_v(wrap_v);
-  /*
-  LMatrix3d mat = color_def.compute_texture_matrix();
-  if (!mat.almost_equal(LMatrix3d::ident_mat())) {
-    tex.set_transform(mat);
-  }
-  */
-}
-#if 0
-/**
- * Compares the texture properties already on the texture (presumably set by a
- * previous call to apply_texture_properties()) and returns false if they
- * differ from that specified by the indicated color_def object, or true if
- * they match.
- */
-bool SoftToEggConverter::
-compare_texture_properties(EggTexture &tex,
-                           const SoftShaderColorDef &color_def) {
-  bool okflag = true;
-
-  EggTexture::WrapMode wrap_u = color_def._wrap_u ? EggTexture::WM_repeat : EggTexture::WM_clamp;
-  EggTexture::WrapMode wrap_v = color_def._wrap_v ? EggTexture::WM_repeat : EggTexture::WM_clamp;
-
-  if (wrap_u != tex.determine_wrap_u()) {
-    // Choose the more general of the two.
-    if (wrap_u == EggTexture::WM_repeat) {
-      tex.set_wrap_u(wrap_u);
-    }
-    okflag = false;
-  }
-  if (wrap_v != tex.determine_wrap_v()) {
-    if (wrap_v == EggTexture::WM_repeat) {
-      tex.set_wrap_v(wrap_v);
-    }
-    okflag = false;
-  }
-
-  LMatrix3d mat = color_def.compute_texture_matrix();
-  if (!mat.almost_equal(tex.get_transform())) {
-    okflag = false;
-  }
-
-  return okflag;
-}
-#endif
-/**
- * Recursively walks the egg hierarchy, reparenting "decal" type nodes below
- * their corresponding "decalbase" type nodes, and setting the flags.
- *
- * Returns true on success, false if some nodes were incorrect.
- */
-bool SoftToEggConverter::
-reparent_decals(EggGroupNode *egg_parent) {
-  bool okflag = true;
-
-  // First, walk through all children of this node, looking for the one decal
-  // base, if any.
-  EggGroup *decal_base = nullptr;
-  pvector<EggGroup *> decal_children;
-
-  EggGroupNode::iterator ci;
-  for (ci = egg_parent->begin(); ci != egg_parent->end(); ++ci) {
-    EggNode *child =  (*ci);
-    if (child->is_of_type(EggGroup::get_class_type())) {
-      EggGroup *child_group = DCAST(EggGroup, child);
-      if (child_group->has_object_type("decalbase")) {
-        if (decal_base != nullptr) {
-          softegg_cat.error()
-            << "Two children of " << egg_parent->get_name()
-            << " both have decalbase set: " << decal_base->get_name()
-            << " and " << child_group->get_name() << "\n";
-          okflag = false;
-        }
-        child_group->remove_object_type("decalbase");
-        decal_base = child_group;
-
-      } else if (child_group->has_object_type("decal")) {
-        child_group->remove_object_type("decal");
-        decal_children.push_back(child_group);
-      }
-    }
-  }
-
-  if (decal_base == nullptr) {
-    if (!decal_children.empty()) {
-      softegg_cat.warning()
-        << decal_children.front()->get_name()
-        << " has decal, but no sibling node has decalbase.\n";
-    }
-
-  } else {
-    if (decal_children.empty()) {
-      softegg_cat.warning()
-        << decal_base->get_name()
-        << " has decalbase, but no sibling nodes have decal.\n";
-
-    } else {
-      // All the decal children get moved to be a child of decal base.  This
-      // usually will not affect the vertex positions, but it could if the
-      // decal base has a transform and the decal child is an instance node.
-      // So don't do that.
-      pvector<EggGroup *>::iterator di;
-      for (di = decal_children.begin(); di != decal_children.end(); ++di) {
-        EggGroup *child_group = (*di);
-        decal_base->add_child(child_group);
-      }
-
-      // Also set the decal state on the base.
-      decal_base->set_decal_flag(true);
-    }
-  }
-
-  // Now recurse on each of the child nodes.
-  for (ci = egg_parent->begin(); ci != egg_parent->end(); ++ci) {
-    EggNode *child =  (*ci);
-    if (child->is_of_type(EggGroupNode::get_class_type())) {
-      EggGroupNode *child_group = DCAST(EggGroupNode, child);
-      if (!reparent_decals(child_group)) {
-        okflag = false;
-      }
-    }
-  }
-
-  return okflag;
-}
-
-/**
- * Returns the TransformType value corresponding to the indicated string, or
- * TT_invalid.
- */
-SoftToEggConverter::TransformType SoftToEggConverter::
-string_transform_type(const string &arg) {
-  if (cmp_nocase(arg, "all") == 0) {
-    return TT_all;
-  } else if (cmp_nocase(arg, "model") == 0) {
-    return TT_model;
-  } else if (cmp_nocase(arg, "dcs") == 0) {
-    return TT_dcs;
-  } else if (cmp_nocase(arg, "none") == 0) {
-    return TT_none;
-  } else {
-    return TT_invalid;
-  }
-}
-
-/**
- * Invokes the softToEggConverter class
- */
-extern "C" int init_soft2egg(int argc, char **argv) {
-  stec._commandName = argv[0];
-  stec.rsrc_path = "c:\\Softimage\\SOFT3D_3.9.2\\3D\\rsrc";
-
-  if (stec.DoGetopts(argc, argv)) {
-    // Create a Filename object and convert the file
-    Filename softFile(argv[1]);
-    stec.convert_file(softFile);
-  }
-
-  return 0;
-}

+ 0 - 179
pandatool/src/softegg/softToEggConverter.h

@@ -1,179 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file softToEggConverter.h
- * @author masad
- * @date 2003-09-25
- */
-
-#ifndef SOFTTOEGGCONVERTER_H
-#define SOFTTOEGGCONVERTER_H
-
-#include "pandatoolbase.h"
-#include "somethingToEggConverter.h"
-#include "softNodeTree.h"
-
-#include "eggTextureCollection.h"
-#include "distanceUnit.h"
-#include "coordinateSystem.h"
-
-#ifdef _MIN
-#undef _MIN
-#endif
-#ifdef _MAX
-#undef _MAX
-#endif
-
-#include <SAA.h>
-#include <SI_macros.h>
-
-class EggData;
-class EggGroup;
-class EggTable;
-class EggVertexPool;
-class EggNurbsCurve;
-class EggPrimitive;
-class EggXfmSAnim;
-class EggSAnimData;
-
-
-/**
- * This class supervises the construction of an EggData structure from a
- * single Softimage file, or from the data already in th    cout << "egg name
- * = " << eggFilename << endl;e global Softimage model space.
- *
- */
-class SoftToEggConverter : public SomethingToEggConverter {
-public:
-  SoftToEggConverter(const std::string &program_name = "");
-  SoftToEggConverter(const SoftToEggConverter &copy);
-  virtual ~SoftToEggConverter();
-
-  void Help();
-  void Usage();
-  void ShowOpts();
-
-  bool HandleGetopts(int &idx, int argc, char **argv);
-  bool DoGetopts(int &argc, char **&argv);
-
-  SoftNodeDesc *find_node(std::string name);
-  int *FindClosestTriVert( EggVertexPool *vpool, SAA_DVector *vertices, int numVert );
-
-  virtual SomethingToEggConverter *make_copy();
-  virtual std::string get_name() const;
-  virtual std::string get_extension() const;
-
-  virtual bool convert_file(const Filename &filename);
-  bool convert_soft(bool from_selection);
-  bool open_api();
-  void close_api();
-
-private:
-  bool convert_flip(double start_frame, double end_frame,
-                    double frame_inc, double output_frame_rate);
-
-  bool make_soft_skin();
-  bool cleanup_soft_skin();
-  bool convert_char_chan();
-  bool convert_char_model();
-  bool convert_hierarchy(EggGroupNode *egg_root);
-  bool process_model_node(SoftNodeDesc *node_desc);
-
-  void make_polyset(SoftNodeDesc *node_desc, EggGroup *egg_group, SAA_ModelType type);
-  void make_nurb_surface(SoftNodeDesc *node_desc, EggGroup *egg_group, SAA_ModelType type);
-  void add_knots( vector <double> &eggKnots, double *knots, int numKnots, SAA_Boolean closed, int degree );
-
-  void set_shader_attributes(SoftNodeDesc *node_desc, EggPrimitive &primitive, int idx);
-  void apply_texture_properties(EggTexture &tex, int uRepeat, int vRepeat);
-
-  bool reparent_decals(EggGroupNode *egg_parent);
-
-  std::string _program_name;
-  bool _from_selection;
-
-  SI_Error            result;
-  SAA_Elem            model;
-  SAA_Database        database;
-
-public:
-
-  SoftNodeTree _tree;
-
-  SAA_Scene           scene;
-
-  char *_getopts;
-
-  // This is argv[0].
-  const char *_commandName;
-
-  // This is the entire command line.
-  char _commandLine[4096];
-
-  char        *rsrc_path;
-  char        *database_name;
-  char        *scene_name;
-  char        *model_name;
-  char        *eggFileName;
-  char        *animFileName;
-  char        *eggGroupName;
-  char        *tex_path;
-  char        *tex_filename;
-  char        *search_prefix;
-
-  int                    nurbs_step;
-  int                    anim_start;
-  int                    anim_end;
-  int                    anim_rate;
-  int                    pose_frame;
-  int                    verbose;
-  int                    flatten;
-  int                    shift_textures;
-  int                    ignore_tex_offsets;
-  int                    use_prefix;
-
-  bool                foundRoot;
-  bool                geom_as_joint;
-  bool                make_anim;
-  bool                make_nurbs;
-  bool                make_poly;
-  bool                make_soft;
-  bool                make_morph;
-  bool                make_duv;
-  bool                make_dart;
-  bool                has_morph;
-  bool                make_pose;
-
-
-  char *GetTextureName( SAA_Scene *scene, SAA_Elem *texture );
-
-  EggTextureCollection _textures;
-
-  bool _polygon_output;
-  double _polygon_tolerance;
-
-  enum TransformType {
-    TT_invalid,
-    TT_all,
-    TT_model,
-    TT_dcs,
-    TT_none,
-  };
-  TransformType _transform_type;
-
-  static TransformType string_transform_type(const std::string &arg);
-
-  typedef pvector<EggSAnimData *> MorphTable;
-  MorphTable _morph_table;
-
-  EggTable *morph_node;
-  EggSAnimData *find_morph_table(char *name);
-};
-
-extern const int TEX_PER_MAT;
-
-#endif

+ 0 - 588
pandatool/src/softprogs/softCVS.cxx

@@ -1,588 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file softCVS.cxx
- * @author drose
- * @date 2000-11-10
- */
-
-#include "softCVS.h"
-
-#include "pnotify.h"
-#include "multifile.h"
-
-#include <algorithm>
-
-using std::string;
-
-/**
- *
- */
-SoftCVS::
-SoftCVS() {
-  _cvs_binary = "cvs";
-
-  set_program_brief("prepare a SoftImage database directory for adding to CVS");
-  set_program_description
-    ("softcvs is designed to prepare a directory hierarchy "
-     "representing a SoftImage database for adding to CVS.  "
-     "First, it eliminates SoftImage's silly filename-based "
-     "versioning system by renaming versioned filenames higher "
-     "than 1-0 back to version 1-0.  Then, it rolls up all the "
-     "files for each scene except the texture images into a Panda "
-     "multifile, which is added to CVS; the texture images are "
-     "directly added to CVS where they are.\n\n"
-
-     "The reduction of hundreds of SoftImage files per scene down to one "
-     "multifile and a handle of texture images should greatly improve "
-     "the update and commit times of CVS.\n\n"
-
-     "You must run this from within the root of a SoftImage database "
-     "directory; e.g. the directory that contains SCENES, PICTURES, MODELS, "
-     "and so on.");
-
-  clear_runlines();
-  add_runline("[opts]");
-
-  add_option
-    ("nc", "", 80,
-     "Do not attempt to add newly-created files to CVS.  The default "
-     "is to add them.",
-     &SoftCVS::dispatch_none, &_no_cvs);
-
-  add_option
-    ("cvs", "cvs_binary", 80,
-     "Specify how to run the cvs program for adding newly-created files.  "
-     "The default is simply \"cvs\".",
-     &SoftCVS::dispatch_string, nullptr, &_cvs_binary);
-}
-
-
-/**
- *
- */
-void SoftCVS::
-run() {
-  // First, check for the scenes directory.  If it doesn't exist, we must not
-  // be in the root of a soft database.
-  Filename scenes = "SCENES/.";
-  if (!scenes.exists()) {
-    nout << "No SCENES directory found; you are not in the root of a "
-      "SoftImage database.\n";
-    exit(1);
-  }
-
-  // Also, if we're expecting to use CVS, make sure the CVS directory exists.
-  Filename cvs_entries = "CVS/Entries";
-  if (!_no_cvs && !cvs_entries.exists()) {
-    nout << "You do not appear to be within a CVS-controlled source "
-      "directory.\n";
-    exit(1);
-  }
-
-  // Scan all the files in the database.
-  traverse_root();
-
-  // Collapse out the higher-versioned scene files.
-  collapse_scene_files();
-
-  // Now determine which element files are actually referenced by at least one
-  // of the scene files.
-  if (!get_scenes()) {
-    exit(1);
-  }
-
-  // Finally, remove all the element files that are no longer referenced by
-  // any scenes.
-  remove_unused_elements();
-
-  // Now do all the cvs adding and removing we need.
-  if (!_no_cvs) {
-    cvs_add_or_remove("remove", _cvs_remove);
-    cvs_add_or_remove("add -kb", _cvs_add);
-  }
-}
-
-/**
- * Reads all of the toplevel directory names, e.g.  SCENES, MATERIALS, etc.,
- * and traverses them.
- */
-void SoftCVS::
-traverse_root() {
-  Filename root(".");
-
-  // Get the list of subdirectories.
-  vector_string subdirs;
-  if (!root.scan_directory(subdirs)) {
-    nout << "Unable to scan directory.\n";
-    return;
-  }
-
-  vector_string::const_iterator di;
-  for (di = subdirs.begin(); di != subdirs.end(); ++di) {
-    Filename subdir = (*di);
-    if (subdir.is_directory() && subdir != "CVS") {
-      traverse_subdir(subdir);
-    }
-  }
-}
-
-/**
- * Reads the directory indicated by prefix and identifies all of the SoftImage
- * files stored there.
- */
-void SoftCVS::
-traverse_subdir(const Filename &directory) {
-  // Get the list of files in the directory.
-  vector_string files;
-  if (!directory.scan_directory(files)) {
-    nout << "Unable to scan directory " << directory << "\n";
-    return;
-  }
-
-  // We need to know the set of files in this directory that are CVS elements.
-  pset<string> cvs_elements;
-  bool in_cvs = false;
-  if (!_no_cvs) {
-    in_cvs = scan_cvs(directory, cvs_elements);
-  }
-
-  bool is_scenes = false;
-  bool keep_all = false;
-  bool wants_cvs = false;
-
-  // Now make some special-case behavior based on the particular SoftImage
-  // subdirectory we're in.
-  string dirname = directory.get_basename();
-  if (dirname == "SCENES") {
-    is_scenes = true;
-
-  } else if (dirname == "CAMERAS") {
-    // We don't want anything in the cameras directory.  These may change
-    // arbitrarily and have no bearing on the model or animation that we will
-    // extract, so avoid them altogether.
-    return;
-
-  } else if (dirname == "PICTURES") {
-    // In the pictures directory, we must keep everything, since the scene
-    // files don't explicitly reference these but they're still important.
-    // Textures that are no longer used will pile up; we leave this as the
-    // user's problem.
-
-    // We not only keep the textures, but we also move them into CVS, since
-    // (again) they're not part of the scene files and thus won't get added to
-    // the multifiles.  Also, some textures are shared between different
-    // scenes, and it would be wasteful to add them to each scene multifile;
-    // furthermore, some scenes are used for animation only, and we don't want
-    // to modify these multifiles when the textures change.
-
-    keep_all = true;
-    wants_cvs = !_no_cvs;
-  }
-
-  vector_string::const_iterator fi;
-  for (fi = files.begin(); fi != files.end(); ++fi) {
-    const string &filename = (*fi);
-    if (filename == "CVS") {
-      // This special filename is not to be considered.
-
-    } else if (filename == "Chapter.rsrc") {
-      // This special filename should not be considered, except to add it to
-      // the multifiles.
-      _global_files.push_back(Filename(directory, filename));
-
-    } else {
-      SoftFilename soft(directory, filename);
-
-      if (cvs_elements.count(filename) != 0) {
-        // This file is known to be in CVS.
-        soft.set_in_cvs(true);
-      }
-
-      if (keep_all) {
-        soft.increment_use_count();
-      }
-      if (wants_cvs && !in_cvs) {
-        // Try to CVSify the directory.
-        cvs_add(directory);
-        in_cvs = true;
-      }
-      soft.set_wants_cvs(wants_cvs);
-
-      if (is_scenes && soft.has_version() && soft.get_extension() == ".dsc") {
-        _scene_files.push_back(soft);
-      } else {
-        _element_files.insert(soft);
-      }
-    }
-  }
-}
-
-/**
- * Walks through the list of scene files found, and renames the higher-
- * versioned ones to version 1-0, removing the intervening versions.
- */
-void SoftCVS::
-collapse_scene_files() {
-  // Get a copy of the scene files vector so we can modify it.  Also empty out
-  // the _scene_files at the same time so we can fill it up again.
-  SceneFiles versions;
-  versions.swap(_scene_files);
-
-  // And sort them into order so we can easily compare higher and lower
-  // versions.
-  sort(versions.begin(), versions.end());
-
-  SceneFiles::iterator vi;
-  vi = versions.begin();
-  while (vi != versions.end()) {
-    SoftFilename &file = (*vi);
-
-    if (!file.is_1_0()) {
-      // Here's a file that needs to be renamed.  But first, identify all the
-      // other versions of the same file.
-      SceneFiles::iterator start_vi;
-      start_vi = vi;
-      while (vi != versions.end() && (*vi).is_same_file(file)) {
-        ++vi;
-      }
-
-      rename_file(start_vi, vi);
-
-    } else {
-      ++vi;
-    }
-
-    file.make_1_0();
-    _scene_files.push_back(file);
-  }
-}
-
-/**
- * Walks through the list of scene files and looks for the set of element
- * files referenced by each one, updating multifile accordingly.
- */
-bool SoftCVS::
-get_scenes() {
-  bool okflag = true;
-
-  // We will be added the multifiles to CVS if they're not already added, so
-  // we have to know which files are in CVS already.
-  pset<string> cvs_elements;
-  if (!_no_cvs) {
-    scan_cvs(".", cvs_elements);
-  }
-
-  SceneFiles::const_iterator vi;
-  for (vi = _scene_files.begin(); vi != _scene_files.end(); ++vi) {
-    const SoftFilename &sf = (*vi);
-    Filename file(sf.get_dirname(), sf.get_filename());
-
-    file.set_text();
-    std::ifstream in;
-    if (!file.open_read(in)) {
-      nout << "Unable to read " << file << "\n";
-    } else {
-      nout << "Scanning " << file << "\n";
-
-      Multifile multifile;
-      Filename multifile_name = sf.get_base() + "mf";
-
-      if (!multifile.open_read_write(multifile_name)) {
-        nout << "Unable to open " << multifile_name << " for updating.\n";
-        okflag = false;
-
-      } else {
-        if (!scan_scene_file(in, multifile)) {
-          okflag = false;
-        }
-
-        // Add all the global files to the multifile too.  These probably
-        // can't take compression (since in SoftImage they're just the
-        // Chapter.rsrc files, each very tiny).
-        vector_string::const_iterator gi;
-        for (gi = _global_files.begin(); gi != _global_files.end(); ++gi) {
-          if (multifile.update_subfile((*gi), (*gi), 0).empty()) {
-            nout << "Unable to add " << (*gi) << "\n";
-            okflag = false;
-          }
-        }
-
-        // Also add the scene file itself.
-        if (multifile.update_subfile(file, file, 6).empty()) {
-          nout << "Unable to add " << file << "\n";
-          okflag = false;
-        }
-
-        bool flushed = false;
-        if (multifile.needs_repack()) {
-          flushed = multifile.repack();
-        } else {
-          flushed = multifile.flush();
-        }
-        if (!flushed) {
-          nout << "Failed to write " << multifile_name << ".\n";
-          okflag = false;
-        } else {
-          nout << "Wrote " << multifile_name << ".\n";
-
-          if (!_no_cvs && cvs_elements.count(multifile_name) == 0) {
-            // Add the multifile to CVS.
-            _cvs_add.push_back(multifile_name);
-          }
-        }
-      }
-    }
-  }
-
-  return okflag;
-}
-
-
-/**
- * Remove all the element files that weren't referenced by any scene file.
- * Also plan to cvs add all those that were referenced.
- */
-void SoftCVS::
-remove_unused_elements() {
-  ElementFiles::const_iterator fi;
-  for (fi = _element_files.begin(); fi != _element_files.end(); ++fi) {
-    const SoftFilename &sf = (*fi);
-    Filename file(sf.get_dirname(), sf.get_filename());
-
-    if (sf.get_use_count() == 0) {
-      nout << file << " is unused.\n";
-
-      if (!file.unlink()) {
-        nout << "Unable to remove " << file << ".\n";
-
-      } else if (sf.get_in_cvs()) {
-        _cvs_remove.push_back(file);
-      }
-
-    } else if (sf.get_wants_cvs() && !sf.get_in_cvs()) {
-      _cvs_add.push_back(file);
-    }
-  }
-}
-
-
-/**
- * Renames the first file in the indicated list to a version 1-0 filename,
- * superceding all the other files in the list.  Returns true if the file is
- * renamed, false otherwise.
- */
-bool SoftCVS::
-rename_file(SoftCVS::SceneFiles::iterator begin,
-            SoftCVS::SceneFiles::iterator end) {
-  int length = end - begin;
-  nassertr(length > 0, false);
-
-  SoftFilename &orig = (*begin);
-
-  string dirname = orig.get_dirname();
-  string source_filename = orig.get_filename();
-  string dest_filename = orig.get_1_0_filename();
-
-  if (length > 2) {
-    nout << source_filename << " supercedes:\n";
-    SceneFiles::const_iterator p;
-    for (p = begin + 1; p != end; ++p) {
-      nout << "  " << (*p).get_filename() << "\n";
-    }
-
-  } else if (length == 2) {
-    nout << source_filename << " supercedes "
-         << (*(begin + 1)).get_filename() << ".\n";
-
-  } else {
-    nout << source_filename << " renamed.\n";
-  }
-
-  // Now remove all of the "wrong" files.
-
-  SceneFiles::const_iterator p;
-  for (p = begin + 1; p != end; ++p) {
-    Filename file((*p).get_dirname(), (*p).get_filename());
-    if (!file.unlink()) {
-      nout << "Unable to remove " << file << ".\n";
-    }
-  }
-
-  // And rename the good one.
-  Filename source(dirname, source_filename);
-  Filename dest(dirname, dest_filename);
-
-  if (!source.rename_to(dest)) {
-    nout << "Unable to rename " << source << " to " << dest_filename << ".\n";
-    exit(1);
-  }
-
-  return true;
-}
-
-/**
- * Scans the CVS repository in the indicated directory to determine which
- * files are already versioned elements.  Returns true if the directory is
- * CVS-controlled, false otherwise.
- */
-bool SoftCVS::
-scan_cvs(const string &dirname, pset<string> &cvs_elements) {
-  Filename cvs_entries = dirname + "/CVS/Entries";
-  if (!cvs_entries.exists()) {
-    return false;
-  }
-
-  std::ifstream in;
-  cvs_entries.set_text();
-  if (!cvs_entries.open_read(in)) {
-    nout << "Unable to read CVS directory.\n";
-    return true;
-  }
-
-  string line;
-  std::getline(in, line);
-  while (!in.fail() && !in.eof()) {
-    if (!line.empty() && line[0] == '/') {
-      size_t slash = line.find('/', 1);
-      if (slash != string::npos) {
-        string filename = line.substr(1, slash - 1);
-
-        if (line.substr(slash + 1, 2) == "-1") {
-          // If the first number after the slash is -1, the file used to be
-          // here but was recently cvs removed.  It counts as no longer being
-          // an element.
-        } else {
-          cvs_elements.insert(filename);
-        }
-      }
-    }
-
-    std::getline(in, line);
-  }
-
-  return true;
-}
-
-/**
- * Reads a scene file, looking for references to element files.  For each
- * reference found, increments the appropriate element file's reference count.
- */
-bool SoftCVS::
-scan_scene_file(std::istream &in, Multifile &multifile) {
-  bool okflag = true;
-
-  int c = in.get();
-  while (!in.eof() && !in.fail()) {
-    // Skip whitespace.
-    while (isspace(c) && !in.eof() && !in.fail()) {
-      c = in.get();
-    }
-
-    // Now begin a word.
-    string word;
-    while (!isspace(c) && !in.eof() && !in.fail()) {
-      word += c;
-      c = in.get();
-    }
-
-    if (!word.empty()) {
-      SoftFilename v("", word);
-
-      // Increment the use count on all matching elements of the multiset.
-      std::pair<ElementFiles::iterator, ElementFiles::iterator> range;
-      range = _element_files.equal_range(v);
-
-      ElementFiles::iterator ei;
-      for (ei = range.first; ei != range.second; ++ei) {
-        // We cheat and get a non-const reference to the filename out of the
-        // set.  We can safely do this because incrementing the use count
-        // won't change its position in the set.
-        SoftFilename &sf = (SoftFilename &)(*ei);
-        sf.increment_use_count();
-
-        Filename file(sf.get_dirname(), sf.get_filename());
-        if (multifile.update_subfile(file, file, 6).empty()) {
-          nout << "Unable to add " << file << "\n";
-          okflag = false;
-        }
-      }
-    }
-  }
-
-  return okflag;
-}
-
-/**
- * Invokes CVS to add just the named file to the repository.  Returns true on
- * success, false on failure.
- */
-bool SoftCVS::
-cvs_add(const string &path) {
-  string command = _cvs_binary + " add -kb " + path;
-  nout << command << "\n";
-  int result = system(command.c_str());
-
-  if (result != 0) {
-    nout << "Failure invoking cvs.\n";
-    return false;
-  }
-  return true;
-}
-
-/**
- * Invokes CVS to add (or remove) all of the files in the indicated vector.
- * Returns true on success, false on failure.
- */
-bool SoftCVS::
-cvs_add_or_remove(const string &cvs_command, const vector_string &paths) {
-  static const int max_command = 4096;
-
-  if (!paths.empty()) {
-    string command = _cvs_binary + " " + cvs_command;
-    vector_string::const_iterator pi;
-    pi = paths.begin();
-    while (pi != paths.end()) {
-      const string &path = (*pi);
-
-      if ((int)command.length() + 1 + (int)path.length() >= max_command) {
-        // Fire off the command now.
-        nout << command << "\n";
-        int result = system(command.c_str());
-
-        if (result != 0) {
-          nout << "Failure invoking cvs.\n";
-          return false;
-        }
-
-        command = _cvs_binary + " " + cvs_command;
-      }
-
-      command += ' ';
-      command += path;
-
-      ++pi;
-    }
-    nout << command << "\n";
-    int result = system(command.c_str());
-
-    if (result != 0) {
-      nout << "Failure invoking cvs.\n";
-      return false;
-    }
-  }
-  return true;
-}
-
-
-int main(int argc, char *argv[]) {
-  SoftCVS prog;
-  prog.parse_command_line(argc, argv);
-  prog.run();
-  return 0;
-}

+ 0 - 70
pandatool/src/softprogs/softCVS.h

@@ -1,70 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file softCVS.h
- * @author drose
- * @date 2000-11-10
- */
-
-#ifndef SOFTCVS_H
-#define SOFTCVS_H
-
-#include "pandatoolbase.h"
-
-#include "softFilename.h"
-
-#include "programBase.h"
-#include "vector_string.h"
-#include "filename.h"
-
-#include "pvector.h"
-#include "pset.h"
-
-class Multifile;
-
-/**
- * This program prepares a SoftImage database for CVS by renaming everything
- * to version 1-0, and adding new files to CVS.
- */
-class SoftCVS : public ProgramBase {
-public:
-  SoftCVS();
-
-  void run();
-
-private:
-  typedef pvector<SoftFilename> SceneFiles;
-  typedef pmultiset<SoftFilename> ElementFiles;
-
-  void traverse_root();
-  void traverse_subdir(const Filename &directory);
-
-  void collapse_scene_files();
-  bool get_scenes();
-  void remove_unused_elements();
-
-  bool rename_file(SceneFiles::iterator begin, SceneFiles::iterator end);
-  bool scan_cvs(const std::string &dirname, pset<std::string> &cvs_elements);
-  bool scan_scene_file(std::istream &in, Multifile &multifile);
-
-  bool cvs_add(const std::string &path);
-  bool cvs_add_or_remove(const std::string &cvs_command,
-                         const vector_string &paths);
-
-  SceneFiles _scene_files;
-  ElementFiles _element_files;
-  vector_string _global_files;
-
-  vector_string _cvs_add;
-  vector_string _cvs_remove;
-
-  bool _no_cvs;
-  std::string _cvs_binary;
-};
-
-#endif

+ 0 - 291
pandatool/src/softprogs/softFilename.cxx

@@ -1,291 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file softFilename.cxx
- * @author drose
- * @date 2000-11-10
- */
-
-#include "softFilename.h"
-
-#include "pnotify.h"
-
-using std::string;
-
-/**
- *
- */
-SoftFilename::
-SoftFilename(const string &dirname, const string &filename) :
-  _dirname(dirname),
-  _filename(filename)
-{
-  _has_version = false;
-  _major = 0;
-  _minor = 0;
-  _in_cvs = false;
-  _wants_cvs = false;
-  _use_count = 0;
-
-  _base = _filename;
-
-  // Scan for a version number and an optional extension after each dot in the
-  // filename.
-  size_t dot = _filename.find('.');
-  while (dot != string::npos) {
-    size_t m = dot + 1;
-    const char *fstr = _filename.c_str();
-    char *endptr;
-    // Check for a numeric version number.
-    int major = strtol(fstr + m , &endptr, 10);
-    if (endptr != fstr + m && *endptr == '-') {
-      // We got a major number, is there a minor number?
-      m = (endptr - fstr) + 1;
-      int minor = strtol(fstr + m, &endptr, 10);
-      if (endptr != fstr + m && (*endptr == '.' || *endptr == '\0')) {
-        // We got a minor number too!
-        _has_version = true;
-        _base = _filename.substr(0, dot + 1);
-        _major = major;
-        _minor = minor;
-        _ext = endptr;
-        return;
-      }
-    }
-
-    // That wasn't a version number.  Is there more?
-    dot = _filename.find('.', dot + 1);
-  }
-}
-
-/**
- *
- */
-SoftFilename::
-SoftFilename(const SoftFilename &copy) :
-  _dirname(copy._dirname),
-  _filename(copy._filename),
-  _has_version(copy._has_version),
-  _base(copy._base),
-  _major(copy._major),
-  _minor(copy._minor),
-  _ext(copy._ext),
-  _in_cvs(copy._in_cvs),
-  _wants_cvs(copy._wants_cvs),
-  _use_count(copy._use_count)
-{
-}
-
-/**
- *
- */
-void SoftFilename::
-operator = (const SoftFilename &copy) {
-  _dirname = copy._dirname;
-  _filename = copy._filename;
-  _has_version = copy._has_version;
-  _base = copy._base;
-  _major = copy._major;
-  _minor = copy._minor;
-  _ext = copy._ext;
-  _in_cvs = copy._in_cvs;
-  _wants_cvs = copy._wants_cvs;
-  _use_count = copy._use_count;
-}
-
-/**
- * Returns the name of the directory this file was found in.
- */
-const string &SoftFilename::
-get_dirname() const {
-  return _dirname;
-}
-
-/**
- * Returns the actual filename as found in the directory.
- */
-const string &SoftFilename::
-get_filename() const {
-  return _filename;
-}
-
-/**
- * Returns true if the filename had a version number, false otherwise.
- */
-bool SoftFilename::
-has_version() const {
-  return _has_version;
-}
-
-/**
- * Returns what the filename would be if it were version 1-0.
- */
-string SoftFilename::
-get_1_0_filename() const {
-  nassertr(_has_version, string());
-  return _base + "1-0" + _ext;
-}
-
-/**
- * Returns the base part of the filename.  This is everything before the
- * version number.
- */
-const string &SoftFilename::
-get_base() const {
-  nassertr(_has_version, _filename);
-  return _base;
-}
-
-/**
- * Returns the major version number.
- */
-int SoftFilename::
-get_major() const {
-  nassertr(_has_version, 0);
-  return _major;
-}
-
-/**
- * Returns the minor version number.
- */
-int SoftFilename::
-get_minor() const {
-  nassertr(_has_version, 0);
-  return _minor;
-}
-
-/**
- * Returns the extension part of the filename.  This is everything after the
- * version number.
- */
-const string &SoftFilename::
-get_extension() const {
-  nassertr(_has_version, _ext);
-  return _ext;
-}
-
-/**
- * Returns the filename part, without the extension.
- */
-string SoftFilename::
-get_non_extension() const {
-  nassertr(_has_version, _filename);
-  nassertr(_ext.length() < _filename.length(), _filename);
-  return _filename.substr(0, _filename.length() - _ext.length());
-}
-
-/**
- * Returns true if this is a version 1_0 filename, false otherwise.
- */
-bool SoftFilename::
-is_1_0() const {
-  nassertr(_has_version, false);
-  return (_major == 1 && _minor == 0);
-}
-
-/**
- * Makes this a 1_0 filename.
- */
-void SoftFilename::
-make_1_0() {
-  _has_version = true;
-  _major = 1;
-  _minor = 0;
-  _filename = get_1_0_filename();
-}
-
-/**
- * Returns true if this file has the same base and extension as the other,
- * disregarding the version number; false otherwise.
- */
-bool SoftFilename::
-is_same_file(const SoftFilename &other) const {
-  return _base == other._base && _ext == other._ext;
-}
-
-/**
- * Puts filenames in order such that the files with the same base are sorted
- * together, ignoring extension; and within files with the same base, files
- * are sorted in decreasing version number order so that the most recent
- * version appears first.
- */
-bool SoftFilename::
-operator < (const SoftFilename &other) const {
-  if (_base != other._base) {
-    return _base < other._base;
-  }
-
-  if (_has_version != other._has_version) {
-    // If one has a version and the other one doesn't, the one without a
-    // version comes first.
-    return _has_version < other._has_version;
-  }
-
-  if (_has_version) {
-    if (_major != other._major) {
-      return _major > other._major;
-    }
-    if (_minor != other._minor) {
-      return _minor > other._minor;
-    }
-  }
-
-  return false;
-}
-
-/**
- * Sets the flag that indicates whether this file is known to be entered into
- * the CVS database.
- */
-void SoftFilename::
-set_in_cvs(bool in_cvs) {
-  _in_cvs = in_cvs;
-}
-
-/**
- * Returns true if this file is known to be entered in the CVS database, false
- * if it is not.
- */
-bool SoftFilename::
-get_in_cvs() const {
-  return _in_cvs;
-}
-
-/**
- * Sets the flag that indicates whether this file should be entered into the
- * CVS database.
- */
-void SoftFilename::
-set_wants_cvs(bool wants_cvs) {
-  _wants_cvs = wants_cvs;
-}
-
-/**
- * Returns true if this file should be entered into the CVS database, false
- * otherwise.
- */
-bool SoftFilename::
-get_wants_cvs() const {
-  return _wants_cvs;
-}
-
-/**
- * Indicates that this filename is referenced by one more scene file.
- */
-void SoftFilename::
-increment_use_count() {
-  _use_count++;
-}
-
-/**
- * Returns the number of scene files that referenced this filename.
- */
-int SoftFilename::
-get_use_count() const {
-  return _use_count;
-}

+ 0 - 73
pandatool/src/softprogs/softFilename.h

@@ -1,73 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file softFilename.h
- * @author drose
- * @date 2000-11-10
- */
-
-#ifndef SOFTFILENAME_H
-#define SOFTFILENAME_H
-
-#include "pandatoolbase.h"
-
-/**
- * This encapsulates a SoftImage versioned filename, of the form base.v-v.ext:
- * it consists of a directory name, a base, a major and minor version number,
- * and an optional extension.
- *
- * It also keeps track of whether the named file has been added to CVS, and
- * how many scene files it is referenced by,
- */
-class SoftFilename {
-public:
-  SoftFilename(const std::string &dirname, const std::string &filename);
-  SoftFilename(const SoftFilename &copy);
-  void operator = (const SoftFilename &copy);
-
-  const std::string &get_dirname() const;
-  const std::string &get_filename() const;
-  bool has_version() const;
-
-  std::string get_1_0_filename() const;
-
-  const std::string &get_base() const;
-  int get_major() const;
-  int get_minor() const;
-  const std::string &get_extension() const;
-  std::string get_non_extension() const;
-
-  bool is_1_0() const;
-  void make_1_0();
-
-  bool is_same_file(const SoftFilename &other) const;
-  bool operator < (const SoftFilename &other) const;
-
-  void set_in_cvs(bool in_cvs);
-  bool get_in_cvs() const;
-
-  void set_wants_cvs(bool wants_cvs);
-  bool get_wants_cvs() const;
-
-  void increment_use_count();
-  int get_use_count() const;
-
-private:
-  std::string _dirname;
-  std::string _filename;
-  bool _has_version;
-  std::string _base;
-  int _major;
-  int _minor;
-  std::string _ext;
-  bool _in_cvs;
-  bool _wants_cvs;
-  int _use_count;
-};
-
-#endif

+ 1 - 0
pandatool/src/xfileegg/xFileMaterial.cxx

@@ -18,6 +18,7 @@
 #include "eggTexture.h"
 #include "eggPrimitive.h"
 #include "datagram.h"
+#include "config_xfile.h"
 
 #include <string.h>  // for strcmp, strdup
 

+ 2 - 0
pandatool/src/xfileegg/xFileMesh.cxx

@@ -12,6 +12,7 @@
  */
 
 #include "xFileMesh.h"
+#include "xFileToEggConverter.h"
 #include "xFileFace.h"
 #include "xFileVertex.h"
 #include "xFileNormal.h"
@@ -22,6 +23,7 @@
 #include "eggVertexPool.h"
 #include "eggVertex.h"
 #include "eggPolygon.h"
+#include "eggGroup.h"
 #include "eggGroupNode.h"
 
 using std::min;

+ 2 - 0
pandatool/src/xfileegg/xFileMesh.h

@@ -22,6 +22,8 @@
 #include "namable.h"
 #include "coordinateSystem.h"
 
+#include "luse.h"
+
 class XFileNode;
 class XFileDataNode;
 class XFileMesh;

+ 1 - 0
pandatool/src/xfileegg/xFileToEggConverter.cxx

@@ -19,6 +19,7 @@
 
 #include "eggData.h"
 #include "eggGroup.h"
+#include "eggTable.h"
 #include "eggXfmSAnim.h"
 #include "eggGroupUniquifier.h"
 #include "datagram.h"

+ 25 - 12
tests/display/test_glsl_shader.py

@@ -10,6 +10,7 @@ from _pytest.outcomes import Failed
 # The reset() function serves to prevent the _triggered variable from being
 # optimized out in the case that the assertions are being optimized out.
 GLSL_COMPUTE_TEMPLATE = """#version {version}
+{extensions}
 
 layout(local_size_x = 1, local_size_y = 1) in;
 
@@ -37,7 +38,7 @@ void main() {{
 """
 
 
-def run_glsl_test(gsg, body, preamble="", inputs={}, version=430):
+def run_glsl_test(gsg, body, preamble="", inputs={}, version=130, exts=set()):
     """ Runs a GLSL test on the given GSG.  The given body is executed in the
     main function and should call assert().  The preamble should contain all
     of the shader inputs. """
@@ -48,11 +49,20 @@ def run_glsl_test(gsg, body, preamble="", inputs={}, version=430):
     if not gsg.supports_buffer_texture:
         pytest.skip("buffer textures not supported")
 
+    exts = exts | {'GL_ARB_compute_shader', 'GL_ARB_shader_image_load_store'}
+    missing_exts = sorted(ext for ext in exts if not gsg.has_extension(ext))
+    if missing_exts:
+        pytest.skip("missing extensions: " + ' '.join(missing_exts))
+
+    extensions = ''
+    for ext in exts:
+        extensions += '#extension {ext} : require\n'.format(ext=ext)
+
     __tracebackhide__ = True
 
     preamble = preamble.strip()
     body = body.rstrip().lstrip('\n')
-    code = GLSL_COMPUTE_TEMPLATE.format(version=version, preamble=preamble, body=body)
+    code = GLSL_COMPUTE_TEMPLATE.format(version=version, extensions=extensions, preamble=preamble, body=body)
     line_offset = code[:code.find(body)].count('\n') + 1
     shader = core.Shader.make_compute(core.Shader.SL_GLSL, code)
     assert shader, code
@@ -122,7 +132,7 @@ def test_glsl_sampler(gsg):
     assert(texelFetch(tex1, 0, 0) == vec4(0, 2 / 255.0, 1, 1));
     assert(texelFetch(tex2, ivec2(0, 0), 0) == vec4(1.0, 2.0, -3.14, 0.0));
     """
-    run_glsl_test(gsg, code, preamble, {'tex1': tex1, 'tex2': tex2}), code
+    run_glsl_test(gsg, code, preamble, {'tex1': tex1, 'tex2': tex2})
 
 
 def test_glsl_image(gsg):
@@ -142,7 +152,7 @@ def test_glsl_image(gsg):
     assert(imageLoad(tex1, 0) == vec4(0, 2 / 255.0, 1, 1));
     assert(imageLoad(tex2, ivec2(0, 0)) == vec4(1.0, 2.0, -3.14, 0.0));
     """
-    run_glsl_test(gsg, code, preamble, {'tex1': tex1, 'tex2': tex2}), code
+    run_glsl_test(gsg, code, preamble, {'tex1': tex1, 'tex2': tex2})
 
 
 def test_glsl_ssbo(gsg):
@@ -164,7 +174,10 @@ def test_glsl_ssbo(gsg):
     assert(value1 == 1234567);
     assert(value2 == -1234567);
     """
-    run_glsl_test(gsg, code, preamble, {'buffer1': buffer1, 'buffer2': buffer2}), code
+    run_glsl_test(gsg, code, preamble, {'buffer1': buffer1, 'buffer2': buffer2},
+                  exts={'GL_ARB_shader_storage_buffer_object',
+                        'GL_ARB_uniform_buffer_object',
+                        'GL_ARB_shading_language_420pack'})
 
 
 def test_glsl_int(gsg):
@@ -197,8 +210,8 @@ def test_glsl_uint(gsg):
     uniform uint intmax;
     """
     code = """
-    assert(zero == 0);
-    assert(intmax == 0x7fffffff);
+    assert(zero == 0u);
+    assert(intmax == 0x7fffffffu);
     """
     run_glsl_test(gsg, code, preamble, inputs)
 
@@ -243,7 +256,7 @@ def test_glsl_pta_int(gsg):
     assert(pta[2] == 2);
     assert(pta[3] == 3);
     """
-    run_glsl_test(gsg, code, preamble, {'pta': pta}), code
+    run_glsl_test(gsg, code, preamble, {'pta': pta})
 
 
 def test_glsl_pta_ivec4(gsg):
@@ -256,7 +269,7 @@ def test_glsl_pta_ivec4(gsg):
     assert(pta[0] == ivec4(0, 1, 2, 3));
     assert(pta[1] == ivec4(4, 5, 6, 7));
     """
-    run_glsl_test(gsg, code, preamble, {'pta': pta}), code
+    run_glsl_test(gsg, code, preamble, {'pta': pta})
 
 
 def test_glsl_pta_mat4(gsg):
@@ -278,7 +291,7 @@ def test_glsl_pta_mat4(gsg):
     assert(pta[1][2] == vec4(24, 25, 26, 27));
     assert(pta[1][3] == vec4(28, 29, 30, 31));
     """
-    run_glsl_test(gsg, code, preamble, {'pta': pta}), code
+    run_glsl_test(gsg, code, preamble, {'pta': pta})
 
 
 def test_glsl_write_extract_image_buffer(gsg):
@@ -299,12 +312,12 @@ def test_glsl_write_extract_image_buffer(gsg):
     layout(r32i) uniform iimageBuffer tex2;
     """
     code = """
-    assert(imageLoad(tex1, 0).r == 0);
+    assert(imageLoad(tex1, 0).r == 0u);
     assert(imageLoad(tex2, 0).r == 0);
     imageStore(tex1, 0, uvec4(123));
     imageStore(tex2, 0, ivec4(-456));
     memoryBarrier();
-    assert(imageLoad(tex1, 0).r == 123);
+    assert(imageLoad(tex1, 0).r == 123u);
     assert(imageLoad(tex2, 0).r == -456);
     """
 

+ 8 - 1
tests/event/test_futures.py

@@ -1,6 +1,5 @@
 from panda3d import core
 import pytest
-import threading
 import time
 import sys
 
@@ -39,7 +38,11 @@ def test_future_timeout():
         fut.result(0.001)
 
 
[email protected](not core.Thread.is_threading_supported(),
+                    reason="Threading support disabled")
 def test_future_wait():
+    threading = pytest.importorskip("direct.stdpy.threading")
+
     fut = core.AsyncFuture()
 
     # Launch a thread to set the result value.
@@ -59,7 +62,11 @@ def test_future_wait():
     assert fut.result() is None
 
 
[email protected](not core.Thread.is_threading_supported(),
+                    reason="Threading support disabled")
 def test_future_wait_cancel():
+    threading = pytest.importorskip("direct.stdpy.threading")
+
     fut = core.AsyncFuture()
 
     # Launch a thread to cancel the future.

+ 7 - 0
tests/text/test_textnode.py

@@ -1,6 +1,13 @@
 from panda3d import core
 
 
+def test_textnode_write():
+    out = core.StringStream()
+    text = core.TextNode("test")
+    text.write(out, 0)
+    assert out.data.startswith(b"TextNode test")
+
+
 def test_textnode_card_as_margin():
     text = core.TextNode("test")
     text.text = "Test"