Browse Source

Merge branch 'master' into cmake

Sam Edwards 10 năm trước cách đây
mục cha
commit
69c22868e1
100 tập tin đã thay đổi với 9461 bổ sung944 xóa
  1. 1 1
      .gitignore
  2. 1 1
      README.md
  3. 38 38
      contrib/src/ai/aiBehaviors.cxx
  4. 16 16
      contrib/src/ai/aiBehaviors.h
  5. 21 26
      contrib/src/ai/aiCharacter.cxx
  6. 4 4
      contrib/src/ai/aiCharacter.h
  7. 1 1
      contrib/src/ai/aiNode.cxx
  8. 2 2
      contrib/src/ai/aiNode.h
  9. 2 2
      contrib/src/ai/aiPathFinder.cxx
  10. 1 1
      contrib/src/ai/aiPathFinder.h
  11. 8 8
      contrib/src/ai/arrival.cxx
  12. 3 3
      contrib/src/ai/arrival.h
  13. 4 4
      contrib/src/ai/evade.cxx
  14. 2 2
      contrib/src/ai/evade.h
  15. 7 7
      contrib/src/ai/flee.cxx
  16. 5 5
      contrib/src/ai/flee.h
  17. 1 1
      contrib/src/ai/meshNode.cxx
  18. 2 2
      contrib/src/ai/meshNode.h
  19. 15 15
      contrib/src/ai/obstacleAvoidance.cxx
  20. 1 1
      contrib/src/ai/obstacleAvoidance.h
  21. 3 3
      contrib/src/ai/pathFind.cxx
  22. 2 2
      contrib/src/ai/pathFind.h
  23. 2 2
      contrib/src/ai/pathFollow.cxx
  24. 2 2
      contrib/src/ai/pathFollow.h
  25. 6 6
      contrib/src/ai/pursue.cxx
  26. 2 2
      contrib/src/ai/pursue.h
  27. 5 5
      contrib/src/ai/seek.cxx
  28. 5 5
      contrib/src/ai/seek.h
  29. 18 18
      contrib/src/ai/wander.cxx
  30. 3 3
      contrib/src/ai/wander.h
  31. 0 5
      direct/src/actor/Actor.py
  32. 2 1
      direct/src/directbase/DirectStart.py
  33. 2 0
      direct/src/directnotify/DirectNotifyGlobal.py
  34. 2 2
      direct/src/directscripts/Doxyfile.python
  35. 111 50
      direct/src/directscripts/extract_docs.py
  36. 4 4
      direct/src/distributed/ConnectionRepository.py
  37. 1 1
      direct/src/distributed/DistributedCartesianGrid.py
  38. 0 9
      direct/src/extensions/ConfigVariableFilename-extensions.py
  39. 1 1
      direct/src/extensions/HTTPChannel-extensions.py
  40. 1 1
      direct/src/extensions_native/HTTPChannel_extensions.py
  41. 8 9
      direct/src/filter/CommonFilters.py
  42. 21 22
      direct/src/filter/FilterManager.py
  43. 1 1
      direct/src/leveleditor/LevelEditorBase.py
  44. 2 2
      direct/src/p3d/AppRunner.py
  45. 1 1
      direct/src/p3d/FileSpec.py
  46. 1 1
      direct/src/p3d/HostInfo.py
  47. 2 2
      direct/src/p3d/PackageInfo.py
  48. 1 1
      direct/src/p3d/Packager.py
  49. 1 1
      direct/src/p3d/PatchMaker.py
  50. 1 1
      direct/src/p3d/ScanDirectoryNode.py
  51. 5 6
      direct/src/plugin/Sources.pp
  52. 5 5
      direct/src/plugin/p3dCert.cxx
  53. 2 2
      direct/src/plugin/p3dCert.h
  54. 15 7
      direct/src/plugin/p3dInstance.cxx
  55. 9 9
      direct/src/plugin/p3dMainObject.cxx
  56. 1 1
      direct/src/plugin/p3dOsxSplashWindow.cxx
  57. 1 1
      direct/src/plugin/p3dOsxSplashWindow.h
  58. 5 1
      direct/src/plugin/p3dPackage.cxx
  59. 15 27
      direct/src/plugin/p3dPythonRun.cxx
  60. 0 3
      direct/src/plugin/p3dPythonRun.h
  61. 20 205
      direct/src/plugin/p3dSplashWindow.cxx
  62. 0 4
      direct/src/plugin/p3dSplashWindow.h
  63. 0 1
      direct/src/plugin/p3dX11SplashWindow.cxx
  64. 6326 0
      direct/src/plugin/stb_image.h
  65. 928 0
      direct/src/plugin_npapi/npapi.h
  66. 329 0
      direct/src/plugin_npapi/npfunctions.h
  67. 393 0
      direct/src/plugin_npapi/npruntime.h
  68. 121 0
      direct/src/plugin_npapi/nptypes.h
  69. 2 2
      direct/src/plugin_npapi/ppBrowserObject.cxx
  70. 7 3
      direct/src/plugin_npapi/ppInstance.cxx
  71. 1 1
      direct/src/plugin_npapi/startup.cxx
  72. 1 2
      direct/src/plugin_standalone/Sources.pp
  73. 3 3
      direct/src/plugin_standalone/panda3dBase.cxx
  74. 1 1
      direct/src/plugin_standalone/panda3dMac.cxx
  75. 5 0
      direct/src/showbase/EventManager.py
  76. 156 125
      direct/src/showbase/ShowBase.py
  77. 1 1
      direct/src/showbase/VFSImporter.py
  78. 1 1
      direct/src/showutil/FreezeTool.py
  79. 104 45
      doc/INSTALL-MK
  80. 102 58
      dtool/src/cppparser/cppBison.yxx
  81. 25 4
      dtool/src/cppparser/cppDeclaration.cxx
  82. 6 3
      dtool/src/cppparser/cppDeclaration.h
  83. 100 12
      dtool/src/cppparser/cppEnumType.cxx
  84. 6 0
      dtool/src/cppparser/cppEnumType.h
  85. 132 3
      dtool/src/cppparser/cppExpression.cxx
  86. 2 0
      dtool/src/cppparser/cppExpression.h
  87. 24 1
      dtool/src/cppparser/cppExtensionType.cxx
  88. 6 1
      dtool/src/cppparser/cppExtensionType.h
  89. 42 2
      dtool/src/cppparser/cppIdentifier.cxx
  90. 5 1
      dtool/src/cppparser/cppIdentifier.h
  91. 1 1
      dtool/src/cppparser/cppInstance.cxx
  92. 2 2
      dtool/src/cppparser/cppManifest.cxx
  93. 24 10
      dtool/src/cppparser/cppPreprocessor.cxx
  94. 1 0
      dtool/src/cppparser/cppPreprocessor.h
  95. 146 65
      dtool/src/cppparser/cppScope.cxx
  96. 7 5
      dtool/src/cppparser/cppScope.h
  97. 12 4
      dtool/src/cppparser/cppSimpleType.cxx
  98. 4 2
      dtool/src/cppparser/cppSimpleType.h
  99. 10 11
      dtool/src/cppparser/cppStructType.cxx
  100. 1 0
      dtool/src/cppparser/cppTemplateParameterList.cxx

+ 1 - 1
.gitignore

@@ -1,4 +1,4 @@
 /built_x64
 /built_x64
 /built
 /built
-/samples
 /thirdparty
 /thirdparty
+/targetroot

+ 1 - 1
README.md

@@ -70,7 +70,7 @@ If you are on Ubuntu, this command should cover the most frequently
 used third-party packages:
 used third-party packages:
 
 
 ```bash
 ```bash
-sudo apt-get install python-dev libpng-dev zlib1g-dev libssl-dev libx11-dev libgl1-mesa-dev libxrandr-dev libxxf86dga-dev libxcursor-dev bison flex libfreetype6-dev libvorbis-dev libjpeg-dev libeigen3-dev libopenal-dev libode-dev libbullet-dev nvidia-cg-toolkit
+sudo apt-get install build-essential pkg-config python-dev libpng-dev libjpeg-dev libtiff-dev zlib1g-dev libssl-dev libx11-dev libgl1-mesa-dev libxrandr-dev libxxf86dga-dev libxcursor-dev bison flex libfreetype6-dev libvorbis-dev libeigen3-dev libopenal-dev libode-dev libbullet-dev nvidia-cg-toolkit libgtk2.0-dev
 ```
 ```
 
 
 Once Panda3D has built, you can either install the .deb or .rpm package that
 Once Panda3D has built, you can either install the .deb or .rpm package that

+ 38 - 38
contrib/src/ai/aiBehaviors.cxx

@@ -18,7 +18,7 @@
 static const float _PI = 3.14;
 static const float _PI = 3.14;
 
 
 AIBehaviors::AIBehaviors() {
 AIBehaviors::AIBehaviors() {
-  _steering_force = LVecBase3f(0.0, 0.0, 0.0);
+  _steering_force = LVecBase3(0.0, 0.0, 0.0);
   _behaviors_flags = _behaviors_flags & _none;
   _behaviors_flags = _behaviors_flags & _none;
   _previous_conflict = false;
   _previous_conflict = false;
   _conflict = false;
   _conflict = false;
@@ -67,7 +67,7 @@ bool AIBehaviors::is_conflict() {
       }
       }
 
 
       if(is_on(_flee)) {
       if(is_on(_flee)) {
-        LVecBase3f dirn = _flee_force;
+        LVecBase3 dirn = _flee_force;
         dirn.normalize();
         dirn.normalize();
         _flee_force = _steering_force.length() * dirn * _flee_obj->_flee_weight;
         _flee_force = _steering_force.length() * dirn * _flee_obj->_flee_weight;
       }
       }
@@ -77,7 +77,7 @@ bool AIBehaviors::is_conflict() {
       }
       }
 
 
       if(is_on(_evade)) {
       if(is_on(_evade)) {
-        LVecBase3f dirn = _evade_force;
+        LVecBase3 dirn = _evade_force;
         dirn.normalize();
         dirn.normalize();
         _evade_force = _steering_force.length() * dirn * _evade_obj->_evade_weight;
         _evade_force = _steering_force.length() * dirn * _evade_obj->_evade_weight;
       }
       }
@@ -111,9 +111,9 @@ bool AIBehaviors::is_conflict() {
 
 
 /////////////////////////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////////////////////////
 
 
-void AIBehaviors::accumulate_force(string force_type, LVecBase3f force) {
+void AIBehaviors::accumulate_force(string force_type, LVecBase3 force) {
 
 
-  LVecBase3f old_force;
+  LVecBase3 old_force;
 
 
   if(force_type == "seek") {
   if(force_type == "seek") {
     old_force = _seek_force;
     old_force = _seek_force;
@@ -169,8 +169,8 @@ void AIBehaviors::accumulate_force(string force_type, LVecBase3f force) {
 
 
 //////////////////////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////
 
 
-LVecBase3f AIBehaviors::calculate_prioritized() {
-  LVecBase3f force;
+LVecBase3 AIBehaviors::calculate_prioritized() {
+  LVecBase3 force;
 
 
   if(is_on(_seek)) {
   if(is_on(_seek)) {
     if(_conflict) {
     if(_conflict) {
@@ -299,13 +299,13 @@ LVecBase3f AIBehaviors::calculate_prioritized() {
 
 
   if(is_on(_arrival)) {
   if(is_on(_arrival)) {
     if(_seek_obj != NULL) {
     if(_seek_obj != NULL) {
-      LVecBase3f dirn = _steering_force;
+      LVecBase3 dirn = _steering_force;
       dirn.normalize();
       dirn.normalize();
       _steering_force = ((_steering_force.length() - _arrival_force.length()) * dirn);
       _steering_force = ((_steering_force.length() - _arrival_force.length()) * dirn);
     }
     }
 
 
     if(_pursue_obj != NULL) {
     if(_pursue_obj != NULL) {
-      LVecBase3f dirn = _steering_force;
+      LVecBase3 dirn = _steering_force;
       dirn.normalize();
       dirn.normalize();
       _steering_force = ((_steering_force.length() - _arrival_force.length()) * _arrival_obj->_arrival_direction);
       _steering_force = ((_steering_force.length() - _arrival_force.length()) * _arrival_obj->_arrival_direction);
     }
     }
@@ -639,7 +639,7 @@ void AIBehaviors::resume_ai(string ai_type) {
 // Function : seek
 // Function : seek
 // Description : This function activates seek and makes an object of the Seek class.
 // Description : This function activates seek and makes an object of the Seek class.
 //                This is the function we want the user to call for seek to be done.
 //                This is the function we want the user to call for seek to be done.
-//                This function is overloaded to accept a NodePath or an LVecBase3f.
+//                This function is overloaded to accept a NodePath or an LVecBase3.
 
 
 /////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////
 
 
@@ -648,7 +648,7 @@ void AIBehaviors::seek(NodePath target_object, float seek_wt) {
   turn_on("seek");
   turn_on("seek");
 }
 }
 
 
-void AIBehaviors::seek(LVecBase3f pos, float seek_wt) {
+void AIBehaviors::seek(LVecBase3 pos, float seek_wt) {
   _seek_obj = new Seek(_ai_char, pos, seek_wt);
   _seek_obj = new Seek(_ai_char, pos, seek_wt);
   turn_on("seek");
   turn_on("seek");
 }
 }
@@ -657,7 +657,7 @@ void AIBehaviors::seek(LVecBase3f pos, float seek_wt) {
 //
 //
 // Function : flee
 // Function : flee
 // Description : This function activates flee_activate and creates an object of the Flee class.
 // Description : This function activates flee_activate and creates an object of the Flee class.
-//                This function is overloaded to accept a NodePath or an LVecBase3f.
+//                This function is overloaded to accept a NodePath or an LVecBase3.
 
 
 //////////////////////////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////////
 
 
@@ -668,7 +668,7 @@ void AIBehaviors::flee(NodePath target_object, double panic_distance, double rel
   turn_on("flee_activate");
   turn_on("flee_activate");
 }
 }
 
 
-void AIBehaviors::flee(LVecBase3f pos, double panic_distance, double relax_distance, float flee_wt) {
+void AIBehaviors::flee(LVecBase3 pos, double panic_distance, double relax_distance, float flee_wt) {
   _flee_obj = new Flee(_ai_char, pos, panic_distance, relax_distance, flee_wt);
   _flee_obj = new Flee(_ai_char, pos, panic_distance, relax_distance, flee_wt);
   _flee_list.insert(_flee_list.end(), *_flee_obj);
   _flee_list.insert(_flee_list.end(), *_flee_obj);
 
 
@@ -769,38 +769,38 @@ void AIBehaviors::flock_activate() {
 
 
 /////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////
 
 
-LVecBase3f AIBehaviors::do_flock() {
+LVecBase3 AIBehaviors::do_flock() {
 
 
   //! Initialize variables required to compute the flocking force on the ai char.
   //! Initialize variables required to compute the flocking force on the ai char.
   unsigned int neighbor_count = 0;
   unsigned int neighbor_count = 0;
-  LVecBase3f separation_force = LVecBase3f(0.0, 0.0, 0.0);
-  LVecBase3f alignment_force = LVecBase3f(0.0, 0.0, 0.0);
-  LVecBase3f cohesion_force = LVecBase3f(0.0, 0.0, 0.0);
-  LVecBase3f avg_neighbor_heading = LVecBase3f(0.0, 0.0, 0.0);
-  LVecBase3f total_neighbor_heading = LVecBase3f(0.0, 0.0, 0.0);
-  LVecBase3f avg_center_of_mass = LVecBase3f(0.0, 0.0, 0.0);
-  LVecBase3f total_center_of_mass = LVecBase3f(0.0, 0.0, 0.0);
+  LVecBase3 separation_force = LVecBase3(0.0, 0.0, 0.0);
+  LVecBase3 alignment_force = LVecBase3(0.0, 0.0, 0.0);
+  LVecBase3 cohesion_force = LVecBase3(0.0, 0.0, 0.0);
+  LVecBase3 avg_neighbor_heading = LVecBase3(0.0, 0.0, 0.0);
+  LVecBase3 total_neighbor_heading = LVecBase3(0.0, 0.0, 0.0);
+  LVecBase3 avg_center_of_mass = LVecBase3(0.0, 0.0, 0.0);
+  LVecBase3 total_center_of_mass = LVecBase3(0.0, 0.0, 0.0);
 
 
   //! Loop through all the other AI units in the flock to check if they are neigbours.
   //! Loop through all the other AI units in the flock to check if they are neigbours.
   for(unsigned int i = 0; i < _flock_group->_ai_char_list.size(); i++) {
   for(unsigned int i = 0; i < _flock_group->_ai_char_list.size(); i++) {
     if(_flock_group->_ai_char_list[i]->_name != _ai_char->_name) {
     if(_flock_group->_ai_char_list[i]->_name != _ai_char->_name) {
 
 
       //! Using visibilty cone to detect neighbors.
       //! Using visibilty cone to detect neighbors.
-      LVecBase3f dist_vect = _flock_group->_ai_char_list[i]->_ai_char_np.get_pos() - _ai_char->_ai_char_np.get_pos();
-      LVecBase3f ai_char_heading = _ai_char->get_velocity();
+      LVecBase3 dist_vect = _flock_group->_ai_char_list[i]->_ai_char_np.get_pos() - _ai_char->_ai_char_np.get_pos();
+      LVecBase3 ai_char_heading = _ai_char->get_velocity();
       ai_char_heading.normalize();
       ai_char_heading.normalize();
 
 
       //! Check if the current unit is a neighbor.
       //! Check if the current unit is a neighbor.
       if(dist_vect.dot(ai_char_heading) > ((dist_vect.length()) * (ai_char_heading.length()) * cos(_flock_group->_flock_vcone_angle * (_PI / 180)))
       if(dist_vect.dot(ai_char_heading) > ((dist_vect.length()) * (ai_char_heading.length()) * cos(_flock_group->_flock_vcone_angle * (_PI / 180)))
         && (dist_vect.length() < _flock_group->_flock_vcone_radius)) {
         && (dist_vect.length() < _flock_group->_flock_vcone_radius)) {
           //! Separation force calculation.
           //! Separation force calculation.
-          LVecBase3f ai_char_to_units = _ai_char->_ai_char_np.get_pos() - _flock_group->_ai_char_list[i]->_ai_char_np.get_pos();
+          LVecBase3 ai_char_to_units = _ai_char->_ai_char_np.get_pos() - _flock_group->_ai_char_list[i]->_ai_char_np.get_pos();
           float to_units_dist = ai_char_to_units.length();
           float to_units_dist = ai_char_to_units.length();
           ai_char_to_units.normalize();
           ai_char_to_units.normalize();
           separation_force += (ai_char_to_units / to_units_dist);
           separation_force += (ai_char_to_units / to_units_dist);
 
 
           //! Calculating the total heading and center of mass of all the neighbors.
           //! Calculating the total heading and center of mass of all the neighbors.
-          LVecBase3f neighbor_heading = _flock_group->_ai_char_list[i]->get_velocity();
+          LVecBase3 neighbor_heading = _flock_group->_ai_char_list[i]->get_velocity();
           neighbor_heading.normalize();
           neighbor_heading.normalize();
           total_neighbor_heading += neighbor_heading;
           total_neighbor_heading += neighbor_heading;
           total_center_of_mass += _flock_group->_ai_char_list[i]->_ai_char_np.get_pos();
           total_center_of_mass += _flock_group->_ai_char_list[i]->_ai_char_np.get_pos();
@@ -814,7 +814,7 @@ LVecBase3f AIBehaviors::do_flock() {
   if(neighbor_count > 0) {
   if(neighbor_count > 0) {
     //! Alignment force calculation
     //! Alignment force calculation
     avg_neighbor_heading = total_neighbor_heading / neighbor_count;
     avg_neighbor_heading = total_neighbor_heading / neighbor_count;
-    LVector3f ai_char_heading = _ai_char->get_velocity();
+    LVector3 ai_char_heading = _ai_char->get_velocity();
     ai_char_heading.normalize();
     ai_char_heading.normalize();
     avg_neighbor_heading -= ai_char_heading;
     avg_neighbor_heading -= ai_char_heading;
     avg_neighbor_heading.normalize();
     avg_neighbor_heading.normalize();
@@ -822,7 +822,7 @@ LVecBase3f AIBehaviors::do_flock() {
 
 
     //! Cohesion force calculation
     //! Cohesion force calculation
     avg_center_of_mass = total_center_of_mass / neighbor_count;
     avg_center_of_mass = total_center_of_mass / neighbor_count;
-    LVecBase3f cohesion_dir = avg_center_of_mass - _ai_char->_ai_char_np.get_pos();
+    LVecBase3 cohesion_dir = avg_center_of_mass - _ai_char->_ai_char_np.get_pos();
     cohesion_dir.normalize();
     cohesion_dir.normalize();
     cohesion_force = cohesion_dir * _ai_char->_movt_force;
     cohesion_force = cohesion_dir * _ai_char->_movt_force;
   }
   }
@@ -830,7 +830,7 @@ LVecBase3f AIBehaviors::do_flock() {
     _flock_done = true;
     _flock_done = true;
     turn_off("flock");
     turn_off("flock");
     turn_on("flock_activate");
     turn_on("flock_activate");
-    return(LVecBase3f(0.0, 0.0, 0.0));
+    return(LVecBase3(0.0, 0.0, 0.0));
   }
   }
 
 
   //! Calculate the resultant force on the ai character by taking into account the separation, alignment and cohesion
   //! Calculate the resultant force on the ai character by taking into account the separation, alignment and cohesion
@@ -885,7 +885,7 @@ void AIBehaviors::path_follow(float follow_wt) {
 
 
 /////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////
 
 
-void AIBehaviors::add_to_path(LVecBase3f pos) {
+void AIBehaviors::add_to_path(LVecBase3 pos) {
   _path_follow_obj->add_to_path(pos);
   _path_follow_obj->add_to_path(pos);
 }
 }
 
 
@@ -923,7 +923,7 @@ void AIBehaviors::init_path_find(const char* navmesh_filename) {
 
 
 ///////////////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////////////
 
 
-void AIBehaviors::path_find_to(LVecBase3f pos, string type) {
+void AIBehaviors::path_find_to(LVecBase3 pos, string type) {
   _path_find_obj->path_find(pos, type);
   _path_find_obj->path_find(pos, type);
 }
 }
 
 
@@ -1331,56 +1331,56 @@ switch(char_to_int(ai_type)) {
               if (is_on(_seek)) {
               if (is_on(_seek)) {
                 _behaviors_flags ^= _seek;
                 _behaviors_flags ^= _seek;
               }
               }
-              _seek_force = LVecBase3f(0.0f, 0.0f, 0.0f);
+              _seek_force = LVecBase3(0.0f, 0.0f, 0.0f);
               break;
               break;
             }
             }
     case 2: {
     case 2: {
               if (is_on(_flee)) {
               if (is_on(_flee)) {
                 _behaviors_flags ^= _flee;
                 _behaviors_flags ^= _flee;
               }
               }
-              _flee_force = LVecBase3f(0.0f, 0.0f, 0.0f);
+              _flee_force = LVecBase3(0.0f, 0.0f, 0.0f);
               break;
               break;
             }
             }
     case 3: {
     case 3: {
               if(is_on(_pursue)) {
               if(is_on(_pursue)) {
                 _behaviors_flags ^= _pursue;
                 _behaviors_flags ^= _pursue;
               }
               }
-              _pursue_force = LVecBase3f(0.0f, 0.0f, 0.0f);
+              _pursue_force = LVecBase3(0.0f, 0.0f, 0.0f);
               break;
               break;
             }
             }
     case 4: {
     case 4: {
               if(is_on(_evade)) {
               if(is_on(_evade)) {
                 _behaviors_flags ^= _evade;
                 _behaviors_flags ^= _evade;
               }
               }
-              _evade_force = LVecBase3f(0.0f, 0.0f, 0.0f);
+              _evade_force = LVecBase3(0.0f, 0.0f, 0.0f);
               break;
               break;
             }
             }
     case 5: {
     case 5: {
               if (is_on(_arrival)) {
               if (is_on(_arrival)) {
                   _behaviors_flags ^= _arrival;
                   _behaviors_flags ^= _arrival;
                 }
                 }
-                _arrival_force = LVecBase3f(0.0f, 0.0f, 0.0f);
+                _arrival_force = LVecBase3(0.0f, 0.0f, 0.0f);
               break;
               break;
             }
             }
     case 6: {
     case 6: {
               if(is_on(_flock)) {
               if(is_on(_flock)) {
                 _behaviors_flags ^= _flock;
                 _behaviors_flags ^= _flock;
               }
               }
-              _flock_force = LVecBase3f(0.0f, 0.0f, 0.0f);
+              _flock_force = LVecBase3(0.0f, 0.0f, 0.0f);
               break;
               break;
             }
             }
     case 7: {
     case 7: {
               if(is_on(_wander)) {
               if(is_on(_wander)) {
                 _behaviors_flags ^= _wander;
                 _behaviors_flags ^= _wander;
               }
               }
-              _wander_force = LVecBase3f(0.0f, 0.0f, 0.0f);
+              _wander_force = LVecBase3(0.0f, 0.0f, 0.0f);
               break;
               break;
             }
             }
     case 8: {
     case 8: {
               if(is_on(_obstacle_avoidance)) {
               if(is_on(_obstacle_avoidance)) {
                 _behaviors_flags ^= _obstacle_avoidance;
                 _behaviors_flags ^= _obstacle_avoidance;
               }
               }
-              _obstacle_avoidance_force = LVecBase3f(0.0f, 0.0f, 0.0f);
+              _obstacle_avoidance_force = LVecBase3(0.0f, 0.0f, 0.0f);
               break;
               break;
             }
             }
     case 9:{
     case 9:{

+ 16 - 16
contrib/src/ai/aiBehaviors.h

@@ -73,41 +73,41 @@ public:
   Flock *_flock_group;
   Flock *_flock_group;
 
 
   int _behaviors_flags;
   int _behaviors_flags;
-  LVecBase3f _steering_force;
+  LVecBase3 _steering_force;
 
 
   Seek *_seek_obj;
   Seek *_seek_obj;
-  LVecBase3f _seek_force;
+  LVecBase3 _seek_force;
 
 
   Flee *_flee_obj;
   Flee *_flee_obj;
-  LVecBase3f _flee_force;
+  LVecBase3 _flee_force;
 
 
   //! This list is used if the ai character needs to flee from multiple onjects.
   //! This list is used if the ai character needs to flee from multiple onjects.
   ListFlee _flee_list;
   ListFlee _flee_list;
   ListFlee::iterator _flee_itr;
   ListFlee::iterator _flee_itr;
 
 
   Pursue *_pursue_obj;
   Pursue *_pursue_obj;
-  LVecBase3f _pursue_force;
+  LVecBase3 _pursue_force;
 
 
   Evade *_evade_obj;
   Evade *_evade_obj;
-  LVecBase3f _evade_force;
+  LVecBase3 _evade_force;
 
 
   //! This list is used if the ai character needs to evade from multiple onjects.
   //! This list is used if the ai character needs to evade from multiple onjects.
   ListEvade _evade_list;
   ListEvade _evade_list;
   ListEvade::iterator _evade_itr;
   ListEvade::iterator _evade_itr;
 
 
   Arrival *_arrival_obj;
   Arrival *_arrival_obj;
-  LVecBase3f _arrival_force;
+  LVecBase3 _arrival_force;
 
 
   //! Since Flock is a collective behavior the variables are declared within the AIBehaviors class.
   //! Since Flock is a collective behavior the variables are declared within the AIBehaviors class.
   float _flock_weight;
   float _flock_weight;
-  LVecBase3f _flock_force;
+  LVecBase3 _flock_force;
   bool _flock_done;
   bool _flock_done;
 
 
   Wander * _wander_obj;
   Wander * _wander_obj;
-  LVecBase3f _wander_force;
+  LVecBase3 _wander_force;
 
 
   ObstacleAvoidance *_obstacle_avoidance_obj;
   ObstacleAvoidance *_obstacle_avoidance_obj;
-  LVecBase3f _obstacle_avoidance_force;
+  LVecBase3 _obstacle_avoidance_force;
 
 
   PathFollow *_path_follow_obj;
   PathFollow *_path_follow_obj;
 
 
@@ -127,20 +127,20 @@ public:
 
 
   bool is_conflict();
   bool is_conflict();
 
 
-  void accumulate_force(string force_type, LVecBase3f force);
-  LVecBase3f calculate_prioritized();
+  void accumulate_force(string force_type, LVecBase3 force);
+  LVecBase3 calculate_prioritized();
 
 
   void flock_activate();
   void flock_activate();
-  LVecBase3f do_flock();
+  LVecBase3 do_flock();
 
 
   int char_to_int(string ai_type);
   int char_to_int(string ai_type);
 
 
 PUBLISHED:
 PUBLISHED:
   void seek(NodePath target_object, float seek_wt = 1.0);
   void seek(NodePath target_object, float seek_wt = 1.0);
-  void seek(LVecBase3f pos, float seek_wt = 1.0);
+  void seek(LVecBase3 pos, float seek_wt = 1.0);
 
 
   void flee(NodePath target_object, double panic_distance = 10.0, double relax_distance = 10.0, float flee_wt = 1.0);
   void flee(NodePath target_object, double panic_distance = 10.0, double relax_distance = 10.0, float flee_wt = 1.0);
-  void flee(LVecBase3f pos, double panic_distance = 10.0, double relax_distance = 10.0, float flee_wt = 1.0);
+  void flee(LVecBase3 pos, double panic_distance = 10.0, double relax_distance = 10.0, float flee_wt = 1.0);
 
 
   void pursue(NodePath target_object, float pursue_wt = 1.0);
   void pursue(NodePath target_object, float pursue_wt = 1.0);
 
 
@@ -155,12 +155,12 @@ PUBLISHED:
   void obstacle_avoidance(float feeler_length = 1.0);
   void obstacle_avoidance(float feeler_length = 1.0);
 
 
   void path_follow(float follow_wt);
   void path_follow(float follow_wt);
-  void add_to_path(LVecBase3f pos);
+  void add_to_path(LVecBase3 pos);
   void start_follow(string type = "normal");
   void start_follow(string type = "normal");
 
 
   // should have different function names.
   // should have different function names.
   void init_path_find(const char* navmesh_filename);
   void init_path_find(const char* navmesh_filename);
-  void path_find_to(LVecBase3f pos, string type = "normal");
+  void path_find_to(LVecBase3 pos, string type = "normal");
   void path_find_to(NodePath target, string type = "normal");
   void path_find_to(NodePath target, string type = "normal");
   void add_static_obstacle(NodePath obstacle);
   void add_static_obstacle(NodePath obstacle);
   void add_dynamic_obstacle(NodePath obstacle);
   void add_dynamic_obstacle(NodePath obstacle);

+ 21 - 26
contrib/src/ai/aiCharacter.cxx

@@ -23,8 +23,8 @@ AICharacter::AICharacter(string model_name, NodePath model_np, double mass, doub
   _max_force = max_force;
   _max_force = max_force;
   _movt_force = movt_force;
   _movt_force = movt_force;
 
 
-  _velocity = LVecBase3f(0.0, 0.0, 0.0);
-  _steering_force = LVecBase3f(0.0, 0.0, 0.0);
+  _velocity = LVecBase3(0.0, 0.0, 0.0);
+  _steering_force = LVecBase3(0.0, 0.0, 0.0);
 
 
   _steering = new AIBehaviors();
   _steering = new AIBehaviors();
   _steering->_ai_char = this;
   _steering->_ai_char = this;
@@ -43,48 +43,43 @@ AICharacter::~AICharacter() {
 //                This also makes the character  look at the direction of the force.
 //                This also makes the character  look at the direction of the force.
 
 
 /////////////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////////////
-
-void AICharacter::update() {
-
-  if(!_steering->is_off(_steering->_none)) {
-
-    LVecBase3f old_pos = _ai_char_np.get_pos();
-
-    LVecBase3f steering_force = _steering->calculate_prioritized();
-
-    LVecBase3f acceleration = steering_force / _mass;
+void AICharacter::
+update() {
+  if (!_steering->is_off(_steering->_none)) {
+    LVecBase3 old_pos = _ai_char_np.get_pos();
+    LVecBase3 steering_force = _steering->calculate_prioritized();
+    LVecBase3 acceleration = steering_force / _mass;
 
 
     _velocity = acceleration;
     _velocity = acceleration;
 
 
-    LVecBase3f direction = _steering->_steering_force;
+    LVecBase3 direction = _steering->_steering_force;
     direction.normalize();
     direction.normalize();
 
 
     _ai_char_np.set_pos(old_pos + _velocity) ;
     _ai_char_np.set_pos(old_pos + _velocity) ;
 
 
-    if(steering_force.length() > 0) {
+    if (steering_force.length() > 0) {
       _ai_char_np.look_at(old_pos + (direction * 5));
       _ai_char_np.look_at(old_pos + (direction * 5));
       _ai_char_np.set_h(_ai_char_np.get_h() + 180);
       _ai_char_np.set_h(_ai_char_np.get_h() + 180);
       _ai_char_np.set_p(-_ai_char_np.get_p());
       _ai_char_np.set_p(-_ai_char_np.get_p());
       _ai_char_np.set_r(-_ai_char_np.get_r());
       _ai_char_np.set_r(-_ai_char_np.get_r());
     }
     }
-  }
-  else {
-    _steering->_steering_force = LVecBase3f(0.0, 0.0, 0.0);
-    _steering->_seek_force = LVecBase3f(0.0, 0.0, 0.0);
-    _steering->_flee_force = LVecBase3f(0.0, 0.0, 0.0);
-    _steering->_pursue_force = LVecBase3f(0.0, 0.0, 0.0);
-    _steering->_evade_force = LVecBase3f(0.0, 0.0, 0.0);
-    _steering->_arrival_force = LVecBase3f(0.0, 0.0, 0.0);
-    _steering->_flock_force = LVecBase3f(0.0, 0.0, 0.0);
-    _steering->_wander_force = LVecBase3f(0.0, 0.0, 0.0);
+  } else {
+    _steering->_steering_force = LVecBase3(0.0, 0.0, 0.0);
+    _steering->_seek_force = LVecBase3(0.0, 0.0, 0.0);
+    _steering->_flee_force = LVecBase3(0.0, 0.0, 0.0);
+    _steering->_pursue_force = LVecBase3(0.0, 0.0, 0.0);
+    _steering->_evade_force = LVecBase3(0.0, 0.0, 0.0);
+    _steering->_arrival_force = LVecBase3(0.0, 0.0, 0.0);
+    _steering->_flock_force = LVecBase3(0.0, 0.0, 0.0);
+    _steering->_wander_force = LVecBase3(0.0, 0.0, 0.0);
   }
   }
 }
 }
 
 
-LVecBase3f AICharacter::get_velocity() {
+LVecBase3 AICharacter::get_velocity() {
   return _velocity;
   return _velocity;
 }
 }
 
 
-void AICharacter::set_velocity(LVecBase3f velocity) {
+void AICharacter::set_velocity(LVecBase3 velocity) {
   _velocity = velocity;
   _velocity = velocity;
 }
 }
 
 

+ 4 - 4
contrib/src/ai/aiCharacter.h

@@ -39,8 +39,8 @@ class EXPCL_PANDAAI AICharacter {
  public:
  public:
   double _mass;
   double _mass;
   double _max_force;
   double _max_force;
-  LVecBase3f _velocity;
-  LVecBase3f _steering_force;
+  LVecBase3 _velocity;
+  LVecBase3 _steering_force;
   string _name;
   string _name;
   double _movt_force;
   double _movt_force;
   unsigned int _ai_char_flock_id;
   unsigned int _ai_char_flock_id;
@@ -51,7 +51,7 @@ class EXPCL_PANDAAI AICharacter {
   bool _pf_guide;
   bool _pf_guide;
 
 
   void update();
   void update();
-  void set_velocity(LVecBase3f vel);
+  void set_velocity(LVecBase3 vel);
   void set_char_render(NodePath render);
   void set_char_render(NodePath render);
   NodePath get_char_render();
   NodePath get_char_render();
 
 
@@ -59,7 +59,7 @@ PUBLISHED:
     double get_mass();
     double get_mass();
     void set_mass(double m);
     void set_mass(double m);
 
 
-    LVecBase3f get_velocity();
+    LVecBase3 get_velocity();
 
 
     double get_max_force();
     double get_max_force();
     void set_max_force(double max_force);
     void set_max_force(double max_force);

+ 1 - 1
contrib/src/ai/aiNode.cxx

@@ -14,7 +14,7 @@
 
 
 #include "aiNode.h"
 #include "aiNode.h"
 
 
-AINode::AINode(int grid_x, int grid_y, LVecBase3f pos, float w, float l, float h) {
+AINode::AINode(int grid_x, int grid_y, LVecBase3 pos, float w, float l, float h) {
   for (int i = 0; i < 8; ++i) {
   for (int i = 0; i < 8; ++i) {
     _neighbours[i] = NULL;
     _neighbours[i] = NULL;
   }
   }

+ 2 - 2
contrib/src/ai/aiNode.h

@@ -62,7 +62,7 @@ public:
   int _grid_x, _grid_y;
   int _grid_x, _grid_y;
 
 
   // Position of the node in 3D space.
   // Position of the node in 3D space.
-  LVecBase3f _position;
+  LVecBase3 _position;
 
 
   // Dimensions of each face / cell on the mesh.
   // Dimensions of each face / cell on the mesh.
   // Height is given in case of expansion to a 3d mesh. Currently
   // Height is given in case of expansion to a 3d mesh. Currently
@@ -77,7 +77,7 @@ public:
   AINode *_next;
   AINode *_next;
 
 
 PUBLISHED:
 PUBLISHED:
-  AINode(int grid_x, int grid_y, LVecBase3f pos, float w, float l, float h);
+  AINode(int grid_x, int grid_y, LVecBase3 pos, float w, float l, float h);
   ~AINode();
   ~AINode();
 
 
   bool contains(float x, float y);
   bool contains(float x, float y);

+ 2 - 2
contrib/src/ai/aiPathFinder.cxx

@@ -36,7 +36,7 @@ void PathFinder::find_path(Node *src_node, Node *dest_node) {
 
 
   // Add a dummy node as the first element of the open list with score = -1.
   // Add a dummy node as the first element of the open list with score = -1.
   // Inorder to implement a binary heap the index of the elements should never be 0.
   // Inorder to implement a binary heap the index of the elements should never be 0.
-  Node *_dummy_node = new Node(-1, -1, LVecBase3f(0.0, 0.0, 0.0), 0, 0, 0);
+  Node *_dummy_node = new Node(-1, -1, LVecBase3(0.0, 0.0, 0.0), 0, 0, 0);
   _dummy_node->_status = _dummy_node->open;
   _dummy_node->_status = _dummy_node->open;
   _dummy_node->_score = -1;
   _dummy_node->_score = -1;
   _open_list.push_back(_dummy_node);
   _open_list.push_back(_dummy_node);
@@ -379,7 +379,7 @@ void PathFinder::remove_from_clist(int r, int c) {
 
 
 /////////////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////////////
 
 
-Node* find_in_mesh(NavMesh nav_mesh, LVecBase3f pos, int grid_size) {
+Node* find_in_mesh(NavMesh nav_mesh, LVecBase3 pos, int grid_size) {
   int size = grid_size;
   int size = grid_size;
   float x = pos[0];
   float x = pos[0];
   float y = pos[1];
   float y = pos[1];

+ 1 - 1
contrib/src/ai/aiPathFinder.h

@@ -23,7 +23,7 @@
 typedef vector<Node *> NodeArray;
 typedef vector<Node *> NodeArray;
 typedef vector<NodeArray> NavMesh;
 typedef vector<NodeArray> NavMesh;
 
 
-Node* find_in_mesh(NavMesh nav_mesh, LVecBase3f pos, int grid_size);
+Node* find_in_mesh(NavMesh nav_mesh, LVecBase3 pos, int grid_size);
 
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 //
 //

+ 8 - 8
contrib/src/ai/arrival.cxx

@@ -36,8 +36,8 @@ Arrival::~Arrival() {
 
 
 /////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////
 
 
-LVecBase3f Arrival::do_arrival() {
-  LVecBase3f direction_to_target;
+LVecBase3 Arrival::do_arrival() {
+  LVecBase3 direction_to_target;
   double distance;
   double distance;
 
 
   if(_arrival_type) {
   if(_arrival_type) {
@@ -52,22 +52,22 @@ LVecBase3f Arrival::do_arrival() {
   _arrival_direction.normalize();
   _arrival_direction.normalize();
 
 
   if(int(distance) == 0) {
   if(int(distance) == 0) {
-    _ai_char->_steering->_steering_force = LVecBase3f(0.0, 0.0, 0.0);
-    _ai_char->_steering->_arrival_force = LVecBase3f(0.0, 0.0, 0.0);
+    _ai_char->_steering->_steering_force = LVecBase3(0.0, 0.0, 0.0);
+    _ai_char->_steering->_arrival_force = LVecBase3(0.0, 0.0, 0.0);
 
 
     if(_ai_char->_steering->_seek_obj != NULL) {
     if(_ai_char->_steering->_seek_obj != NULL) {
       _ai_char->_steering->turn_off("arrival");
       _ai_char->_steering->turn_off("arrival");
       _ai_char->_steering->turn_on("arrival_activate");
       _ai_char->_steering->turn_on("arrival_activate");
     }
     }
     _arrival_done = true;
     _arrival_done = true;
-    return(LVecBase3f(0.0, 0.0, 0.0));
+    return(LVecBase3(0.0, 0.0, 0.0));
   }
   }
   else {
   else {
     _arrival_done = false;
     _arrival_done = false;
   }
   }
 
 
   double u = _ai_char->get_velocity().length();
   double u = _ai_char->get_velocity().length();
-  LVecBase3f desired_force = ((u * u) / (2 * distance)) * _ai_char->get_mass();
+  LVecBase3 desired_force = ((u * u) / (2 * distance)) * _ai_char->get_mass();
 
 
   if(_ai_char->_steering->_seek_obj != NULL) {
   if(_ai_char->_steering->_seek_obj != NULL) {
     return(desired_force);
     return(desired_force);
@@ -85,7 +85,7 @@ LVecBase3f Arrival::do_arrival() {
   }
   }
 
 
   cout<<"Arrival works only with seek and pursue"<<endl;
   cout<<"Arrival works only with seek and pursue"<<endl;
-  return(LVecBase3f(0.0, 0.0, 0.0));
+  return(LVecBase3(0.0, 0.0, 0.0));
 }
 }
 
 
 /////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////
@@ -98,7 +98,7 @@ LVecBase3f Arrival::do_arrival() {
 /////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////
 
 
 void Arrival::arrival_activate() {
 void Arrival::arrival_activate() {
-  LVecBase3f dirn;
+  LVecBase3 dirn;
   if(_arrival_type) {
   if(_arrival_type) {
     dirn = (_ai_char->_ai_char_np.get_pos(_ai_char->_window_render) - _ai_char->get_ai_behaviors()->_pursue_obj->_pursue_target.get_pos(_ai_char->_window_render));
     dirn = (_ai_char->_ai_char_np.get_pos(_ai_char->_window_render) - _ai_char->get_ai_behaviors()->_pursue_obj->_pursue_target.get_pos(_ai_char->_window_render));
   }
   }

+ 3 - 3
contrib/src/ai/arrival.h

@@ -27,9 +27,9 @@ public:
   AICharacter *_ai_char;
   AICharacter *_ai_char;
 
 
   NodePath _arrival_target;
   NodePath _arrival_target;
-  LVecBase3f _arrival_target_pos;
+  LVecBase3 _arrival_target_pos;
   double _arrival_distance;
   double _arrival_distance;
-  LVecBase3f _arrival_direction;
+  LVecBase3 _arrival_direction;
   bool _arrival_done;
   bool _arrival_done;
 
 
   // This flag specifies if the arrival behavior is being used with seek or pursue behavior.
   // This flag specifies if the arrival behavior is being used with seek or pursue behavior.
@@ -39,7 +39,7 @@ public:
 
 
   Arrival(AICharacter *ai_ch, double distance = 10.0);
   Arrival(AICharacter *ai_ch, double distance = 10.0);
   ~Arrival();
   ~Arrival();
-  LVecBase3f do_arrival();
+  LVecBase3 do_arrival();
   void arrival_activate();
   void arrival_activate();
 };
 };
 
 

+ 4 - 4
contrib/src/ai/evade.cxx

@@ -42,23 +42,23 @@ Evade::~Evade() {
 
 
 /////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////
 
 
-LVecBase3f Evade::do_evade() {
+LVecBase3 Evade::do_evade() {
   assert(_evade_target && "evade target not assigned");
   assert(_evade_target && "evade target not assigned");
 
 
   _evade_direction = _ai_char->_ai_char_np.get_pos(_ai_char->_window_render) - _evade_target.get_pos(_ai_char->_window_render);
   _evade_direction = _ai_char->_ai_char_np.get_pos(_ai_char->_window_render) - _evade_target.get_pos(_ai_char->_window_render);
   double distance = _evade_direction.length();
   double distance = _evade_direction.length();
 
 
   _evade_direction.normalize();
   _evade_direction.normalize();
-  LVecBase3f desired_force = _evade_direction * _ai_char->_movt_force;
+  LVecBase3 desired_force = _evade_direction * _ai_char->_movt_force;
 
 
   if(distance > (_evade_distance + _evade_relax_distance)) {
   if(distance > (_evade_distance + _evade_relax_distance)) {
     if((_ai_char->_steering->_behaviors_flags | _ai_char->_steering->_evade) == _ai_char->_steering->_evade) {
     if((_ai_char->_steering->_behaviors_flags | _ai_char->_steering->_evade) == _ai_char->_steering->_evade) {
-      _ai_char->_steering->_steering_force = LVecBase3f(0.0, 0.0, 0.0);
+      _ai_char->_steering->_steering_force = LVecBase3(0.0, 0.0, 0.0);
     }
     }
     _ai_char->_steering->turn_off("evade");
     _ai_char->_steering->turn_off("evade");
     _ai_char->_steering->turn_on("evade_activate");
     _ai_char->_steering->turn_on("evade_activate");
     _evade_done = true;
     _evade_done = true;
-    return(LVecBase3f(0.0, 0.0, 0.0));
+    return(LVecBase3(0.0, 0.0, 0.0));
   }
   }
   else {
   else {
       _evade_done = false;
       _evade_done = false;

+ 2 - 2
contrib/src/ai/evade.h

@@ -28,7 +28,7 @@ public:
 
 
   NodePath _evade_target;
   NodePath _evade_target;
   float _evade_weight;
   float _evade_weight;
-  LVecBase3f _evade_direction;
+  LVecBase3 _evade_direction;
   double _evade_distance;
   double _evade_distance;
   double _evade_relax_distance;
   double _evade_relax_distance;
   bool _evade_done;
   bool _evade_done;
@@ -38,7 +38,7 @@ public:
                                           double relax_distance, float evade_wt);
                                           double relax_distance, float evade_wt);
 
 
   ~Evade();
   ~Evade();
-  LVecBase3f do_evade();
+  LVecBase3 do_evade();
   void evade_activate();
   void evade_activate();
 };
 };
 
 

+ 7 - 7
contrib/src/ai/flee.cxx

@@ -29,7 +29,7 @@ Flee::Flee(AICharacter *ai_ch, NodePath target_object, double panic_distance,
   _flee_activate_done = false;
   _flee_activate_done = false;
 }
 }
 
 
-Flee::Flee(AICharacter *ai_ch, LVecBase3f pos, double panic_distance,
+Flee::Flee(AICharacter *ai_ch, LVecBase3 pos, double panic_distance,
                                 double relax_distance, float flee_wt){
                                 double relax_distance, float flee_wt){
 
 
     _ai_char = ai_ch;
     _ai_char = ai_ch;
@@ -57,10 +57,10 @@ Flee::~Flee() {
 
 
 /////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////
 
 
-LVecBase3f Flee::do_flee() {
-  LVecBase3f dirn;
+LVecBase3 Flee::do_flee() {
+  LVecBase3 dirn;
   double distance;
   double distance;
-  LVecBase3f desired_force;
+  LVecBase3 desired_force;
 
 
   dirn = _ai_char->_ai_char_np.get_pos(_ai_char->_window_render) - _flee_present_pos;
   dirn = _ai_char->_ai_char_np.get_pos(_ai_char->_window_render) - _flee_present_pos;
   distance = dirn.length();
   distance = dirn.length();
@@ -68,12 +68,12 @@ LVecBase3f Flee::do_flee() {
 
 
   if(distance > (_flee_distance + _flee_relax_distance)) {
   if(distance > (_flee_distance + _flee_relax_distance)) {
     if((_ai_char->_steering->_behaviors_flags | _ai_char->_steering->_flee) == _ai_char->_steering->_flee) {
     if((_ai_char->_steering->_behaviors_flags | _ai_char->_steering->_flee) == _ai_char->_steering->_flee) {
-        _ai_char->_steering->_steering_force = LVecBase3f(0.0, 0.0, 0.0);
+        _ai_char->_steering->_steering_force = LVecBase3(0.0, 0.0, 0.0);
     }
     }
     _flee_done = true;
     _flee_done = true;
     _ai_char->_steering->turn_off("flee");
     _ai_char->_steering->turn_off("flee");
     _ai_char->_steering->turn_on("flee_activate");
     _ai_char->_steering->turn_on("flee_activate");
-    return(LVecBase3f(0.0, 0.0, 0.0));
+    return(LVecBase3(0.0, 0.0, 0.0));
   }
   }
   else {
   else {
       return(desired_force);
       return(desired_force);
@@ -90,7 +90,7 @@ LVecBase3f Flee::do_flee() {
 /////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////
 
 
 void Flee::flee_activate() {
 void Flee::flee_activate() {
-  LVecBase3f dirn;
+  LVecBase3 dirn;
   double distance;
   double distance;
 
 
   _flee_activate_done = false;
   _flee_activate_done = false;

+ 5 - 5
contrib/src/ai/flee.h

@@ -26,23 +26,23 @@ class EXPCL_PANDAAI Flee {
 public:
 public:
   AICharacter *_ai_char;
   AICharacter *_ai_char;
 
 
-  LVecBase3f _flee_position;
+  LVecBase3 _flee_position;
   float _flee_weight;
   float _flee_weight;
-  LVecBase3f _flee_direction;
+  LVecBase3 _flee_direction;
   double _flee_distance;
   double _flee_distance;
   double _flee_relax_distance;
   double _flee_relax_distance;
-  LVecBase3f _flee_present_pos;
+  LVecBase3 _flee_present_pos;
   bool _flee_done;
   bool _flee_done;
   bool _flee_activate_done;
   bool _flee_activate_done;
 
 
   Flee(AICharacter *ai_ch, NodePath target_object, double panic_distance = 10.0,
   Flee(AICharacter *ai_ch, NodePath target_object, double panic_distance = 10.0,
                               double relax_distance = 10.0, float flee_wt = 1.0);
                               double relax_distance = 10.0, float flee_wt = 1.0);
 
 
-  Flee(AICharacter *ai_ch, LVecBase3f pos, double panic_distance = 10.0,
+  Flee(AICharacter *ai_ch, LVecBase3 pos, double panic_distance = 10.0,
                               double relax_distance = 10.0, float flee_wt = 1.0);
                               double relax_distance = 10.0, float flee_wt = 1.0);
 
 
   ~Flee();
   ~Flee();
-  LVecBase3f do_flee();
+  LVecBase3 do_flee();
   void flee_activate();
   void flee_activate();
 };
 };
 
 

+ 1 - 1
contrib/src/ai/meshNode.cxx

@@ -1,7 +1,7 @@
 
 
 #include "meshNode.h"
 #include "meshNode.h"
 
 
-Node::Node(int grid_x, int grid_y, LVecBase3f pos, float w, float l, float h) {
+Node::Node(int grid_x, int grid_y, LVecBase3 pos, float w, float l, float h) {
   for(int i = 0; i < 8; ++i) {
   for(int i = 0; i < 8; ++i) {
     _neighbours[i] = NULL;
     _neighbours[i] = NULL;
   }
   }

+ 2 - 2
contrib/src/ai/meshNode.h

@@ -47,7 +47,7 @@ public:
     int _grid_x, _grid_y;
     int _grid_x, _grid_y;
 
 
     // Position of the node in 3D space.
     // Position of the node in 3D space.
-    LVecBase3f _position;
+    LVecBase3 _position;
 
 
     // Dimensions of each face / cell on the mesh.
     // Dimensions of each face / cell on the mesh.
     // Height is given in case of expansion to a 3d mesh. Currently not used.
     // Height is given in case of expansion to a 3d mesh. Currently not used.
@@ -58,7 +58,7 @@ public:
     // Note: The data in this member is discarded when mesh data is written into navmesh.csv file.
     // Note: The data in this member is discarded when mesh data is written into navmesh.csv file.
     Node *_next;
     Node *_next;
 
 
-    Node(int grid_x, int grid_y, LVecBase3f pos, float w, float l, float h);
+    Node(int grid_x, int grid_y, LVecBase3 pos, float w, float l, float h);
     ~Node();
     ~Node();
 
 
     bool contains(float x, float y);
     bool contains(float x, float y);

+ 15 - 15
contrib/src/ai/obstacleAvoidance.cxx

@@ -35,15 +35,15 @@ bool ObstacleAvoidance::obstacle_detection() {
   // Calculate the volume of the AICharacter with respect to render
   // Calculate the volume of the AICharacter with respect to render
   PT(BoundingVolume) np_bounds = _ai_char->get_node_path().get_bounds();
   PT(BoundingVolume) np_bounds = _ai_char->get_node_path().get_bounds();
   CPT(BoundingSphere) np_sphere = np_bounds->as_bounding_sphere();
   CPT(BoundingSphere) np_sphere = np_bounds->as_bounding_sphere();
-  LVecBase3f avoidance(0.0, 0.0, 0.0);
+  LVecBase3 avoidance(0.0, 0.0, 0.0);
   double distance = 0x7fff ;
   double distance = 0x7fff ;
   double expanded_radius;
   double expanded_radius;
-  LVecBase3f to_obstacle;
-  LVecBase3f prev_avoidance;
+  LVecBase3 to_obstacle;
+  LVecBase3 prev_avoidance;
   for(unsigned int i = 0; i < _ai_char->_world->_obstacles.size(); ++i) {
   for(unsigned int i = 0; i < _ai_char->_world->_obstacles.size(); ++i) {
     PT(BoundingVolume) bounds = _ai_char->_world->_obstacles[i].get_bounds();
     PT(BoundingVolume) bounds = _ai_char->_world->_obstacles[i].get_bounds();
     CPT(BoundingSphere) bsphere = bounds->as_bounding_sphere();
     CPT(BoundingSphere) bsphere = bounds->as_bounding_sphere();
-    LVecBase3f near_obstacle = _ai_char->_world->_obstacles[i].get_pos() - _ai_char->get_node_path().get_pos();
+    LVecBase3 near_obstacle = _ai_char->_world->_obstacles[i].get_pos() - _ai_char->get_node_path().get_pos();
     // Check if it's the nearest obstacle, If so initialize as the nearest obstacle
     // Check if it's the nearest obstacle, If so initialize as the nearest obstacle
     if((near_obstacle.length() < distance) && (_ai_char->_world->_obstacles[i].get_pos() != _ai_char->get_node_path().get_pos())) {
     if((near_obstacle.length() < distance) && (_ai_char->_world->_obstacles[i].get_pos() != _ai_char->get_node_path().get_pos())) {
       _nearest_obstacle = _ai_char->_world->_obstacles[i];
       _nearest_obstacle = _ai_char->_world->_obstacles[i];
@@ -51,13 +51,13 @@ bool ObstacleAvoidance::obstacle_detection() {
       expanded_radius = bsphere->get_radius() + np_sphere->get_radius();
       expanded_radius = bsphere->get_radius() + np_sphere->get_radius();
     }
     }
   }
   }
-     LVecBase3f feeler = _feeler * _ai_char->get_char_render().get_relative_vector(_ai_char->get_node_path(), LVector3f::forward());
+     LVecBase3 feeler = _feeler * _ai_char->get_char_render().get_relative_vector(_ai_char->get_node_path(), LVector3::forward());
      feeler.normalize();
      feeler.normalize();
      feeler *= (expanded_radius + np_sphere->get_radius()) ;
      feeler *= (expanded_radius + np_sphere->get_radius()) ;
      to_obstacle = _nearest_obstacle.get_pos() - _ai_char->get_node_path().get_pos();
      to_obstacle = _nearest_obstacle.get_pos() - _ai_char->get_node_path().get_pos();
-     LVector3f line_vector = _ai_char->get_char_render().get_relative_vector(_ai_char->get_node_path(), LVector3f::forward());
-     LVecBase3f project = (to_obstacle.dot(line_vector) * line_vector) / line_vector.length_squared();
-     LVecBase3f perp = project - to_obstacle;
+     LVector3 line_vector = _ai_char->get_char_render().get_relative_vector(_ai_char->get_node_path(), LVector3::forward());
+     LVecBase3 project = (to_obstacle.dot(line_vector) * line_vector) / line_vector.length_squared();
+     LVecBase3 perp = project - to_obstacle;
      // If the nearest obstacle will collide with our AICharacter then send obstacle detection as true
      // If the nearest obstacle will collide with our AICharacter then send obstacle detection as true
      if((_nearest_obstacle) && (perp.length() < expanded_radius - np_sphere->get_radius()) && (project.length() < feeler.length())) {
      if((_nearest_obstacle) && (perp.length() < expanded_radius - np_sphere->get_radius()) && (project.length() < feeler.length())) {
        return true;
        return true;
@@ -90,27 +90,27 @@ void ObstacleAvoidance::obstacle_avoidance_activate() {
 
 
 /////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////
 
 
-LVecBase3f ObstacleAvoidance::do_obstacle_avoidance() {
-  LVecBase3f offset = _ai_char->get_node_path().get_pos() - _nearest_obstacle.get_pos();
+LVecBase3 ObstacleAvoidance::do_obstacle_avoidance() {
+  LVecBase3 offset = _ai_char->get_node_path().get_pos() - _nearest_obstacle.get_pos();
   PT(BoundingVolume) bounds =_nearest_obstacle.get_bounds();
   PT(BoundingVolume) bounds =_nearest_obstacle.get_bounds();
   CPT(BoundingSphere) bsphere = bounds->as_bounding_sphere();
   CPT(BoundingSphere) bsphere = bounds->as_bounding_sphere();
   PT(BoundingVolume) np_bounds = _ai_char->get_node_path().get_bounds();
   PT(BoundingVolume) np_bounds = _ai_char->get_node_path().get_bounds();
   CPT(BoundingSphere) np_sphere = np_bounds->as_bounding_sphere();
   CPT(BoundingSphere) np_sphere = np_bounds->as_bounding_sphere();
   double distance_needed = offset.length() - bsphere->get_radius() - np_sphere->get_radius();
   double distance_needed = offset.length() - bsphere->get_radius() - np_sphere->get_radius();
   if((obstacle_detection())) {
   if((obstacle_detection())) {
-    LVecBase3f direction = _ai_char->get_char_render().get_relative_vector(_ai_char->get_node_path(), LVector3f::forward());
+    LVecBase3 direction = _ai_char->get_char_render().get_relative_vector(_ai_char->get_node_path(), LVector3::forward());
     direction.normalize();
     direction.normalize();
     float forward_component = offset.dot(direction);
     float forward_component = offset.dot(direction);
-    LVecBase3f projection = forward_component * direction;
-    LVecBase3f perpendicular_component = offset - projection;
+    LVecBase3 projection = forward_component * direction;
+    LVecBase3 perpendicular_component = offset - projection;
     double p = perpendicular_component.length();
     double p = perpendicular_component.length();
     perpendicular_component.normalize();
     perpendicular_component.normalize();
-    LVecBase3f   avoidance = perpendicular_component;
+    LVecBase3   avoidance = perpendicular_component;
     // The more closer the obstacle, the more force it generates
     // The more closer the obstacle, the more force it generates
     avoidance = (avoidance * _ai_char->get_max_force() * _ai_char->_movt_force) / (p + 0.01);
     avoidance = (avoidance * _ai_char->get_max_force() * _ai_char->_movt_force) / (p + 0.01);
     return avoidance;
     return avoidance;
   }
   }
   _ai_char->_steering->turn_on("obstacle_avoidance_activate");
   _ai_char->_steering->turn_on("obstacle_avoidance_activate");
   _ai_char->_steering->turn_off("obstacle_avoidance");
   _ai_char->_steering->turn_off("obstacle_avoidance");
-  return LVecBase3f(0, 0, 0);
+  return LVecBase3(0, 0, 0);
 }
 }

+ 1 - 1
contrib/src/ai/obstacleAvoidance.h

@@ -30,7 +30,7 @@ class EXPCL_PANDAAI ObstacleAvoidance {
     float _feeler;
     float _feeler;
 
 
     ObstacleAvoidance(AICharacter *ai_char, float feeler_length);
     ObstacleAvoidance(AICharacter *ai_char, float feeler_length);
-    LVecBase3f do_obstacle_avoidance();
+    LVecBase3 do_obstacle_avoidance();
     ~ObstacleAvoidance();
     ~ObstacleAvoidance();
     void obstacle_avoidance_activate();
     void obstacle_avoidance_activate();
     bool obstacle_detection();
     bool obstacle_detection();

+ 3 - 3
contrib/src/ai/pathFind.cxx

@@ -29,7 +29,7 @@ void PathFind::create_nav_mesh(const char* navmesh_filename) {
   // Stage variables.
   // Stage variables.
   int grid_x, grid_y;
   int grid_x, grid_y;
   float l, w, h;
   float l, w, h;
-  LVecBase3f position;
+  LVecBase3 position;
 
 
   // Variable to hold line data read from file.
   // Variable to hold line data read from file.
   string line;
   string line;
@@ -75,7 +75,7 @@ void PathFind::create_nav_mesh(const char* navmesh_filename) {
         l = atof(fields[4].c_str());
         l = atof(fields[4].c_str());
         w = atof(fields[5].c_str());
         w = atof(fields[5].c_str());
         h = atof(fields[6].c_str());
         h = atof(fields[6].c_str());
-        position = LVecBase3f(atof(fields[7].c_str()), atof(fields[8].c_str()), atof(fields[9].c_str()));
+        position = LVecBase3(atof(fields[7].c_str()), atof(fields[8].c_str()), atof(fields[9].c_str()));
 
 
         Node *stage_node = new Node(grid_x, grid_y, position, w, l, h);
         Node *stage_node = new Node(grid_x, grid_y, position, w, l, h);
 
 
@@ -197,7 +197,7 @@ void PathFind::set_path_find(const char* navmesh_filename) {
 ///////////////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////////////
 
 
 
 
-void PathFind::path_find(LVecBase3f pos, string type) {
+void PathFind::path_find(LVecBase3 pos, string type) {
   if(type == "addPath") {
   if(type == "addPath") {
     if(_ai_char->_steering->_path_follow_obj) {
     if(_ai_char->_steering->_path_follow_obj) {
       _ai_char->_steering->remove_ai("pathfollow");
       _ai_char->_steering->remove_ai("pathfollow");

+ 2 - 2
contrib/src/ai/pathFind.h

@@ -43,7 +43,7 @@ public:
 
 
   int _grid_size;
   int _grid_size;
   NodePath _path_find_target;
   NodePath _path_find_target;
-  LVecBase3f _prev_position;
+  LVecBase3 _prev_position;
   PT(GeomNode) _parent;
   PT(GeomNode) _parent;
   LineSegs *_pen;
   LineSegs *_pen;
   vector<int> _previous_obstacles;
   vector<int> _previous_obstacles;
@@ -62,7 +62,7 @@ public:
   void clear_previous_obstacles();
   void clear_previous_obstacles();
 
 
   void set_path_find(const char* navmesh_filename);
   void set_path_find(const char* navmesh_filename);
-  void path_find(LVecBase3f pos, string type = "normal");
+  void path_find(LVecBase3 pos, string type = "normal");
   void path_find(NodePath target, string type = "normal");
   void path_find(NodePath target, string type = "normal");
   void add_obstacle_to_mesh(NodePath obstacle);
   void add_obstacle_to_mesh(NodePath obstacle);
   void dynamic_avoid(NodePath obstacle);
   void dynamic_avoid(NodePath obstacle);

+ 2 - 2
contrib/src/ai/pathFollow.cxx

@@ -20,7 +20,7 @@ PathFollow::~PathFollow() {
 
 
 /////////////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////////////
 
 
-void PathFollow::add_to_path(LVecBase3f pos) {
+void PathFollow::add_to_path(LVecBase3 pos) {
     _path.push_back(pos);
     _path.push_back(pos);
 }
 }
 
 
@@ -119,7 +119,7 @@ void PathFollow::do_follow() {
 
 
 bool PathFollow::check_if_possible() {
 bool PathFollow::check_if_possible() {
   Node* src = find_in_mesh(_ai_char->_steering->_path_find_obj->_nav_mesh, _ai_char->_ai_char_np.get_pos(_ai_char->_window_render), _ai_char->_steering->_path_find_obj->_grid_size);
   Node* src = find_in_mesh(_ai_char->_steering->_path_find_obj->_nav_mesh, _ai_char->_ai_char_np.get_pos(_ai_char->_window_render), _ai_char->_steering->_path_find_obj->_grid_size);
-  LVecBase3f _prev_position = _ai_char->_steering->_path_find_obj->_path_find_target.get_pos(_ai_char->_window_render);
+  LVecBase3 _prev_position = _ai_char->_steering->_path_find_obj->_path_find_target.get_pos(_ai_char->_window_render);
   Node* dst = find_in_mesh(_ai_char->_steering->_path_find_obj->_nav_mesh, _prev_position, _ai_char->_steering->_path_find_obj->_grid_size);
   Node* dst = find_in_mesh(_ai_char->_steering->_path_find_obj->_nav_mesh, _prev_position, _ai_char->_steering->_path_find_obj->_grid_size);
 
 
   if(src && dst) {
   if(src && dst) {

+ 2 - 2
contrib/src/ai/pathFollow.h

@@ -13,7 +13,7 @@ class EXPCL_PANDAAI PathFollow {
 public:
 public:
   AICharacter *_ai_char;
   AICharacter *_ai_char;
   float _follow_weight;
   float _follow_weight;
-  vector<LVecBase3f> _path;
+  vector<LVecBase3> _path;
   int _curr_path_waypoint;
   int _curr_path_waypoint;
   bool _start;
   bool _start;
   NodePath _dummy;
   NodePath _dummy;
@@ -23,7 +23,7 @@ public:
 
 
   PathFollow(AICharacter *ai_ch, float follow_wt);
   PathFollow(AICharacter *ai_ch, float follow_wt);
   ~PathFollow();
   ~PathFollow();
-  void add_to_path(LVecBase3f pos);
+  void add_to_path(LVecBase3 pos);
   void start(string type);
   void start(string type);
   void do_follow();
   void do_follow();
   bool check_if_possible();
   bool check_if_possible();

+ 6 - 6
contrib/src/ai/pursue.cxx

@@ -37,17 +37,17 @@ Pursue::~Pursue() {
 
 
 /////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////
 
 
-LVecBase3f Pursue::do_pursue() {
+LVecBase3 Pursue::do_pursue() {
   assert(_pursue_target && "pursue target not assigned");
   assert(_pursue_target && "pursue target not assigned");
 
 
-  LVecBase3f present_pos = _ai_char->_ai_char_np.get_pos(_ai_char->_window_render);
+  LVecBase3 present_pos = _ai_char->_ai_char_np.get_pos(_ai_char->_window_render);
   double target_distance = (_pursue_target.get_pos(_ai_char->_window_render) - present_pos).length();
   double target_distance = (_pursue_target.get_pos(_ai_char->_window_render) - present_pos).length();
 
 
   if(int(target_distance) == 0) {
   if(int(target_distance) == 0) {
     _pursue_done = true;
     _pursue_done = true;
-    _ai_char->_steering->_steering_force = LVecBase3f(0.0, 0.0, 0.0);
-    _ai_char->_steering->_pursue_force = LVecBase3f(0.0, 0.0, 0.0);
-    return(LVecBase3f(0.0, 0.0, 0.0));
+    _ai_char->_steering->_steering_force = LVecBase3(0.0, 0.0, 0.0);
+    _ai_char->_steering->_pursue_force = LVecBase3(0.0, 0.0, 0.0);
+    return(LVecBase3(0.0, 0.0, 0.0));
   }
   }
   else {
   else {
     _pursue_done = false;
     _pursue_done = false;
@@ -56,6 +56,6 @@ LVecBase3f Pursue::do_pursue() {
   _pursue_direction = _pursue_target.get_pos(_ai_char->_window_render) - present_pos;
   _pursue_direction = _pursue_target.get_pos(_ai_char->_window_render) - present_pos;
   _pursue_direction.normalize();
   _pursue_direction.normalize();
 
 
-  LVecBase3f desired_force = _pursue_direction * _ai_char->_movt_force;
+  LVecBase3 desired_force = _pursue_direction * _ai_char->_movt_force;
   return(desired_force);
   return(desired_force);
 }
 }

+ 2 - 2
contrib/src/ai/pursue.h

@@ -28,12 +28,12 @@ public:
 
 
   NodePath _pursue_target;
   NodePath _pursue_target;
   float _pursue_weight;
   float _pursue_weight;
-  LVecBase3f _pursue_direction;
+  LVecBase3 _pursue_direction;
   bool _pursue_done;
   bool _pursue_done;
 
 
   Pursue(AICharacter *ai_ch, NodePath target_object, float pursue_wt);
   Pursue(AICharacter *ai_ch, NodePath target_object, float pursue_wt);
   ~Pursue();
   ~Pursue();
-  LVecBase3f do_pursue();
+  LVecBase3 do_pursue();
 };
 };
 
 
 #endif
 #endif

+ 5 - 5
contrib/src/ai/seek.cxx

@@ -27,7 +27,7 @@ Seek::Seek(AICharacter *ai_ch, NodePath target_object, float seek_wt) {
   _seek_done = false;
   _seek_done = false;
 }
 }
 
 
-Seek::Seek(AICharacter *ai_ch, LVecBase3f pos, float seek_wt) {
+Seek::Seek(AICharacter *ai_ch, LVecBase3 pos, float seek_wt) {
       _ai_char = ai_ch;
       _ai_char = ai_ch;
 
 
   _seek_position = pos;
   _seek_position = pos;
@@ -51,16 +51,16 @@ Seek::~Seek() {
 
 
 /////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////
 
 
-LVecBase3f Seek::do_seek() {
+LVecBase3 Seek::do_seek() {
   double target_distance = (_seek_position - _ai_char->_ai_char_np.get_pos(_ai_char->_window_render)).length();
   double target_distance = (_seek_position - _ai_char->_ai_char_np.get_pos(_ai_char->_window_render)).length();
 
 
     if(int(target_distance) == 0) {
     if(int(target_distance) == 0) {
         _seek_done = true;
         _seek_done = true;
-    _ai_char->_steering->_steering_force = LVecBase3f(0.0, 0.0, 0.0);
+    _ai_char->_steering->_steering_force = LVecBase3(0.0, 0.0, 0.0);
     _ai_char->_steering->turn_off("seek");
     _ai_char->_steering->turn_off("seek");
-    return(LVecBase3f(0.0, 0.0, 0.0));
+    return(LVecBase3(0.0, 0.0, 0.0));
   }
   }
 
 
-  LVecBase3f desired_force = _seek_direction * _ai_char->_movt_force;
+  LVecBase3 desired_force = _seek_direction * _ai_char->_movt_force;
   return(desired_force);
   return(desired_force);
 }
 }

+ 5 - 5
contrib/src/ai/seek.h

@@ -26,16 +26,16 @@ class EXPCL_PANDAAI Seek {
 public:
 public:
   AICharacter *_ai_char;
   AICharacter *_ai_char;
 
 
-  LVecBase3f _seek_position;
+  LVecBase3 _seek_position;
   float _seek_weight;
   float _seek_weight;
-  LVecBase3f _seek_direction;
+  LVecBase3 _seek_direction;
   bool _seek_done;
   bool _seek_done;
-  LVecBase3f _seek_accum_force;
+  LVecBase3 _seek_accum_force;
 
 
   Seek(AICharacter *ai_ch, NodePath target_object, float seek_wt = 1.0);
   Seek(AICharacter *ai_ch, NodePath target_object, float seek_wt = 1.0);
-  Seek(AICharacter *ai_ch, LVecBase3f pos, float seek_wt = 1.0);
+  Seek(AICharacter *ai_ch, LVecBase3 pos, float seek_wt = 1.0);
   ~Seek();
   ~Seek();
-  LVecBase3f do_seek();
+  LVecBase3 do_seek();
 };
 };
 
 
 #endif
 #endif

+ 18 - 18
contrib/src/ai/wander.cxx

@@ -57,23 +57,23 @@ Wander::Wander(AICharacter *ai_ch, double wander_radius,int flag, double aoe, fl
   // default is XY axes
   // default is XY axes
   switch(_flag) {
   switch(_flag) {
     case 0: {
     case 0: {
-              _wander_target = LVecBase3f(_wander_radius * cos(theta), _wander_radius * sin(theta),0);
+              _wander_target = LVecBase3(_wander_radius * cos(theta), _wander_radius * sin(theta),0);
               break;
               break;
             }
             }
     case 1: {
     case 1: {
-              _wander_target = LVecBase3f(0, _wander_radius * cos(theta), _wander_radius * sin(theta));
+              _wander_target = LVecBase3(0, _wander_radius * cos(theta), _wander_radius * sin(theta));
               break;
               break;
             }
             }
     case 2: {
     case 2: {
-              _wander_target = LVecBase3f(_wander_radius * cos(theta), 0,  _wander_radius * sin(theta));
+              _wander_target = LVecBase3(_wander_radius * cos(theta), 0,  _wander_radius * sin(theta));
               break;
               break;
             }
             }
     case 3: {
     case 3: {
-              _wander_target = LVecBase3f(_wander_radius * sin(theta) * cos(si), _wander_radius * sin(theta) * sin(si), _wander_radius * cos(theta));
+              _wander_target = LVecBase3(_wander_radius * sin(theta) * cos(si), _wander_radius * sin(theta) * sin(si), _wander_radius * cos(theta));
               break;
               break;
             }
             }
     default: {
     default: {
-              _wander_target = LVecBase3f(_wander_radius * cos(theta), _wander_radius * sin(theta),0);
+              _wander_target = LVecBase3(_wander_radius * cos(theta), _wander_radius * sin(theta),0);
               break;
               break;
              }
              }
   }
   }
@@ -91,52 +91,52 @@ Wander::~Wander() {
 
 
 /////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////
 
 
-LVecBase3f Wander::do_wander() {
-  LVecBase3f present_pos = _ai_char->get_node_path().get_pos(_ai_char->get_char_render());
+LVecBase3 Wander::do_wander() {
+  LVecBase3 present_pos = _ai_char->get_node_path().get_pos(_ai_char->get_char_render());
   // Create the random slices to enable random movement of wander for x,y,z respectively
   // Create the random slices to enable random movement of wander for x,y,z respectively
   double time_slice_1 = random_clamped() * 1.5;
   double time_slice_1 = random_clamped() * 1.5;
   double time_slice_2 = random_clamped() * 1.5;
   double time_slice_2 = random_clamped() * 1.5;
   double time_slice_3 = random_clamped() * 1.5;
   double time_slice_3 = random_clamped() * 1.5;
   switch(_flag) {
   switch(_flag) {
   case 0: {
   case 0: {
-            _wander_target += LVecBase3f(time_slice_1, time_slice_2, 0);
+            _wander_target += LVecBase3(time_slice_1, time_slice_2, 0);
             break;
             break;
           }
           }
   case 1: {
   case 1: {
-            _wander_target += LVecBase3f(0, time_slice_1, time_slice_2);
+            _wander_target += LVecBase3(0, time_slice_1, time_slice_2);
             break;
             break;
           }
           }
   case 2: {
   case 2: {
-            _wander_target += LVecBase3f(time_slice_1, 0, time_slice_2);
+            _wander_target += LVecBase3(time_slice_1, 0, time_slice_2);
             break;
             break;
           }
           }
   case 3: {
   case 3: {
-            _wander_target += LVecBase3f(time_slice_1, time_slice_2, time_slice_3);
+            _wander_target += LVecBase3(time_slice_1, time_slice_2, time_slice_3);
             break;
             break;
           }
           }
 
 
   default: {
   default: {
-            _wander_target = LVecBase3f(time_slice_1, time_slice_2, 0);
+            _wander_target = LVecBase3(time_slice_1, time_slice_2, 0);
            }
            }
   }
   }
   _wander_target.normalize();
   _wander_target.normalize();
   _wander_target *= _wander_radius;
   _wander_target *= _wander_radius;
-  LVecBase3f target = _ai_char->get_char_render().get_relative_vector(_ai_char->get_node_path(), LVector3f::forward());
+  LVecBase3 target = _ai_char->get_char_render().get_relative_vector(_ai_char->get_node_path(), LVector3::forward());
   target.normalize();
   target.normalize();
   // Project wander target onto global space
   // Project wander target onto global space
   target = _wander_target + target;
   target = _wander_target + target;
-  LVecBase3f desired_target = present_pos + target;
-  LVecBase3f desired_force = desired_target - _ai_char->get_node_path().get_pos() ;
+  LVecBase3 desired_target = present_pos + target;
+  LVecBase3 desired_force = desired_target - _ai_char->get_node_path().get_pos() ;
   desired_force.normalize();
   desired_force.normalize();
   desired_force *= _ai_char->_movt_force;
   desired_force *= _ai_char->_movt_force;
   double distance = (present_pos - _init_pos).length();
   double distance = (present_pos - _init_pos).length();
   if(_area_of_effect > 0 && distance > _area_of_effect) {
   if(_area_of_effect > 0 && distance > _area_of_effect) {
-    LVecBase3f direction = present_pos - _init_pos;
+    LVecBase3 direction = present_pos - _init_pos;
     direction.normalize();
     direction.normalize();
     desired_force =  - direction * _ai_char->_movt_force;
     desired_force =  - direction * _ai_char->_movt_force;
-    LVecBase3f dirn = _ai_char->_steering->_steering_force;
+    LVecBase3 dirn = _ai_char->_steering->_steering_force;
     dirn.normalize();
     dirn.normalize();
-    _ai_char->_steering->_steering_force = LVecBase3f(0.0, 0.0, 0.0);
+    _ai_char->_steering->_steering_force = LVecBase3(0.0, 0.0, 0.0);
   }
   }
   return desired_force;
   return desired_force;
 }
 }

+ 3 - 3
contrib/src/ai/wander.h

@@ -24,14 +24,14 @@ class EXPCL_PANDAAI Wander {
   public:
   public:
     AICharacter *_ai_char;
     AICharacter *_ai_char;
     double _wander_radius;
     double _wander_radius;
-    LVecBase3f _wander_target;
+    LVecBase3 _wander_target;
     float _wander_weight;
     float _wander_weight;
     int _flag;
     int _flag;
-    LVecBase3f _init_pos;
+    LVecBase3 _init_pos;
     double _area_of_effect;
     double _area_of_effect;
 
 
     Wander(AICharacter *ai_ch, double wander_radius, int flag, double aoe, float wander_weight);
     Wander(AICharacter *ai_ch, double wander_radius, int flag, double aoe, float wander_weight);
-    LVecBase3f do_wander();
+    LVecBase3 do_wander();
     ~Wander();
     ~Wander();
 };
 };
 
 

+ 0 - 5
direct/src/actor/Actor.py

@@ -1019,11 +1019,6 @@ class Actor(DirectObject, NodePath):
         if (partName in partDict):
         if (partName in partDict):
             del(partDict[partName])
             del(partDict[partName])
 
 
-        # remove the bundle handle, in case this part is ever
-        # loaded again in the future
-        if partName in self.__commonBundleHandles:
-            del self.__commonBundleHandles[partName]
-
     def hidePart(self, partName, lodName="lodRoot"):
     def hidePart(self, partName, lodName="lodRoot"):
         """
         """
         Make the given part of the optionally given lod not render,
         Make the given part of the optionally given lod not render,

+ 2 - 1
direct/src/directbase/DirectStart.py

@@ -1,4 +1,5 @@
-print 'DirectStart: Starting the game.'
+__all__ = []
+print('Using deprecated DirectStart interface.')
 
 
 from direct.showbase import ShowBase
 from direct.showbase import ShowBase
 base = ShowBase.ShowBase()
 base = ShowBase.ShowBase()

+ 2 - 0
direct/src/directnotify/DirectNotifyGlobal.py

@@ -1,5 +1,7 @@
 """instantiate global DirectNotify used in Direct"""
 """instantiate global DirectNotify used in Direct"""
 
 
+__all__ = ['directNotify', 'giveNotify']
+
 import DirectNotify
 import DirectNotify
 
 
 directNotify = DirectNotify.DirectNotify()
 directNotify = DirectNotify.DirectNotify()

+ 2 - 2
direct/src/directscripts/Doxyfile.python

@@ -760,13 +760,13 @@ STRIP_CODE_COMMENTS    = YES
 # then for each documented function all documented 
 # then for each documented function all documented 
 # functions referencing it will be listed.
 # functions referencing it will be listed.
 
 
-REFERENCED_BY_RELATION = YES
+REFERENCED_BY_RELATION = NO
 
 
 # If the REFERENCES_RELATION tag is set to YES 
 # If the REFERENCES_RELATION tag is set to YES 
 # then for each documented function all documented entities 
 # then for each documented function all documented entities 
 # called/used by that function will be listed.
 # called/used by that function will be listed.
 
 
-REFERENCES_RELATION    = YES
+REFERENCES_RELATION    = NO
 
 
 # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) 
 # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) 
 # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from 
 # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from 

+ 111 - 50
direct/src/directscripts/extract_docs.py

@@ -30,6 +30,7 @@ def comment(code):
             if empty_line:
             if empty_line:
                 # New paragraph.
                 # New paragraph.
                 comment += '\n\n'
                 comment += '\n\n'
+                empty_line = False
             elif comment:
             elif comment:
                 comment += '\n'
                 comment += '\n'
             comment += '/// ' + line
             comment += '/// ' + line
@@ -56,15 +57,29 @@ def block_comment(code):
 
 
         line = line.rstrip()
         line = line.rstrip()
         strline = line.lstrip('/ \t')
         strline = line.lstrip('/ \t')
-        if reading_desc:
-            newlines.append('/// ' + line[min(indent, len(line) - len(strline)):])
-        else:
-            # A "Description:" text starts the description.
-            if strline.startswith("Description"):
-                strline = strline[11:].lstrip(': \t')
-                indent = len(line) - len(strline)
-                reading_desc = True
-                newlines.append('/// ' + strline)
+
+        if ':' in strline:
+            pre, post = strline.split(':', 1)
+            pre = pre.rstrip()
+            if pre == "Description":
+                strline = post.lstrip()
+            elif pre in ("Class", "Access", "Function", "Created by", "Enum"):
+                continue
+
+        if strline or len(newlines) > 0:
+            newlines.append('/// ' + strline)
+
+        #if reading_desc:
+        #    newlines.append('/// ' + line[min(indent, len(line) - len(strline)):])
+        #else:
+        #    # A "Description:" text starts the description.
+        #    if strline.startswith("Description"):
+        #        strline = strline[11:].lstrip(': \t')
+        #        indent = len(line) - len(strline)
+        #        reading_desc = True
+        #        newlines.append('/// ' + strline)
+        #    else:
+        #        print line
 
 
     newcode = '\n'.join(newlines)
     newcode = '\n'.join(newlines)
     if len(newcode) > 0:
     if len(newcode) > 0:
@@ -73,6 +88,9 @@ def block_comment(code):
         return ""
         return ""
 
 
 def translateFunctionName(name):
 def translateFunctionName(name):
+    if name.startswith("__"):
+        return name
+
     new = ""
     new = ""
     for i in name.split("_"):
     for i in name.split("_"):
         if new == "":
         if new == "":
@@ -85,32 +103,58 @@ def translateFunctionName(name):
             new += i[0].upper() + i[1:]
             new += i[0].upper() + i[1:]
     return new
     return new
 
 
-def translated_type_name(type):
+def translateTypeName(name, mangle=True):
+    # Equivalent to C++ classNameFromCppName
+    class_name = ""
+    bad_chars = "!@#$%^&*()<>,.-=+~{}? "
+    next_cap = False
+    first_char = mangle
+
+    for chr in name:
+        if (chr == '_' or chr == ' ') and mangle:
+            next_cap = True
+        elif chr in bad_chars:
+            if not mangle:
+                class_name += '_'
+        elif next_cap or first_char:
+            class_name += chr.upper()
+            next_cap = False
+            first_char = False
+        else:
+            class_name += chr
+
+    return class_name
+
+def translated_type_name(type, scoped=True):
+    while interrogate_type_is_wrapped(type):
+        if interrogate_type_is_const(type):
+            return 'const ' + translated_type_name(interrogate_type_wrapped_type(type))
+        else:
+            type = interrogate_type_wrapped_type(type)
+
+    typename = interrogate_type_name(type)
+    if typename in ("PyObject", "_object"):
+        return "object"
+
     if interrogate_type_is_atomic(type):
     if interrogate_type_is_atomic(type):
         token = interrogate_type_atomic_token(type)
         token = interrogate_type_atomic_token(type)
         if token == 7:
         if token == 7:
             return 'str'
             return 'str'
+        else:
+            return typename
 
 
-    typename = interrogate_type_name(type)
-    typename = typename.replace("< ", "").replace(" >", "")
-    return typename
-
-def translateTypeSpec(name):
-    name = name.strip("* ")
-    name = name.replace("BitMask< unsigned int, 32 >", "BitMask32")
-    name = name.replace("atomic ", "")
-    name = name.replace("< ", "").replace(" >", "")
-    if name == '_object':
-        name = 'object'
-    elif name == '_typeobject':
-        name = 'type'
-    return name
+    typename = translateTypeName(typename)
+
+    if scoped and interrogate_type_is_nested(type):
+        return translated_type_name(interrogate_type_outer_class(type)) + '::' + typename
+    else:
+        return typename
 
 
 def processElement(handle, element):
 def processElement(handle, element):
     if interrogate_element_has_comment(element):
     if interrogate_element_has_comment(element):
         print >>handle, comment(interrogate_element_comment(element))
         print >>handle, comment(interrogate_element_comment(element))
 
 
-    print >>handle, translateTypeSpec(translated_type_name(interrogate_element_type(element))),
+    print >>handle, translated_type_name(interrogate_element_type(element)),
     print >>handle, interrogate_element_name(element) + ';'
     print >>handle, interrogate_element_name(element) + ';'
 
 
 def processFunction(handle, function, isConstructor = False):
 def processFunction(handle, function, isConstructor = False):
@@ -120,11 +164,12 @@ def processFunction(handle, function, isConstructor = False):
             print >>handle, block_comment(interrogate_wrapper_comment(wrapper))
             print >>handle, block_comment(interrogate_wrapper_comment(wrapper))
         
         
         if not isConstructor:
         if not isConstructor:
-            if not interrogate_wrapper_number_of_parameters(wrapper) > 0 or not interrogate_wrapper_parameter_is_this(wrapper, 0):
-                print >>handle, "static",
+            if interrogate_function_is_method(function):
+                if not interrogate_wrapper_number_of_parameters(wrapper) > 0 or not interrogate_wrapper_parameter_is_this(wrapper, 0):
+                    print >>handle, "static",
             
             
             if interrogate_wrapper_has_return_value(wrapper):
             if interrogate_wrapper_has_return_value(wrapper):
-                print >>handle, translateTypeSpec(translated_type_name(interrogate_wrapper_return_type(wrapper))),
+                print >>handle, translated_type_name(interrogate_wrapper_return_type(wrapper)),
             else:
             else:
                 pass#print >>handle, "void",
                 pass#print >>handle, "void",
 
 
@@ -137,7 +182,7 @@ def processFunction(handle, function, isConstructor = False):
             if not interrogate_wrapper_parameter_is_this(wrapper, i_param):
             if not interrogate_wrapper_parameter_is_this(wrapper, i_param):
                 if not first:
                 if not first:
                     print >>handle, ",",
                     print >>handle, ",",
-                print >>handle, translateTypeSpec(translated_type_name(interrogate_wrapper_parameter_type(wrapper, i_param))),
+                print >>handle, translated_type_name(interrogate_wrapper_parameter_type(wrapper, i_param)),
                 if interrogate_wrapper_parameter_has_name(wrapper, i_param):
                 if interrogate_wrapper_parameter_has_name(wrapper, i_param):
                     print >>handle, interrogate_wrapper_parameter_name(wrapper, i_param),
                     print >>handle, interrogate_wrapper_parameter_name(wrapper, i_param),
                 first = False
                 first = False
@@ -145,7 +190,7 @@ def processFunction(handle, function, isConstructor = False):
         print >>handle, ");"
         print >>handle, ");"
 
 
 def processType(handle, type):
 def processType(handle, type):
-    typename = translated_type_name(type)
+    typename = translated_type_name(type, scoped=False)
     derivations = [ translated_type_name(interrogate_type_get_derivation(type, n)) for n in range(interrogate_type_number_of_derivations(type)) ]
     derivations = [ translated_type_name(interrogate_type_get_derivation(type, n)) for n in range(interrogate_type_number_of_derivations(type)) ]
     
     
     if interrogate_type_has_comment(type):
     if interrogate_type_has_comment(type):
@@ -157,7 +202,7 @@ def processType(handle, type):
             docstring = comment(interrogate_type_enum_value_comment(type, i_value))
             docstring = comment(interrogate_type_enum_value_comment(type, i_value))
             if docstring:
             if docstring:
                 print >>handle, docstring
                 print >>handle, docstring
-            print >>handle, translateFunctionName(interrogate_type_enum_value_name(type, i_value)), "=", interrogate_type_enum_value(type, i_value), ","
+            print >>handle, interrogate_type_enum_value_name(type, i_value), "=", interrogate_type_enum_value(type, i_value), ","
     else:
     else:
         if interrogate_type_is_struct(type):
         if interrogate_type_is_struct(type):
             classtype = "struct"
             classtype = "struct"
@@ -192,38 +237,54 @@ def processType(handle, type):
     
     
     print >>handle, "};"
     print >>handle, "};"
 
 
+def processModule(handle, package):
+    print >>handle, "namespace %s {" % package
+
+    if package != "core":
+        print >>handle, "using namespace core;"
+
+    for i_type in xrange(interrogate_number_of_global_types()):
+        type = interrogate_get_global_type(i_type)
+
+        if interrogate_type_has_module_name(type):
+            module_name = interrogate_type_module_name(type)
+            if "panda3d." + package == module_name:
+                processType(handle, type)
+        else:
+            print "Type %s has no module name" % typename
+
+    for i_func in xrange(interrogate_number_of_global_functions()):
+        func = interrogate_get_global_function(i_func)
+
+        if interrogate_function_has_module_name(func):
+            module_name = interrogate_function_module_name(func)
+            if "panda3d." + package == module_name:
+                processFunction(handle, func)
+        else:
+            print "Type %s has no module name" % typename
+
+    print >>handle, "}"
+
+
 if __name__ == "__main__":
 if __name__ == "__main__":
     handle = open("pandadoc.hpp", "w")
     handle = open("pandadoc.hpp", "w")
     
     
     print >>handle, comment("Panda3D modules that are implemented in C++.")
     print >>handle, comment("Panda3D modules that are implemented in C++.")
-    print >>handle, "namespace panda3d {}"
+    print >>handle, "namespace panda3d {"
     
     
     # Determine the path to the interrogatedb files
     # Determine the path to the interrogatedb files
     interrogate_add_search_directory(os.path.join(os.path.dirname(pandac.__file__), "..", "..", "etc"))
     interrogate_add_search_directory(os.path.join(os.path.dirname(pandac.__file__), "..", "..", "etc"))
     interrogate_add_search_directory(os.path.join(os.path.dirname(pandac.__file__), "input"))
     interrogate_add_search_directory(os.path.join(os.path.dirname(pandac.__file__), "input"))
 
 
     import panda3d.core
     import panda3d.core
+    processModule(handle, "core")
 
 
     for lib in os.listdir(os.path.dirname(panda3d.__file__)):
     for lib in os.listdir(os.path.dirname(panda3d.__file__)):
         if lib.endswith(('.pyd', '.so')) and not lib.startswith('core.'):
         if lib.endswith(('.pyd', '.so')) and not lib.startswith('core.'):
-            __import__('panda3d.' + os.path.splitext(lib)[0])
+            module_name = os.path.splitext(lib)[0]
+            __import__("panda3d." + module_name)
+            processModule(handle, module_name)
 
 
-    lastpkg = None
-    for i_type in xrange(interrogate_number_of_global_types()):
-        type = interrogate_get_global_type(i_type)
 
 
-        if interrogate_type_has_module_name(type):
-            package = interrogate_type_module_name(type)
-            if lastpkg != package:
-                if lastpkg is not None:
-                    print >>handle, "}"
-                print >>handle, "namespace %s {" % package
-                lastpkg = package
-
-            processType(handle, type)
-        else:
-            print "Type %s has no module name" % typename
-    
-    if lastpkg is not None:
-        print >>handle, "}"
+    print >>handle, "}"
     handle.close()
     handle.close()

+ 4 - 4
direct/src/distributed/ConnectionRepository.py

@@ -491,7 +491,7 @@ class ConnectionRepository(
         elif self.connectMethod == self.CM_NET or (not hasattr(self,"connectNative")):
         elif self.connectMethod == self.CM_NET or (not hasattr(self,"connectNative")):
             # Try each of the servers in turn.
             # Try each of the servers in turn.
             for url in serverList:
             for url in serverList:
-                self.notify.info("Connecting to %s via NET interface." % (url.cStr()))
+                self.notify.info("Connecting to %s via NET interface." % (url))
                 if self.tryConnectNet(url):
                 if self.tryConnectNet(url):
                     self.startReaderPollTask()
                     self.startReaderPollTask()
                     if successCallback:
                     if successCallback:
@@ -503,7 +503,7 @@ class ConnectionRepository(
                 failureCallback(0, '', *failureArgs)
                 failureCallback(0, '', *failureArgs)
         elif self.connectMethod == self.CM_NATIVE:
         elif self.connectMethod == self.CM_NATIVE:
             for url in serverList:
             for url in serverList:
-                self.notify.info("Connecting to %s via Native interface." % (url.cStr()))
+                self.notify.info("Connecting to %s via Native interface." % (url))
                 if self.connectNative(url):
                 if self.connectNative(url):
                     self.startReaderPollTask()
                     self.startReaderPollTask()
                     if successCallback:
                     if successCallback:
@@ -536,7 +536,7 @@ class ConnectionRepository(
         if ch.isConnectionReady():
         if ch.isConnectionReady():
             self.setConnectionHttp(ch)
             self.setConnectionHttp(ch)
             self._serverAddress = serverList[serverIndex-1]
             self._serverAddress = serverList[serverIndex-1]
-            self.notify.info("Successfully connected to %s." % (self._serverAddress.cStr()))
+            self.notify.info("Successfully connected to %s." % (self._serverAddress))
 
 
             ## if self.recorder:
             ## if self.recorder:
             ##     # If we have a recorder, we wrap the connect inside a
             ##     # If we have a recorder, we wrap the connect inside a
@@ -562,7 +562,7 @@ class ConnectionRepository(
             # No connection yet, but keep trying.
             # No connection yet, but keep trying.
 
 
             url = serverList[serverIndex]
             url = serverList[serverIndex]
-            self.notify.info("Connecting to %s via HTTP interface." % (url.cStr()))
+            self.notify.info("Connecting to %s via HTTP interface." % (url))
             ch.preserveStatus()
             ch.preserveStatus()
 
 
             ch.beginConnectTo(DocumentSpec(url))
             ch.beginConnectTo(DocumentSpec(url))

+ 1 - 1
direct/src/distributed/DistributedCartesianGrid.py

@@ -250,7 +250,7 @@ class DistributedCartesianGrid(DistributedNode, CartesianGridBase):
         assert self.notify.debug("removeObjectFromGrid %s" % av)
         assert self.notify.debug("removeObjectFromGrid %s" % av)
         # TODO: WHAT LOCATION SHOULD WE SET THIS TO?
         # TODO: WHAT LOCATION SHOULD WE SET THIS TO?
         #av.reparentTo(hidden)
         #av.reparentTo(hidden)
-        if (av.getParent().compareTo(self) == 0):
+        if av.getParent() == self:
             # only detach if object is directly parented
             # only detach if object is directly parented
             av.detachNode()
             av.detachNode()
         #av.b_setLocation(0, 0)
         #av.b_setLocation(0, 0)

+ 0 - 9
direct/src/extensions/ConfigVariableFilename-extensions.py

@@ -1,9 +0,0 @@
-
-    def __str__(self):
-        return self.cStr()
-
-    def __len__(self):
-        return self.length()
-    
-    def __getitem__(self, n):
-        return self.cStr().__getitem__(n)

+ 1 - 1
direct/src/extensions/HTTPChannel-extensions.py

@@ -14,7 +14,7 @@
         Returns the newly-spawned task.
         Returns the newly-spawned task.
         """
         """
         if not name:
         if not name:
-            name = self.getUrl().cStr()
+            name = str(self.getUrl())
         from direct.task import Task
         from direct.task import Task
         task = Task.Task(self.doTask)
         task = Task.Task(self.doTask)
         task.callback = callback
         task.callback = callback

+ 1 - 1
direct/src/extensions_native/HTTPChannel_extensions.py

@@ -18,7 +18,7 @@ def spawnTask(self, name = None, callback = None, extraArgs = []):
         Returns the newly-spawned task.
         Returns the newly-spawned task.
         """
         """
         if not name:
         if not name:
-            name = self.getUrl().cStr()
+            name = str(self.getUrl())
         from direct.task import Task
         from direct.task import Task
         task = Task.Task(self.doTask)
         task = Task.Task(self.doTask)
         task.callback = callback
         task.callback = callback

+ 8 - 9
direct/src/filter/CommonFilters.py

@@ -16,11 +16,10 @@ clunky approach.  - Josh
 """
 """
 
 
 from FilterManager import FilterManager
 from FilterManager import FilterManager
-from pandac.PandaModules import Point3, Vec3, Vec4, Point2
-from pandac.PandaModules import NodePath, PandaNode
-from pandac.PandaModules import Filename
-from pandac.PandaModules import AuxBitplaneAttrib
-from pandac.PandaModules import RenderState, Texture, Shader, ATSNone
+from panda3d.core import LVecBase4, LPoint2
+from panda3d.core import Filename
+from panda3d.core import AuxBitplaneAttrib
+from panda3d.core import RenderState, Texture, Shader, ATSNone
 import sys,os
 import sys,os
 
 
 CARTOON_BODY="""
 CARTOON_BODY="""
@@ -348,13 +347,13 @@ class CommonFilters:
         if (changed == "CartoonInk") or fullrebuild:
         if (changed == "CartoonInk") or fullrebuild:
             if ("CartoonInk" in configuration):
             if ("CartoonInk" in configuration):
                 c = configuration["CartoonInk"]
                 c = configuration["CartoonInk"]
-                self.finalQuad.setShaderInput("cartoonseparation", Vec4(c.separation, 0, c.separation, 0))
+                self.finalQuad.setShaderInput("cartoonseparation", LVecBase4(c.separation, 0, c.separation, 0))
                 self.finalQuad.setShaderInput("cartooncolor", c.color)
                 self.finalQuad.setShaderInput("cartooncolor", c.color)
 
 
         if (changed == "BlurSharpen") or fullrebuild:
         if (changed == "BlurSharpen") or fullrebuild:
             if ("BlurSharpen" in configuration):
             if ("BlurSharpen" in configuration):
                 blurval = configuration["BlurSharpen"]
                 blurval = configuration["BlurSharpen"]
-                self.finalQuad.setShaderInput("blurval", Vec4(blurval, blurval, blurval, blurval))
+                self.finalQuad.setShaderInput("blurval", LVecBase4(blurval, blurval, blurval, blurval))
 
 
         if (changed == "Bloom") or fullrebuild:
         if (changed == "Bloom") or fullrebuild:
             if ("Bloom" in configuration):
             if ("Bloom" in configuration):
@@ -386,9 +385,9 @@ class CommonFilters:
 
 
         if "VolumetricLighting" in self.configuration:
         if "VolumetricLighting" in self.configuration:
             caster = self.configuration["VolumetricLighting"].caster
             caster = self.configuration["VolumetricLighting"].caster
-            casterpos = Point2()
+            casterpos = LPoint2()
             self.manager.camera.node().getLens().project(caster.getPos(self.manager.camera), casterpos)
             self.manager.camera.node().getLens().project(caster.getPos(self.manager.camera), casterpos)
-            self.finalQuad.setShaderInput("casterpos", Vec4(casterpos.getX() * 0.5 + 0.5, (casterpos.getY() * 0.5 + 0.5), 0, 0))
+            self.finalQuad.setShaderInput("casterpos", LVecBase4(casterpos.getX() * 0.5 + 0.5, (casterpos.getY() * 0.5 + 0.5), 0, 0))
         if task != None:
         if task != None:
             return task.cont
             return task.cont
 
 

+ 21 - 22
direct/src/filter/FilterManager.py

@@ -14,16 +14,15 @@ Still need to implement:
 
 
 """
 """
 
 
-from pandac.PandaModules import Point3, Vec3, Vec4
-from pandac.PandaModules import NodePath, PandaNode
-from pandac.PandaModules import RenderState, Texture, Shader
-from pandac.PandaModules import CardMaker
-from pandac.PandaModules import TextureStage
-from pandac.PandaModules import GraphicsPipe, GraphicsOutput
-from pandac.PandaModules import WindowProperties, FrameBufferProperties
-from pandac.PandaModules import Camera, DisplayRegion
-from pandac.PandaModules import OrthographicLens
-from pandac.PandaModules import AuxBitplaneAttrib
+from panda3d.core import NodePath, PandaNode
+from panda3d.core import RenderState, Texture, Shader
+from panda3d.core import CardMaker
+from panda3d.core import TextureStage
+from panda3d.core import GraphicsPipe, GraphicsOutput
+from panda3d.core import WindowProperties, FrameBufferProperties
+from panda3d.core import Camera, DisplayRegion
+from panda3d.core import OrthographicLens
+from panda3d.core import AuxBitplaneAttrib
 from direct.directnotify.DirectNotifyGlobal import *
 from direct.directnotify.DirectNotifyGlobal import *
 from direct.showbase.DirectObject import DirectObject
 from direct.showbase.DirectObject import DirectObject
 
 
@@ -111,16 +110,16 @@ class FilterManager(DirectObject):
 
 
         winx = self.forcex
         winx = self.forcex
         winy = self.forcey
         winy = self.forcey
-        if (winx == 0): winx = self.win.getXSize()
-        if (winy == 0): winy = self.win.getYSize()
+        if winx == 0: winx = self.win.getXSize()
+        if winy == 0: winy = self.win.getYSize()
 
 
-        if (div != 1):
-            winx = ((winx+align-1) / align) * align
-            winy = ((winy+align-1) / align) * align
-            winx = winx / div
-            winy = winy / div
+        if div != 1:
+            winx = ((winx+align-1) // align) * align
+            winy = ((winy+align-1) // align) * align
+            winx = winx // div
+            winy = winy // div
 
 
-        if (mul != 1):
+        if mul != 1:
             winx = winx * mul
             winx = winx * mul
             winy = winy * mul
             winy = winy * mul
 
 
@@ -198,7 +197,7 @@ class FilterManager(DirectObject):
         quad.setDepthTest(0)
         quad.setDepthTest(0)
         quad.setDepthWrite(0)
         quad.setDepthWrite(0)
         quad.setTexture(colortex)
         quad.setTexture(colortex)
-        quad.setColor(Vec4(1,0.5,0.5,1))
+        quad.setColor(1, 0.5, 0.5, 1)
 
 
         cs = NodePath("dummy")
         cs = NodePath("dummy")
         cs.setState(self.camstate)
         cs.setState(self.camstate)
@@ -221,7 +220,7 @@ class FilterManager(DirectObject):
         self.setStackedClears(buffer, self.rclears, self.wclears)
         self.setStackedClears(buffer, self.rclears, self.wclears)
         if (auxtex0):
         if (auxtex0):
             buffer.setClearActive(GraphicsOutput.RTPAuxRgba0, 1)
             buffer.setClearActive(GraphicsOutput.RTPAuxRgba0, 1)
-            buffer.setClearValue(GraphicsOutput.RTPAuxRgba0, Vec4(0.5, 0.5, 1.0, 0.0))
+            buffer.setClearValue(GraphicsOutput.RTPAuxRgba0, (0.5, 0.5, 1.0, 0.0))
         if (auxtex1):
         if (auxtex1):
             buffer.setClearActive(GraphicsOutput.RTPAuxRgba1, 1)
             buffer.setClearActive(GraphicsOutput.RTPAuxRgba1, 1)
         self.region.disableClears()
         self.region.disableClears()
@@ -262,7 +261,7 @@ class FilterManager(DirectObject):
         quad = NodePath(cm.generate())
         quad = NodePath(cm.generate())
         quad.setDepthTest(0)
         quad.setDepthTest(0)
         quad.setDepthWrite(0)
         quad.setDepthWrite(0)
-        quad.setColor(Vec4(1,0.5,0.5,1))
+        quad.setColor(1, 0.5, 0.5, 1)
 
 
         quadcamnode = Camera("filter-quad-cam")
         quadcamnode = Camera("filter-quad-cam")
         lens = OrthographicLens()
         lens = OrthographicLens()
@@ -294,7 +293,7 @@ class FilterManager(DirectObject):
 
 
         winprops = WindowProperties()
         winprops = WindowProperties()
         winprops.setSize(xsize, ysize)
         winprops.setSize(xsize, ysize)
-        props = FrameBufferProperties(self.win.getFbProperties())
+        props = FrameBufferProperties(FrameBufferProperties.getDefault())
         props.setBackBuffers(0)
         props.setBackBuffers(0)
         props.setRgbColor(1)
         props.setRgbColor(1)
         props.setDepthBits(depthbits)
         props.setDepthBits(depthbits)

+ 1 - 1
direct/src/leveleditor/LevelEditorBase.py

@@ -111,7 +111,7 @@ class LevelEditorBase(DirectObject):
         base.direct.deselect(nodePath)
         base.direct.deselect(nodePath)
         self.objectMgr.removeObjectByNodePath(nodePath)
         self.objectMgr.removeObjectByNodePath(nodePath)
 
 
-        if (base.direct.selected.last != None and nodePath.compareTo(base.direct.selected.last)==0):
+        if base.direct.selected.last is not None and nodePath == base.direct.selected.last:
             # if base.direct.selected.last is refering to this
             # if base.direct.selected.last is refering to this
             # removed obj, clear the reference
             # removed obj, clear the reference
             if (hasattr(__builtins__,'last')):
             if (hasattr(__builtins__,'last')):

+ 2 - 2
direct/src/p3d/AppRunner.py

@@ -175,7 +175,7 @@ class AppRunner(DirectObject):
         # the current working directory, for convenience; but when we
         # the current working directory, for convenience; but when we
         # move to multiple-instance sessions, it may have to be
         # move to multiple-instance sessions, it may have to be
         # different for each instance.
         # different for each instance.
-        self.multifileRoot = ExecutionEnvironment.getCwd().cStr()
+        self.multifileRoot = str(ExecutionEnvironment.getCwd())
 
 
         # The "main" object will be exposed to the DOM as a property
         # The "main" object will be exposed to the DOM as a property
         # of the plugin object; that is, document.pluginobject.main in
         # of the plugin object; that is, document.pluginobject.main in
@@ -554,7 +554,7 @@ class AppRunner(DirectObject):
         # Write the file to a temporary filename, then atomically move
         # Write the file to a temporary filename, then atomically move
         # it to its actual filename, to avoid race conditions when
         # it to its actual filename, to avoid race conditions when
         # updating this file.
         # updating this file.
-        tfile = Filename.temporary(self.rootDir.cStr(), '.xml')
+        tfile = Filename.temporary(str(self.rootDir), '.xml')
         if doc.SaveFile(tfile.toOsSpecific()):
         if doc.SaveFile(tfile.toOsSpecific()):
             tfile.renameTo(filename)
             tfile.renameTo(filename)
 
 

+ 1 - 1
direct/src/p3d/FileSpec.py

@@ -25,7 +25,7 @@ class FileSpec:
         if pathname is None:
         if pathname is None:
             pathname = Filename(packageDir, filename)
             pathname = Filename(packageDir, filename)
 
 
-        self.filename = filename.cStr()
+        self.filename = str(filename)
         self.basename = filename.getBasename()
         self.basename = filename.getBasename()
 
 
         if st is None:
         if st is None:

+ 1 - 1
direct/src/p3d/HostInfo.py

@@ -646,7 +646,7 @@ class HostInfo:
         if hostDirBasename:
         if hostDirBasename:
             # If the contents.xml specified a host_dir parameter, use
             # If the contents.xml specified a host_dir parameter, use
             # it.
             # it.
-            hostDir = self.rootDir.cStr() + '/hosts'
+            hostDir = str(self.rootDir) + '/hosts'
             for component in hostDirBasename.split('/'):
             for component in hostDirBasename.split('/'):
                 if component:
                 if component:
                     if component[0] == '.':
                     if component[0] == '.':

+ 2 - 2
direct/src/p3d/PackageInfo.py

@@ -1066,7 +1066,7 @@ class PackageInfo:
             return False
             return False
 
 
         # We mount it under its actual location on disk.
         # We mount it under its actual location on disk.
-        root = self.getPackageDir().cStr()
+        root = self.getPackageDir()
 
 
         vfs = VirtualFileSystem.getGlobalPtr()
         vfs = VirtualFileSystem.getGlobalPtr()
         vfs.mount(mf, root, vfs.MFReadOnly)
         vfs.mount(mf, root, vfs.MFReadOnly)
@@ -1210,7 +1210,7 @@ class PackageInfo:
         # Write the file to a temporary filename, then atomically move
         # Write the file to a temporary filename, then atomically move
         # it to its actual filename, to avoid race conditions when
         # it to its actual filename, to avoid race conditions when
         # updating this file.
         # updating this file.
-        tfile = Filename.temporary(self.getPackageDir().cStr(), '.xml')
+        tfile = Filename.temporary(str(self.getPackageDir()), '.xml')
         if doc.SaveFile(tfile.toOsSpecific()):
         if doc.SaveFile(tfile.toOsSpecific()):
             tfile.renameTo(filename)
             tfile.renameTo(filename)
 
 

+ 1 - 1
direct/src/p3d/Packager.py

@@ -2263,7 +2263,7 @@ class Packager:
                 self.executablePath.appendDirectory('/usr/lib')
                 self.executablePath.appendDirectory('/usr/lib')
                 self.executablePath.appendDirectory('/usr/local/lib')
                 self.executablePath.appendDirectory('/usr/local/lib')
 
 
-        if os.uname()[1] == "pcbsd":
+        if self.platform.startswith('freebsd') and os.uname()[1] == "pcbsd":
             self.executablePath.appendDirectory('/usr/PCBSD/local/lib')
             self.executablePath.appendDirectory('/usr/PCBSD/local/lib')
 
 
         # Set this flag true to automatically add allow_python_dev to
         # Set this flag true to automatically add allow_python_dev to

+ 1 - 1
direct/src/p3d/PatchMaker.py

@@ -526,7 +526,7 @@ class PatchMaker:
             # Also copy the seq to the import desc file, for
             # Also copy the seq to the import desc file, for
             # documentation purposes.
             # documentation purposes.
 
 
-            importDescFilename = self.packageDesc.cStr()[:-3] + 'import.xml'
+            importDescFilename = str(self.packageDesc)[:-3] + 'import.xml'
             importDescFullpath = Filename(self.patchMaker.installDir, importDescFilename)
             importDescFullpath = Filename(self.patchMaker.installDir, importDescFilename)
             doc = TiXmlDocument(importDescFullpath.toOsSpecific())
             doc = TiXmlDocument(importDescFullpath.toOsSpecific())
             if doc.LoadFile():
             if doc.LoadFile():

+ 1 - 1
direct/src/p3d/ScanDirectoryNode.py

@@ -58,7 +58,7 @@ class ScanDirectoryNode:
             # Now update the usage.xml file with the newly-determined
             # Now update the usage.xml file with the newly-determined
             # disk space.
             # disk space.
             xusage.SetAttribute('disk_space', str(self.getTotalSize()))
             xusage.SetAttribute('disk_space', str(self.getTotalSize()))
-            tfile = Filename.temporary(pathname.cStr(), '.xml')
+            tfile = Filename.temporary(str(pathname), '.xml')
             if doc.SaveFile(tfile.toOsSpecific()):
             if doc.SaveFile(tfile.toOsSpecific()):
                 tfile.renameTo(usageFilename)
                 tfile.renameTo(usageFilename)
 
 

+ 5 - 6
direct/src/plugin/Sources.pp

@@ -18,8 +18,7 @@
 // /MD.  This links the plugin with the static C runtime library,
 // /MD.  This links the plugin with the static C runtime library,
 // instead of the dynamic runtime library, which is much better for
 // instead of the dynamic runtime library, which is much better for
 // distributing the plugin with the XPI and CAB interfaces.  This
 // distributing the plugin with the XPI and CAB interfaces.  This
-// requires that special /MT versions of OpenSSL, libjpeg, libpng,
-// and zlib are available.
+// requires that special /MT versions of OpenSSL and zlib are available.
 
 
 #define _MT $[if $[P3D_PLUGIN_MT],_mt]
 #define _MT $[if $[P3D_PLUGIN_MT],_mt]
 
 
@@ -114,8 +113,8 @@
 // p3d_plugin.dll, the main entry point to the Core API.
 // p3d_plugin.dll, the main entry point to the Core API.
 //
 //
 
 
-  #define BUILD_TARGET $[and $[HAVE_P3D_PLUGIN],$[HAVE_OPENSSL],$[HAVE_ZLIB],$[HAVE_JPEG],$[HAVE_PNG]]
-  #define USE_PACKAGES openssl$[_MT] zlib$[_MT] jpeg$[_MT] png$[_MT] x11
+  #define BUILD_TARGET $[and $[HAVE_P3D_PLUGIN],$[HAVE_OPENSSL],$[HAVE_ZLIB]]
+  #define USE_PACKAGES openssl$[_MT] zlib$[_MT] x11
   #define TARGET p3d_plugin
   #define TARGET p3d_plugin
   #define LIB_PREFIX
   #define LIB_PREFIX
   #define BUILDING_DLL BUILDING_P3D_PLUGIN
   #define BUILDING_DLL BUILDING_P3D_PLUGIN
@@ -141,8 +140,8 @@
 // libp3d_plugin_static.lib, the Core API as a static library (for p3dembed).
 // libp3d_plugin_static.lib, the Core API as a static library (for p3dembed).
 //
 //
 
 
-  #define BUILD_TARGET $[and $[HAVE_P3D_PLUGIN],$[HAVE_OPENSSL],$[HAVE_ZLIB],$[HAVE_JPEG],$[HAVE_PNG]]
-  #define USE_PACKAGES openssl zlib jpeg png x11
+  #define BUILD_TARGET $[and $[HAVE_P3D_PLUGIN],$[HAVE_OPENSSL],$[HAVE_ZLIB]]
+  #define USE_PACKAGES openssl zlib x11
   #define TARGET p3d_plugin_static
   #define TARGET p3d_plugin_static
   #define BUILDING_DLL BUILDING_P3D_PLUGIN
   #define BUILDING_DLL BUILDING_P3D_PLUGIN
 
 

+ 5 - 5
direct/src/plugin/p3dCert.cxx

@@ -16,10 +16,10 @@
 #include "wstring_encode.h"
 #include "wstring_encode.h"
 #include "mkdir_complete.h"
 #include "mkdir_complete.h"
 
 
-#include <Fl/Fl_Box.H>
-#include <Fl/Fl_Button.H>
-#include <Fl/Fl_Return_Button.H>
-#include <Fl/Fl_Text_Display.H>
+#include <FL/Fl_Box.H>
+#include <FL/Fl_Button.H>
+#include <FL/Fl_Return_Button.H>
+#include <FL/Fl_Text_Display.H>
 
 
 #include <cassert>
 #include <cassert>
 #include <sys/types.h>
 #include <sys/types.h>
@@ -557,7 +557,7 @@ get_text(char *header, size_t hlen, char *text, size_t tlen) {
 
 
   case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
   case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
     strncpy(header, "Unverified signature!", hlen);
     strncpy(header, "Unverified signature!", hlen);
-    snprintf(text, tlen, unknown_auth_cert_text, _friendly_name.c_str());
+    snprintf(text, tlen, unknown_auth_cert_text);
     break;
     break;
 
 
   case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
   case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:

+ 2 - 2
direct/src/plugin/p3dCert.h

@@ -15,8 +15,8 @@
 #ifndef P3DCERT_H
 #ifndef P3DCERT_H
 #define P3DCERT_H
 #define P3DCERT_H
 
 
-#include <Fl/Fl.H>
-#include <Fl/Fl_Window.H>
+#include <FL/Fl.H>
+#include <FL/Fl_Window.H>
 
 
 #define OPENSSL_NO_KRB5
 #define OPENSSL_NO_KRB5
 #include "openssl/x509.h"
 #include "openssl/x509.h"

+ 15 - 7
direct/src/plugin/p3dInstance.cxx

@@ -52,7 +52,7 @@ enum {
 
 
 #ifdef _WIN32
 #ifdef _WIN32
 typedef P3DWinSplashWindow SplashWindowType;
 typedef P3DWinSplashWindow SplashWindowType;
-#elif defined(__APPLE__)
+#elif defined(__APPLE__) && !__LP64__
 typedef P3DOsxSplashWindow SplashWindowType;
 typedef P3DOsxSplashWindow SplashWindowType;
 #elif defined(HAVE_X11)
 #elif defined(HAVE_X11)
 typedef P3DX11SplashWindow SplashWindowType;
 typedef P3DX11SplashWindow SplashWindowType;
@@ -740,7 +740,7 @@ get_request() {
         // to shutdown.
         // to shutdown.
         _main_object->set_pyobj(NULL);
         _main_object->set_pyobj(NULL);
         _main_object->set_string_property("status", "stopped");
         _main_object->set_string_property("status", "stopped");
-        
+
         string message = "onpythonstop";
         string message = "onpythonstop";
         string expression = _fparams.lookup_token(message);
         string expression = _fparams.lookup_token(message);
         nout << "notify: " << message << " " << expression << "\n";
         nout << "notify: " << message << " " << expression << "\n";
@@ -782,9 +782,12 @@ get_request() {
         }
         }
       }
       }
       break;
       break;
+
+    default:
+      break;
     }
     }
   }
   }
-  
+
   return request;
   return request;
 }
 }
 
 
@@ -935,6 +938,9 @@ finish_request(P3D_request *request, bool handled) {
       request->_request._forget_package._package_version = NULL;
       request->_request._forget_package._package_version = NULL;
     }
     }
     break;
     break;
+
+  default:
+    break;
   }
   }
 
 
   p3d_unref_delete(((P3DInstance *)request->_instance));
   p3d_unref_delete(((P3DInstance *)request->_instance));
@@ -3449,7 +3455,9 @@ paint_window() {
 #ifdef __APPLE__
 #ifdef __APPLE__
   const P3D_window_handle &handle = _wparams.get_parent_window();
   const P3D_window_handle &handle = _wparams.get_parent_window();
   if (handle._window_handle_type == P3D_WHT_osx_port) {
   if (handle._window_handle_type == P3D_WHT_osx_port) {
+#if !__LP64__
     paint_window_osx_port();
     paint_window_osx_port();
+#endif
 
 
   } else if (handle._window_handle_type == P3D_WHT_osx_cgcontext) {
   } else if (handle._window_handle_type == P3D_WHT_osx_cgcontext) {
     const P3D_window_handle &handle = _wparams.get_parent_window();
     const P3D_window_handle &handle = _wparams.get_parent_window();
@@ -3461,7 +3469,7 @@ paint_window() {
 #endif  // __APPLE__
 #endif  // __APPLE__
 }
 }
 
 
-#ifdef __APPLE__
+#if defined(__APPLE__) && !__LP64__
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DInstance::get_framebuffer_osx_port
 //     Function: P3DInstance::get_framebuffer_osx_port
 //       Access: Private
 //       Access: Private
@@ -3584,7 +3592,7 @@ get_framebuffer_osx_cgcontext() {
 }
 }
 #endif  // __APPLE__
 #endif  // __APPLE__
 
 
-#ifdef __APPLE__
+#if defined(__APPLE__) && !__LP64__
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DInstance::paint_window_osx_port
 //     Function: P3DInstance::paint_window_osx_port
 //       Access: Private
 //       Access: Private
@@ -3674,7 +3682,7 @@ bool P3DInstance::
 handle_event_osx_event_record(const P3D_event_data &event) {
 handle_event_osx_event_record(const P3D_event_data &event) {
   bool retval = false;
   bool retval = false;
 
 
-#ifdef __APPLE__
+#if defined(__APPLE__) && !__LP64__
   assert(event._event_type == P3D_ET_osx_event_record);
   assert(event._event_type == P3D_ET_osx_event_record);
   EventRecord *er = event._event._osx_event_record._event;
   EventRecord *er = event._event._osx_event_record._event;
 
 
@@ -3889,7 +3897,7 @@ handle_event_osx_cocoa(const P3D_event_data &event) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void P3DInstance::
 void P3DInstance::
 add_carbon_modifier_flags(unsigned int &swb_flags, int modifiers) {
 add_carbon_modifier_flags(unsigned int &swb_flags, int modifiers) {
-#ifdef __APPLE__
+#if defined(__APPLE__) && !__LP64__
   if (modifiers & cmdKey) {
   if (modifiers & cmdKey) {
     swb_flags |= SubprocessWindowBuffer::EF_meta_held;
     swb_flags |= SubprocessWindowBuffer::EF_meta_held;
   }
   }

+ 9 - 9
direct/src/plugin/p3dMainObject.cxx

@@ -575,14 +575,14 @@ read_log(const string &log_pathname, P3D_object *params[], int num_params) {
 
 
   // Read matching files
   // Read matching files
   vector<string> all_logs;
   vector<string> all_logs;
-  int log_matches_found = 0; 
+  int log_matches_found = 0;
   string log_matching_pathname;
   string log_matching_pathname;
   inst_mgr->scan_directory(log_directory, all_logs);
   inst_mgr->scan_directory(log_directory, all_logs);
-  for (int i=(int)all_logs.size()-1; i>=0; --i) {
-    if ((all_logs[i] == log_leafname_primary) ||
-        (all_logs[i].find(log_basename) == 0) &&
-        (all_logs[i].size() > 4) &&
-        (all_logs[i].substr(all_logs[i].size() - 4) == string(".log"))) {
+  for (int i = (int)all_logs.size() - 1; i >= 0; --i) {
+    if (all_logs[i] == log_leafname_primary ||
+        (all_logs[i].find(log_basename) == 0 &&
+         all_logs[i].size() > 4 &&
+         all_logs[i].substr(all_logs[i].size() - 4) == string(".log"))) {
       log_matches_found++;
       log_matches_found++;
       log_matching_pathname = (log_directory + all_logs[i]);
       log_matching_pathname = (log_directory + all_logs[i]);
       read_log_file(log_matching_pathname, tail_bytes, head_bytes, log_data);
       read_log_file(log_matching_pathname, tail_bytes, head_bytes, log_data);
@@ -606,10 +606,10 @@ read_log(const string &log_pathname, P3D_object *params[], int num_params) {
 //  Description: The generic log-reader function.
 //  Description: The generic log-reader function.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void P3DMainObject::
 void P3DMainObject::
-read_log_file(const string &log_pathname, 
-              size_t tail_bytes, size_t head_bytes, 
+read_log_file(const string &log_pathname,
+              size_t tail_bytes, size_t head_bytes,
               ostringstream &log_data) {
               ostringstream &log_data) {
-  
+
   // Get leaf name
   // Get leaf name
   string log_leafname = log_pathname;
   string log_leafname = log_pathname;
   size_t slash = log_leafname.rfind('/');
   size_t slash = log_leafname.rfind('/');

+ 1 - 1
direct/src/plugin/p3dOsxSplashWindow.cxx

@@ -14,7 +14,7 @@
 
 
 #include "p3dOsxSplashWindow.h"
 #include "p3dOsxSplashWindow.h"
 
 
-#ifdef __APPLE__
+#if defined(__APPLE__) && !__LP64__
 
 
 #include <Carbon/Carbon.h>
 #include <Carbon/Carbon.h>
 #include <ApplicationServices/ApplicationServices.h>
 #include <ApplicationServices/ApplicationServices.h>

+ 1 - 1
direct/src/plugin/p3dOsxSplashWindow.h

@@ -17,7 +17,7 @@
 
 
 #include "p3d_plugin_common.h"
 #include "p3d_plugin_common.h"
 
 
-#ifdef __APPLE__
+#if defined(__APPLE__) && !__LP64__
 
 
 #include "p3dSplashWindow.h"
 #include "p3dSplashWindow.h"
 
 

+ 5 - 1
direct/src/plugin/p3dPackage.cxx

@@ -1539,6 +1539,10 @@ download_progress() {
   assert(_package->_active_download == this);
   assert(_package->_active_download == this);
 
 
   switch (_dtype) {
   switch (_dtype) {
+  case DT_contents_file:
+  case DT_redownload_contents_file:
+    break;
+
   case DT_desc_file:
   case DT_desc_file:
     break;
     break;
 
 
@@ -1581,7 +1585,7 @@ download_finished(bool success) {
         _file_spec.get_actual_file()->output_hash(nout);
         _file_spec.get_actual_file()->output_hash(nout);
         nout << "\n";
         nout << "\n";
       }
       }
-      
+
       success = false;
       success = false;
     }
     }
   }
   }

+ 15 - 27
direct/src/plugin/p3dPythonRun.cxx

@@ -19,10 +19,7 @@
 #include "virtualFileSystem.h"
 #include "virtualFileSystem.h"
 #include "nativeWindowHandle.h"
 #include "nativeWindowHandle.h"
 
 
-#ifndef CPPPARSER
 #include "py_panda.h"
 #include "py_panda.h"
-IMPORT_THIS struct Dtool_PyTypedObject Dtool_WindowHandle;
-#endif
 
 
 // There is only one P3DPythonRun object in any given process space.
 // There is only one P3DPythonRun object in any given process space.
 // Makes the statics easier to deal with, and we don't need multiple
 // Makes the statics easier to deal with, and we don't need multiple
@@ -298,14 +295,12 @@ run_python() {
 
 
   // Now pass that func pointer back to our AppRunner instance, so it
   // Now pass that func pointer back to our AppRunner instance, so it
   // can call up to us.
   // can call up to us.
-  result = PyObject_CallMethod(_runner, (char *)"setRequestFunc", (char *)"O", request_func);
+  result = PyObject_CallMethod(_runner, (char *)"setRequestFunc", (char *)"N", request_func);
   if (result == NULL) {
   if (result == NULL) {
     PyErr_Print();
     PyErr_Print();
     return false;
     return false;
   }
   }
   Py_DECREF(result);
   Py_DECREF(result);
-  Py_DECREF(request_func);
-
 
 
   // Now add check_comm() as a task.  It can be a threaded task, but
   // Now add check_comm() as a task.  It can be a threaded task, but
   // this does mean that application programmers will have to be alert
   // this does mean that application programmers will have to be alert
@@ -326,14 +321,14 @@ run_python() {
     return false;
     return false;
   }
   }
 
 
-  // We have to make it a PythonTask, not just a GenericAsyncTask,
-  // because we need the code in PythonTask that supports calling into
-  // Python from a separate thread.
-  _check_comm_task = new PythonTask(check_comm, "check_comm");
-  _check_comm_task->set_task_chain("JavaScript");
-  task_mgr->add(_check_comm_task);
-
-  Py_DECREF(check_comm);
+  // Add it to the task manager.  We do this instead of constructing a
+  // PythonTask because linking p3dpython with core.pyd is problematic.
+  result = PyObject_CallMethod(_taskMgr, (char *)"add", (char *)"Ns", check_comm, "check_comm");
+  if (result == NULL) {
+    PyErr_Print();
+    return false;
+  }
+  Py_DECREF(result);
 
 
   // Finally, get lost in AppRunner.run() (which is really a call to
   // Finally, get lost in AppRunner.run() (which is really a call to
   // taskMgr.run()).
   // taskMgr.run()).
@@ -603,10 +598,8 @@ handle_pyobj_command(TiXmlElement *xcommand, bool needs_response,
         Py_INCREF(obj);
         Py_INCREF(obj);
       }
       }
 
 
-      PyObject *result = PyObject_CallMethod
-        (_runner, (char *)"setBrowserScriptObject", (char *)"O", obj);
-      Py_DECREF(obj);
-      Py_XDECREF(result);
+      Py_XDECREF(PyObject_CallMethod
+        (_runner, (char *)"setBrowserScriptObject", (char *)"N", obj));
 
 
     } else if (strcmp(op, "call") == 0) {
     } else if (strcmp(op, "call") == 0) {
       // Call the named method on the indicated object, or the object
       // Call the named method on the indicated object, or the object
@@ -1215,9 +1208,8 @@ set_instance_info(P3DCInstance *inst, TiXmlElement *xinstance) {
   xinstance->Attribute("respect_per_platform", &respect_per_platform);
   xinstance->Attribute("respect_per_platform", &respect_per_platform);
 
 
   PyObject *result = PyObject_CallMethod
   PyObject *result = PyObject_CallMethod
-    (_runner, (char *)"setInstanceInfo", (char *)"sssiOi", root_dir,
+    (_runner, (char *)"setInstanceInfo", (char *)"sssiNi", root_dir,
      log_directory, super_mirror, verify_contents, main, respect_per_platform);
      log_directory, super_mirror, verify_contents, main, respect_per_platform);
-  Py_DECREF(main);
 
 
   if (result == NULL) {
   if (result == NULL) {
     PyErr_Print();
     PyErr_Print();
@@ -1331,11 +1323,9 @@ set_p3d_filename(P3DCInstance *inst, TiXmlElement *xfparams) {
   }
   }
 
 
   PyObject *result = PyObject_CallMethod
   PyObject *result = PyObject_CallMethod
-    (_runner, (char *)"setP3DFilename", (char *)"sOOiiis", p3d_filename.c_str(),
+    (_runner, (char *)"setP3DFilename", (char *)"sNNiiis", p3d_filename.c_str(),
      token_list, arg_list, inst->get_instance_id(), _interactive_console, p3d_offset,
      token_list, arg_list, inst->get_instance_id(), _interactive_console, p3d_offset,
      p3d_url.c_str());
      p3d_url.c_str());
-  Py_DECREF(token_list);
-  Py_DECREF(arg_list);
 
 
   if (result == NULL) {
   if (result == NULL) {
     PyErr_Print();
     PyErr_Print();
@@ -1425,18 +1415,16 @@ setup_window(P3DCInstance *inst, TiXmlElement *xwparams) {
     // setupWindow() call.  For this, we need to create a Python
     // setupWindow() call.  For this, we need to create a Python
     // wrapper objcet.
     // wrapper objcet.
     parent_window_handle->ref();
     parent_window_handle->ref();
-    py_handle = DTool_CreatePyInstanceTyped(parent_window_handle, Dtool_WindowHandle, true, false, parent_window_handle->get_type_index());
+    py_handle = DTool_CreatePyInstanceTyped(parent_window_handle.p(), true);
   }
   }
   Py_INCREF(py_handle);
   Py_INCREF(py_handle);
 
 
   // TODO: direct this into the particular instance.  This will
   // TODO: direct this into the particular instance.  This will
   // require a specialized ShowBase replacement.
   // require a specialized ShowBase replacement.
   PyObject *result = PyObject_CallMethod
   PyObject *result = PyObject_CallMethod
-    (_runner, (char *)"setupWindow", (char *)"siiiiO", window_type.c_str(),
+    (_runner, (char *)"setupWindow", (char *)"siiiiN", window_type.c_str(),
      win_x, win_y, win_width, win_height, py_handle);
      win_x, win_y, win_width, win_height, py_handle);
 
 
-  Py_DECREF(py_handle);
-
   if (result == NULL) {
   if (result == NULL) {
     PyErr_Print();
     PyErr_Print();
     if (_interactive_console) {
     if (_interactive_console) {

+ 0 - 3
direct/src/plugin/p3dPythonRun.h

@@ -27,7 +27,6 @@
 #include "handleStream.h"
 #include "handleStream.h"
 #include "p3dCInstance.h"
 #include "p3dCInstance.h"
 #include "pandaFileStreamBuf.h"
 #include "pandaFileStreamBuf.h"
-#include "pythonTask.h"
 #include "pmap.h"
 #include "pmap.h"
 #include "pdeque.h"
 #include "pdeque.h"
 #include "pmutex.h"
 #include "pmutex.h"
@@ -173,8 +172,6 @@ private:
   PyObject *_browser_object_class;
   PyObject *_browser_object_class;
   PyObject *_taskMgr;
   PyObject *_taskMgr;
 
 
-  PT(PythonTask) _check_comm_task;
-
   // This map keeps track of the PyObject pointers we have delivered
   // This map keeps track of the PyObject pointers we have delivered
   // to the parent process.  We have to hold the reference count on
   // to the parent process.  We have to hold the reference count on
   // each of these until the parent process tells us it's safe to
   // each of these until the parent process tells us it's safe to

+ 20 - 205
direct/src/plugin/p3dSplashWindow.cxx

@@ -15,30 +15,11 @@
 #include "p3dSplashWindow.h"
 #include "p3dSplashWindow.h"
 #include "wstring_encode.h"
 #include "wstring_encode.h"
 
 
-// Stuff to use libpng.
-#include <png.h>
-
-// Stuff to use libjpeg.
-extern "C" {
-#include <jpeglib.h>
-#include <jerror.h>
-}
-
-#include <setjmp.h>
-
-struct my_error_mgr {
-  struct jpeg_error_mgr pub;
-  jmp_buf setjmp_buffer;
-};
-
-typedef struct my_error_mgr *my_error_ptr;
-
-METHODDEF(void) my_error_exit (j_common_ptr cinfo) {
-  // cinfo->err really points to a my_error_mgr struct, so coerce pointer
-  my_error_ptr myerr = (my_error_ptr) cinfo->err;
-  // Return control to the setjmp point
-  longjmp(myerr->setjmp_buffer, 1);
-}
+// We use the public domain stb_image library for loading images.
+// Define the stb_image implementation.  We only use it in this unit.
+#define STB_IMAGE_STATIC
+#define STB_IMAGE_IMPLEMENTATION
+#include "stb_image.h"
 
 
 // The number of pixels to move the block per byte downloaded, when we
 // The number of pixels to move the block per byte downloaded, when we
 // don't know the actual file size we're downloading.
 // don't know the actual file size we're downloading.
@@ -52,7 +33,7 @@ const double P3DSplashWindow::_unknown_progress_rate = 1.0 / 4096;
 //               them both into this class for reference.
 //               them both into this class for reference.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 P3DSplashWindow::
 P3DSplashWindow::
-P3DSplashWindow(P3DInstance *inst, bool make_visible) : 
+P3DSplashWindow(P3DInstance *inst, bool make_visible) :
   _inst(inst),
   _inst(inst),
   _fparams(inst->get_fparams()),
   _fparams(inst->get_fparams()),
   _wparams(inst->get_wparams())
   _wparams(inst->get_wparams())
@@ -82,7 +63,7 @@ P3DSplashWindow(P3DInstance *inst, bool make_visible) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DSplashWindow::Destructor
 //     Function: P3DSplashWindow::Destructor
 //       Access: Public, Virtual
 //       Access: Public, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 P3DSplashWindow::
 P3DSplashWindow::
 ~P3DSplashWindow() {
 ~P3DSplashWindow() {
@@ -259,191 +240,25 @@ read_image_data(ImageData &image, string &data,
     return false;
     return false;
   }
   }
 
 
-  // We only support JPEG or PNG images.
-  FILE *fp = NULL;
-#ifdef _WIN32
-  wstring image_filename_w;
-  if (string_to_wstring(image_filename_w, image_filename)) {
-    fp = _wfopen(image_filename_w.c_str(), L"rb");
-  }
-#else // _WIN32
-  fp = fopen(image_filename.c_str(), "rb");
-#endif  // _WIN32
-
-  if (fp == NULL) {
-    nout << "Couldn't open splash file image: " << image_filename << "\n";
-    return false;
-  }
-
-  // Check the magic number to determine which image type we have.
-  static const size_t magic_number_len = 2;
-  char magic_number[magic_number_len];
-  if (fread(magic_number, 1, magic_number_len, fp) != magic_number_len) {
-    nout << "Empty file: " << image_filename << "\n";
-    return false;
-  }
-  // Rewind to re-read the magic number below.
-  fseek(fp, 0, SEEK_SET);
+  nout << "Reading splash file image: " << image_filename << "\n";
 
 
-  bool result = false;
-  if ((char)magic_number[0] == (char)0xff &&
-      (char)magic_number[1] == (char)0xd8) {
-    // It's a jpeg image.
-    result = read_image_data_jpeg(image, data, fp, image_filename);
-
-  } else if (png_sig_cmp((png_bytep)magic_number, 0, magic_number_len) == 0) {
-    // It's a PNG image.
-    result = read_image_data_png(image, data, fp, image_filename);
-
-  } else {
-    nout << "Neither a JPEG nor a PNG image: " << image_filename << "\n";
-    result = false;
-  }
+  unsigned char *imgdata = stbi_load(image_filename.c_str(), &image._width,
+                                     &image._height, &image._num_channels, 0);
 
 
-  fclose(fp);
-  return result;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: P3DSplashWindow::read_image_data_jpeg
-//       Access: Protected
-//  Description: Reads the image filename and sets image parameters
-//               width, height, num_channels, and data.  Returns true
-//               on success, false on failure.
-////////////////////////////////////////////////////////////////////
-bool P3DSplashWindow::
-read_image_data_jpeg(ImageData &image, string &data,
-                     FILE *fp, const string &image_filename) {
-  // We set up the normal JPEG error routines, then override error_exit.
-  struct jpeg_decompress_struct cinfo;
-
-  struct my_error_mgr jerr;
-  cinfo.err = jpeg_std_error(&jerr.pub);
-  jerr.pub.error_exit = my_error_exit;
-
-  JSAMPLE *buffer = NULL;
-  
-  // Establish the setjmp return context for my_error_exit to use
-  if (setjmp(jerr.setjmp_buffer)) {
-    // If we get here, the JPEG code has signaled an error.
-    nout << "JPEG error decoding " << image_filename << "\n";
-
-    // We need to clean up the JPEG object, close the input file, and return.
-    jpeg_destroy_decompress(&cinfo);
-
-    if (buffer != NULL) {
-      delete[] buffer;
+  if (imgdata == NULL) {
+    nout << "Couldn't read splash file image: " << image_filename << "\n";
+    const char *reason = stbi_failure_reason();
+    if (reason != NULL) {
+      nout << "stbi_failure_reason: " << reason << "\n";
     }
     }
     return false;
     return false;
   }
   }
 
 
-  /* Now we can initialize the JPEG decompression object. */
-  jpeg_create_decompress(&cinfo);
-  jpeg_stdio_src(&cinfo, fp);
-
-  jpeg_read_header(&cinfo, true);
-
-  cinfo.scale_num = 1;
-  cinfo.scale_denom = 1;
-
-  jpeg_start_decompress(&cinfo);
-
-  image._width = cinfo.output_width;
-  image._height = cinfo.output_height;
-  image._num_channels = cinfo.output_components;
-
-  int row_stride = image._width * image._num_channels;
-
-  size_t buffer_size = image._height * row_stride;
-  buffer = new JSAMPLE[buffer_size];
-  JSAMPLE *buffer_end = buffer + buffer_size;
-
-  JSAMPLE *rowptr = buffer;
-  while (cinfo.output_scanline < cinfo.output_height) {
-    assert(rowptr + row_stride <= buffer_end);
-    jpeg_read_scanlines(&cinfo, &rowptr, 1);
-    rowptr += row_stride;
-  }
+  size_t data_size = image._width * image._height * image._num_channels;
+  data.resize(data_size);
+  memcpy(&data[0], imgdata, data_size);
 
 
-  jpeg_finish_decompress(&cinfo);
-
-  data.append((const char *)buffer, buffer_size);
-  delete[] buffer;
-
-  return true;
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: P3DSplashWindow::read_image_data_png
-//       Access: Protected
-//  Description: Reads the image filename and sets image parameters
-//               width, height, num_channels, and data.  Returns true
-//               on success, false on failure.
-////////////////////////////////////////////////////////////////////
-bool P3DSplashWindow::
-read_image_data_png(ImageData &image, string &data,
-                    FILE *fp, const string &image_filename) {
-  png_structp png;
-  png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-  if (png == NULL) {
-    return false;
-  }
-
-  png_infop info;
-  info = png_create_info_struct(png);
-  if (info == NULL) {
-    png_destroy_read_struct(&png, NULL, NULL);
-    return false;
-  }
-
-  jmp_buf jmpbuf;
-  if (setjmp(jmpbuf)) {
-    // This is the ANSI C way to handle exceptions.  If setjmp(),
-    // above, returns true, it means that libpng detected an exception
-    // while executing the code that reads the header info, below.
-    png_destroy_read_struct(&png, &info, NULL);
-    return false;
-  }
-
-  png_init_io(png, fp);
-  int transforms = PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_SHIFT;
-  //  transforms |= PNG_TRANSFORM_STRIP_ALPHA;
-  png_read_png(png, info, transforms, NULL);
-
-  png_uint_32 width;
-  png_uint_32 height;
-  int bit_depth;
-  int color_type;
-
-  png_get_IHDR(png, info, &width, &height,
-               &bit_depth, &color_type, NULL, NULL, NULL);
-
-  image._width = width;
-  image._height = height;
-
-  switch (color_type) {
-  case PNG_COLOR_TYPE_RGB:
-    image._num_channels = 3;
-    break;
-
-  case PNG_COLOR_TYPE_RGB_ALPHA:
-    image._num_channels = 4;
-    break;
-
-  default:
-    nout << "Unsupported color type: " << color_type << "\n";
-    png_destroy_read_struct(&png, &info, NULL);
-    return false;
-  }
-
-  int row_stride = image._width * image._num_channels;
-  png_bytep *row_pointers = png_get_rows(png, info);
-  for (int yi = 0; yi < image._height; ++yi) {
-    data.append((const char *)row_pointers[yi], row_stride);
-  }
-
-  png_destroy_read_struct(&png, &info, NULL);
+  stbi_image_free(imgdata);
   return true;
   return true;
 }
 }
 
 
@@ -479,7 +294,7 @@ set_button_range(const ImageData &image) {
   // But it can't be larger than the window itself.
   // But it can't be larger than the window itself.
   _button_width = min(_button_width, _win_width);
   _button_width = min(_button_width, _win_width);
   _button_height = min(_button_height, _win_height);
   _button_height = min(_button_height, _win_height);
-      
+
   // Compute the top-left corner of the button image in window
   // Compute the top-left corner of the button image in window
   // coordinates.
   // coordinates.
   _button_x = (_win_width - _button_width) / 2;
   _button_x = (_win_width - _button_width) / 2;

+ 0 - 4
direct/src/plugin/p3dSplashWindow.h

@@ -78,10 +78,6 @@ protected:
 
 
   bool read_image_data(ImageData &image, string &data,
   bool read_image_data(ImageData &image, string &data,
                        const string &image_filename);
                        const string &image_filename);
-  bool read_image_data_jpeg(ImageData &image, string &data,
-                            FILE *fp, const string &image_filename);
-  bool read_image_data_png(ImageData &image, string &data,
-                           FILE *fp, const string &image_filename);
   void get_bar_placement(int &bar_x, int &bar_y,
   void get_bar_placement(int &bar_x, int &bar_y,
                          int &bar_width, int &bar_height);
                          int &bar_width, int &bar_height);
   void set_button_range(const ImageData &image);
   void set_button_range(const ImageData &image);

+ 0 - 1
direct/src/plugin/p3dX11SplashWindow.cxx

@@ -1060,7 +1060,6 @@ update_image(X11ImageData &image) {
   _needs_new_composite = true;
   _needs_new_composite = true;
 
 
   // Go read the image.
   // Go read the image.
-  string data;
   if (!read_image_data(image, image._data, image._filename)) {
   if (!read_image_data(image, image._data, image._filename)) {
     return;
     return;
   }
   }

+ 6326 - 0
direct/src/plugin/stb_image.h

@@ -0,0 +1,6326 @@
+/* stb_image - v2.02 - public domain image loader - http://nothings.org/stb_image.h
+                                     no warranty implied; use at your own risk
+
+   Do this:
+      #define STB_IMAGE_IMPLEMENTATION
+   before you include this file in *one* C or C++ file to create the implementation.
+
+   // i.e. it should look like this:
+   #include ...
+   #include ...
+   #include ...
+   #define STB_IMAGE_IMPLEMENTATION
+   #include "stb_image.h"
+
+   You can #define STBI_ASSERT(x) before the #include to avoid using assert.h.
+   And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free
+
+
+   QUICK NOTES:
+      Primarily of interest to game developers and other people who can
+          avoid problematic images and only need the trivial interface
+
+      JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib)
+      PNG 1/2/4/8-bit-per-channel (16 bpc not supported)
+
+      TGA (not sure what subset, if a subset)
+      BMP non-1bpp, non-RLE
+      PSD (composited view only, no extra channels)
+
+      GIF (*comp always reports as 4-channel)
+      HDR (radiance rgbE format)
+      PIC (Softimage PIC)
+      PNM (PPM and PGM binary only)
+
+      - decode from memory or through FILE (define STBI_NO_STDIO to remove code)
+      - decode from arbitrary I/O callbacks
+      - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON)
+
+   Full documentation under "DOCUMENTATION" below.
+
+
+   Revision 2.00 release notes:
+
+      - Progressive JPEG is now supported.
+
+      - PPM and PGM binary formats are now supported, thanks to Ken Miller.
+
+      - x86 platforms now make use of SSE2 SIMD instructions for
+        JPEG decoding, and ARM platforms can use NEON SIMD if requested.
+        This work was done by Fabian "ryg" Giesen. SSE2 is used by
+        default, but NEON must be enabled explicitly; see docs.
+
+        With other JPEG optimizations included in this version, we see
+        2x speedup on a JPEG on an x86 machine, and a 1.5x speedup
+        on a JPEG on an ARM machine, relative to previous versions of this
+        library. The same results will not obtain for all JPGs and for all
+        x86/ARM machines. (Note that progressive JPEGs are significantly
+        slower to decode than regular JPEGs.) This doesn't mean that this
+        is the fastest JPEG decoder in the land; rather, it brings it
+        closer to parity with standard libraries. If you want the fastest
+        decode, look elsewhere. (See "Philosophy" section of docs below.)
+
+        See final bullet items below for more info on SIMD.
+
+      - Added STBI_MALLOC, STBI_REALLOC, and STBI_FREE macros for replacing
+        the memory allocator. Unlike other STBI libraries, these macros don't
+        support a context parameter, so if you need to pass a context in to
+        the allocator, you'll have to store it in a global or a thread-local
+        variable.
+
+      - Split existing STBI_NO_HDR flag into two flags, STBI_NO_HDR and
+        STBI_NO_LINEAR.
+            STBI_NO_HDR:     suppress implementation of .hdr reader format
+            STBI_NO_LINEAR:  suppress high-dynamic-range light-linear float API
+
+      - You can suppress implementation of any of the decoders to reduce
+        your code footprint by #defining one or more of the following
+        symbols before creating the implementation.
+
+            STBI_NO_JPEG
+            STBI_NO_PNG
+            STBI_NO_BMP
+            STBI_NO_PSD
+            STBI_NO_TGA
+            STBI_NO_GIF
+            STBI_NO_HDR
+            STBI_NO_PIC
+            STBI_NO_PNM   (.ppm and .pgm)
+
+      - You can request *only* certain decoders and suppress all other ones
+        (this will be more forward-compatible, as addition of new decoders
+        doesn't require you to disable them explicitly):
+
+            STBI_ONLY_JPEG
+            STBI_ONLY_PNG
+            STBI_ONLY_BMP
+            STBI_ONLY_PSD
+            STBI_ONLY_TGA
+            STBI_ONLY_GIF
+            STBI_ONLY_HDR
+            STBI_ONLY_PIC
+            STBI_ONLY_PNM   (.ppm and .pgm)
+
+         Note that you can define multiples of these, and you will get all
+         of them ("only x" and "only y" is interpreted to mean "only x&y").
+
+       - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still
+         want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB
+
+      - Compilation of all SIMD code can be suppressed with
+            #define STBI_NO_SIMD
+        It should not be necessary to disable SIMD unless you have issues
+        compiling (e.g. using an x86 compiler which doesn't support SSE
+        intrinsics or that doesn't support the method used to detect
+        SSE2 support at run-time), and even those can be reported as
+        bugs so I can refine the built-in compile-time checking to be
+        smarter.
+
+      - The old STBI_SIMD system which allowed installing a user-defined
+        IDCT etc. has been removed. If you need this, don't upgrade. My
+        assumption is that almost nobody was doing this, and those who
+        were will find the built-in SIMD more satisfactory anyway.
+
+      - RGB values computed for JPEG images are slightly different from
+        previous versions of stb_image. (This is due to using less
+        integer precision in SIMD.) The C code has been adjusted so
+        that the same RGB values will be computed regardless of whether
+        SIMD support is available, so your app should always produce
+        consistent results. But these results are slightly different from
+        previous versions. (Specifically, about 3% of available YCbCr values
+        will compute different RGB results from pre-1.49 versions by +-1;
+        most of the deviating values are one smaller in the G channel.)
+
+      - If you must produce consistent results with previous versions of
+        stb_image, #define STBI_JPEG_OLD and you will get the same results
+        you used to; however, you will not get the SIMD speedups for
+        the YCbCr-to-RGB conversion step (although you should still see
+        significant JPEG speedup from the other changes).
+
+        Please note that STBI_JPEG_OLD is a temporary feature; it will be
+        removed in future versions of the library. It is only intended for
+        near-term back-compatibility use.
+
+
+   Latest revision history:
+      2.02  (2015-01-19) fix incorrect assert, fix warning
+      2.01  (2015-01-17) fix various warnings
+      2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG
+      2.00  (2014-12-25) optimize JPEG, including x86 SSE2 & ARM NEON SIMD
+                         progressive JPEG
+                         PGM/PPM support
+                         STBI_MALLOC,STBI_REALLOC,STBI_FREE
+                         STBI_NO_*, STBI_ONLY_*
+                         GIF bugfix
+      1.48  (2014-12-14) fix incorrectly-named assert()
+      1.47  (2014-12-14) 1/2/4-bit PNG support (both grayscale and paletted)
+                         optimize PNG
+                         fix bug in interlaced PNG with user-specified channel count
+      1.46  (2014-08-26) fix broken tRNS chunk in non-paletted PNG
+      1.45  (2014-08-16) workaround MSVC-ARM internal compiler error by wrapping malloc
+
+   See end of file for full revision history.
+
+
+ ============================    Contributors    =========================
+
+ Image formats                                Bug fixes & warning fixes
+    Sean Barrett (jpeg, png, bmp)                Marc LeBlanc
+    Nicolas Schulz (hdr, psd)                    Christpher Lloyd
+    Jonathan Dummer (tga)                        Dave Moore
+    Jean-Marc Lienher (gif)                      Won Chun
+    Tom Seddon (pic)                             the Horde3D community
+    Thatcher Ulrich (psd)                        Janez Zemva
+    Ken Miller (pgm, ppm)                        Jonathan Blow
+                                                 Laurent Gomila
+                                                 Aruelien Pocheville
+ Extensions, features                            Ryamond Barbiero
+    Jetro Lauha (stbi_info)                      David Woo
+    Martin "SpartanJ" Golini (stbi_info)         Martin Golini
+    James "moose2000" Brown (iPhone PNG)         Roy Eltham
+    Ben "Disch" Wenger (io callbacks)            Luke Graham
+    Omar Cornut (1/2/4-bit PNG)                  Thomas Ruf
+                                                 John Bartholomew
+                                                 Ken Hamada
+ Optimizations & bugfixes                        Cort Stratton
+    Fabian "ryg" Giesen                          Blazej Dariusz Roszkowski
+    Arseny Kapoulkine                            Thibault Reuille
+                                                 Paul Du Bois
+                                                 Guillaume George
+  If your name should be here but                Jerry Jansson
+  isn't, let Sean know.                          Hayaki Saito
+                                                 Johan Duparc
+                                                 Ronny Chevalier
+                                                 Michal Cichon
+                                                 Tero Hanninen
+                                                 Sergio Gonzalez
+                                                 Cass Everitt
+                                                 Engin Manap
+
+License:
+   This software is in the public domain. Where that dedication is not
+   recognized, you are granted a perpetual, irrevocable license to copy
+   and modify this file however you want.
+
+*/
+
+#ifndef STBI_INCLUDE_STB_IMAGE_H
+#define STBI_INCLUDE_STB_IMAGE_H
+
+// DOCUMENTATION
+//
+// Limitations:
+//    - no 16-bit-per-channel PNG
+//    - no 12-bit-per-channel JPEG
+//    - no JPEGs with arithmetic coding
+//    - no 1-bit BMP
+//    - GIF always returns *comp=4
+//
+// Basic usage (see HDR discussion below for HDR usage):
+//    int x,y,n;
+//    unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
+//    // ... process data if not NULL ...
+//    // ... x = width, y = height, n = # 8-bit components per pixel ...
+//    // ... replace '0' with '1'..'4' to force that many components per pixel
+//    // ... but 'n' will always be the number that it would have been if you said 0
+//    stbi_image_free(data)
+//
+// Standard parameters:
+//    int *x       -- outputs image width in pixels
+//    int *y       -- outputs image height in pixels
+//    int *comp    -- outputs # of image components in image file
+//    int req_comp -- if non-zero, # of image components requested in result
+//
+// The return value from an image loader is an 'unsigned char *' which points
+// to the pixel data, or NULL on an allocation failure or if the image is
+// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels,
+// with each pixel consisting of N interleaved 8-bit components; the first
+// pixel pointed to is top-left-most in the image. There is no padding between
+// image scanlines or between pixels, regardless of format. The number of
+// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise.
+// If req_comp is non-zero, *comp has the number of components that _would_
+// have been output otherwise. E.g. if you set req_comp to 4, you will always
+// get RGBA output, but you can check *comp to see if it's trivially opaque
+// because e.g. there were only 3 channels in the source image.
+//
+// An output image with N components has the following components interleaved
+// in this order in each pixel:
+//
+//     N=#comp     components
+//       1           grey
+//       2           grey, alpha
+//       3           red, green, blue
+//       4           red, green, blue, alpha
+//
+// If image loading fails for any reason, the return value will be NULL,
+// and *x, *y, *comp will be unchanged. The function stbi_failure_reason()
+// can be queried for an extremely brief, end-user unfriendly explanation
+// of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid
+// compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly
+// more user-friendly ones.
+//
+// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.
+//
+// ===========================================================================
+//
+// Philosophy
+//
+// stb libraries are designed with the following priorities:
+//
+//    1. easy to use
+//    2. easy to maintain
+//    3. good performance
+//
+// Sometimes I let "good performance" creep up in priority over "easy to maintain",
+// and for best performance I may provide less-easy-to-use APIs that give higher
+// performance, in addition to the easy to use ones. Nevertheless, it's important
+// to keep in mind that from the standpoint of you, a client of this library,
+// all you care about is #1 and #3, and stb libraries do not emphasize #3 above all.
+//
+// Some secondary priorities arise directly from the first two, some of which
+// make more explicit reasons why performance can't be emphasized.
+//
+//    - Portable ("ease of use")
+//    - Small footprint ("easy to maintain")
+//    - No dependencies ("ease of use")
+//
+// ===========================================================================
+//
+// I/O callbacks
+//
+// I/O callbacks allow you to read from arbitrary sources, like packaged
+// files or some other source. Data read from callbacks are processed
+// through a small internal buffer (currently 128 bytes) to try to reduce
+// overhead.
+//
+// The three functions you must define are "read" (reads some bytes of data),
+// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end).
+//
+// ===========================================================================
+//
+// SIMD support
+//
+// The JPEG decoder will try to automatically use SIMD kernels on x86 when
+// supported by the compiler. For ARM Neon support, you must explicitly
+// request it.
+//
+// (The old do-it-yourself SIMD API is no longer supported in the current
+// code.)
+//
+// On x86, SSE2 will automatically be used when available based on a run-time
+// test; if not, the generic C versions are used as a fall-back. On ARM targets,
+// the typical path is to have separate builds for NEON and non-NEON devices
+// (at least this is true for iOS and Android). Therefore, the NEON support is
+// toggled by a build flag: define STBI_NEON to get NEON loops.
+//
+// The output of the JPEG decoder is slightly different from versions where
+// SIMD support was introduced (that is, for versions before 1.49). The
+// difference is only +-1 in the 8-bit RGB channels, and only on a small
+// fraction of pixels. You can force the pre-1.49 behavior by defining
+// STBI_JPEG_OLD, but this will disable some of the SIMD decoding path
+// and hence cost some performance.
+//
+// If for some reason you do not want to use any of SIMD code, or if
+// you have issues compiling it, you can disable it entirely by
+// defining STBI_NO_SIMD.
+//
+// ===========================================================================
+//
+// HDR image support   (disable by defining STBI_NO_HDR)
+//
+// stb_image now supports loading HDR images in general, and currently
+// the Radiance .HDR file format, although the support is provided
+// generically. You can still load any file through the existing interface;
+// if you attempt to load an HDR file, it will be automatically remapped to
+// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1;
+// both of these constants can be reconfigured through this interface:
+//
+//     stbi_hdr_to_ldr_gamma(2.2f);
+//     stbi_hdr_to_ldr_scale(1.0f);
+//
+// (note, do not use _inverse_ constants; stbi_image will invert them
+// appropriately).
+//
+// Additionally, there is a new, parallel interface for loading files as
+// (linear) floats to preserve the full dynamic range:
+//
+//    float *data = stbi_loadf(filename, &x, &y, &n, 0);
+//
+// If you load LDR images through this interface, those images will
+// be promoted to floating point values, run through the inverse of
+// constants corresponding to the above:
+//
+//     stbi_ldr_to_hdr_scale(1.0f);
+//     stbi_ldr_to_hdr_gamma(2.2f);
+//
+// Finally, given a filename (or an open file or memory block--see header
+// file for details) containing image data, you can query for the "most
+// appropriate" interface to use (that is, whether the image is HDR or
+// not), using:
+//
+//     stbi_is_hdr(char *filename);
+//
+// ===========================================================================
+//
+// iPhone PNG support:
+//
+// By default we convert iphone-formatted PNGs back to RGB, even though
+// they are internally encoded differently. You can disable this conversion
+// by by calling stbi_convert_iphone_png_to_rgb(0), in which case
+// you will always just get the native iphone "format" through (which
+// is BGR stored in RGB).
+//
+// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per
+// pixel to remove any premultiplied alpha *only* if the image file explicitly
+// says there's premultiplied data (currently only happens in iPhone images,
+// and only if iPhone convert-to-rgb processing is on).
+//
+
+
+#ifndef STBI_NO_STDIO
+#include <stdio.h>
+#endif // STBI_NO_STDIO
+
+#define STBI_VERSION 1
+
+enum
+{
+   STBI_default = 0, // only used for req_comp
+
+   STBI_grey       = 1,
+   STBI_grey_alpha = 2,
+   STBI_rgb        = 3,
+   STBI_rgb_alpha  = 4
+};
+
+typedef unsigned char stbi_uc;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef STB_IMAGE_STATIC
+#define STBIDEF static
+#else
+#define STBIDEF extern
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// PRIMARY API - works on images of any type
+//
+
+//
+// load image by filename, open file, or memory buffer
+//
+
+typedef struct
+{
+   int      (*read)  (void *user,char *data,int size);   // fill 'data' with 'size' bytes.  return number of bytes actually read
+   void     (*skip)  (void *user,int n);                 // skip the next 'n' bytes, or 'unget' the last -n bytes if negative
+   int      (*eof)   (void *user);                       // returns nonzero if we are at end of file/data
+} stbi_io_callbacks;
+
+STBIDEF stbi_uc *stbi_load               (char              const *filename,           int *x, int *y, int *comp, int req_comp);
+STBIDEF stbi_uc *stbi_load_from_memory   (stbi_uc           const *buffer, int len   , int *x, int *y, int *comp, int req_comp);
+STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk  , void *user, int *x, int *y, int *comp, int req_comp);
+
+#ifndef STBI_NO_STDIO
+STBIDEF stbi_uc *stbi_load_from_file  (FILE *f,                  int *x, int *y, int *comp, int req_comp);
+// for stbi_load_from_file, file pointer is left pointing immediately after image
+#endif
+
+#ifndef STBI_NO_LINEAR
+   STBIDEF float *stbi_loadf                 (char const *filename,           int *x, int *y, int *comp, int req_comp);
+   STBIDEF float *stbi_loadf_from_memory     (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
+   STBIDEF float *stbi_loadf_from_callbacks  (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp);
+
+   #ifndef STBI_NO_STDIO
+   STBIDEF float *stbi_loadf_from_file  (FILE *f,                int *x, int *y, int *comp, int req_comp);
+   #endif
+#endif
+
+#ifndef STBI_NO_HDR
+   STBIDEF void   stbi_hdr_to_ldr_gamma(float gamma);
+   STBIDEF void   stbi_hdr_to_ldr_scale(float scale);
+#endif
+
+#ifndef STBI_NO_LINEAR
+   STBIDEF void   stbi_ldr_to_hdr_gamma(float gamma);
+   STBIDEF void   stbi_ldr_to_hdr_scale(float scale);
+#endif // STBI_NO_HDR
+
+// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR
+STBIDEF int    stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);
+STBIDEF int    stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);
+#ifndef STBI_NO_STDIO
+STBIDEF int      stbi_is_hdr          (char const *filename);
+STBIDEF int      stbi_is_hdr_from_file(FILE *f);
+#endif // STBI_NO_STDIO
+
+
+// get a VERY brief reason for failure
+// NOT THREADSAFE
+STBIDEF const char *stbi_failure_reason  (void);
+
+// free the loaded image -- this is just free()
+STBIDEF void     stbi_image_free      (void *retval_from_stbi_load);
+
+// get image dimensions & components without fully decoding
+STBIDEF int      stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
+STBIDEF int      stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);
+
+#ifndef STBI_NO_STDIO
+STBIDEF int      stbi_info            (char const *filename,     int *x, int *y, int *comp);
+STBIDEF int      stbi_info_from_file  (FILE *f,                  int *x, int *y, int *comp);
+
+#endif
+
+
+
+// for image formats that explicitly notate that they have premultiplied alpha,
+// we just return the colors as stored in the file. set this flag to force
+// unpremultiplication. results are undefined if the unpremultiply overflow.
+STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply);
+
+// indicate whether we should process iphone images back to canonical format,
+// or just pass them through "as-is"
+STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);
+
+
+// ZLIB client - used by PNG, available for other purposes
+
+STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);
+STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header);
+STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen);
+STBIDEF int   stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
+
+STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen);
+STBIDEF int   stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+//
+//
+////   end header file   /////////////////////////////////////////////////////
+#endif // STBI_INCLUDE_STB_IMAGE_H
+
+#ifdef STB_IMAGE_IMPLEMENTATION
+
+#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \
+  || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \
+  || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \
+  || defined(STBI_ONLY_ZLIB)
+   #ifndef STBI_ONLY_JPEG
+   #define STBI_NO_JPEG
+   #endif
+   #ifndef STBI_ONLY_PNG
+   #define STBI_NO_PNG
+   #endif
+   #ifndef STBI_ONLY_BMP
+   #define STBI_NO_BMP
+   #endif
+   #ifndef STBI_ONLY_PSD
+   #define STBI_NO_PSD
+   #endif
+   #ifndef STBI_ONLY_TGA
+   #define STBI_NO_TGA
+   #endif
+   #ifndef STBI_ONLY_GIF
+   #define STBI_NO_GIF
+   #endif
+   #ifndef STBI_ONLY_HDR
+   #define STBI_NO_HDR
+   #endif
+   #ifndef STBI_ONLY_PIC
+   #define STBI_NO_PIC
+   #endif
+   #ifndef STBI_ONLY_PNM
+   #define STBI_NO_PNM
+   #endif
+#endif
+
+#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB)
+#define STBI_NO_ZLIB
+#endif
+
+
+#include <stdarg.h>
+#include <stddef.h> // ptrdiff_t on osx
+#include <stdlib.h>
+#include <string.h>
+
+#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
+#include <math.h>  // ldexp
+#endif
+
+#ifndef STBI_NO_STDIO
+#include <stdio.h>
+#endif
+
+#ifndef STBI_ASSERT
+#include <assert.h>
+#define STBI_ASSERT(x) assert(x)
+#endif
+
+
+#ifndef _MSC_VER
+   #ifdef __cplusplus
+   #define stbi_inline inline
+   #else
+   #define stbi_inline
+   #endif
+#else
+   #define stbi_inline __forceinline
+#endif
+
+
+#ifdef _MSC_VER
+typedef unsigned short stbi__uint16;
+typedef   signed short stbi__int16;
+typedef unsigned int   stbi__uint32;
+typedef   signed int   stbi__int32;
+#else
+#include <stdint.h>
+typedef uint16_t stbi__uint16;
+typedef int16_t  stbi__int16;
+typedef uint32_t stbi__uint32;
+typedef int32_t  stbi__int32;
+#endif
+
+// should produce compiler error if size is wrong
+typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
+
+#ifdef _MSC_VER
+#define STBI_NOTUSED(v)  (void)(v)
+#else
+#define STBI_NOTUSED(v)  (void)sizeof(v)
+#endif
+
+#ifdef _MSC_VER
+#define STBI_HAS_LROTL
+#endif
+
+#ifdef STBI_HAS_LROTL
+   #define stbi_lrot(x,y)  _lrotl(x,y)
+#else
+   #define stbi_lrot(x,y)  (((x) << (y)) | ((x) >> (32 - (y))))
+#endif
+
+#if defined(STBI_MALLOC) && defined(STBI_FREE) && defined(STBI_REALLOC)
+// ok
+#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC)
+// ok
+#else
+#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC."
+#endif
+
+#ifndef STBI_MALLOC
+#define STBI_MALLOC(sz)    malloc(sz)
+#define STBI_REALLOC(p,sz) realloc(p,sz)
+#define STBI_FREE(p)       free(p)
+#endif
+
+#if defined(__GNUC__) && !defined(__SSE2__) && !defined(STBI_NO_SIMD)
+// gcc doesn't support sse2 intrinsics unless you compile with -msse2,
+// (but compiling with -msse2 allows the compiler to use SSE2 everywhere;
+// this is just broken and gcc are jerks for not fixing it properly
+// http://www.virtualdub.org/blog/pivot/entry.php?id=363 )
+#define STBI_NO_SIMD
+#endif
+
+#if !defined(STBI_NO_SIMD) && (defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86))
+#define STBI_SSE2
+#include <emmintrin.h>
+
+#ifdef _MSC_VER
+
+#if _MSC_VER >= 1400  // not VC6
+#include <intrin.h> // __cpuid
+static int stbi__cpuid3(void)
+{
+   int info[4];
+   __cpuid(info,1);
+   return info[3];
+}
+#else
+static int stbi__cpuid3(void)
+{
+   int res;
+   __asm {
+      mov  eax,1
+      cpuid
+      mov  res,edx
+   }
+   return res;
+}
+#endif
+
+#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name
+
+static int stbi__sse2_available()
+{
+   int info3 = stbi__cpuid3();
+   return ((info3 >> 26) & 1) != 0;
+}
+#else // assume GCC-style if not VC++
+#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
+
+static int stbi__sse2_available()
+{
+#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 // GCC 4.8 or later
+   // GCC 4.8+ has a nice way to do this
+   return __builtin_cpu_supports("sse2");
+#else
+   // portable way to do this, preferably without using GCC inline ASM?
+   // just bail for now.
+   return 0;
+#endif
+}
+#endif
+#endif
+
+// ARM NEON
+#if defined(STBI_NO_SIMD) && defined(STBI_NEON)
+#undef STBI_NEON
+#endif
+
+#ifdef STBI_NEON
+#include <arm_neon.h>
+// assume GCC or Clang on ARM targets
+#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
+#endif
+
+#ifndef STBI_SIMD_ALIGN
+#define STBI_SIMD_ALIGN(type, name) type name
+#endif
+
+///////////////////////////////////////////////
+//
+//  stbi__context struct and start_xxx functions
+
+// stbi__context structure is our basic context used by all images, so it
+// contains all the IO context, plus some basic image information
+typedef struct
+{
+   stbi__uint32 img_x, img_y;
+   int img_n, img_out_n;
+
+   stbi_io_callbacks io;
+   void *io_user_data;
+
+   int read_from_callbacks;
+   int buflen;
+   stbi_uc buffer_start[128];
+
+   stbi_uc *img_buffer, *img_buffer_end;
+   stbi_uc *img_buffer_original;
+} stbi__context;
+
+
+static void stbi__refill_buffer(stbi__context *s);
+
+// initialize a memory-decode context
+static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len)
+{
+   s->io.read = NULL;
+   s->read_from_callbacks = 0;
+   s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer;
+   s->img_buffer_end = (stbi_uc *) buffer+len;
+}
+
+// initialize a callback-based context
+static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user)
+{
+   s->io = *c;
+   s->io_user_data = user;
+   s->buflen = sizeof(s->buffer_start);
+   s->read_from_callbacks = 1;
+   s->img_buffer_original = s->buffer_start;
+   stbi__refill_buffer(s);
+}
+
+#ifndef STBI_NO_STDIO
+
+static int stbi__stdio_read(void *user, char *data, int size)
+{
+   return (int) fread(data,1,size,(FILE*) user);
+}
+
+static void stbi__stdio_skip(void *user, int n)
+{
+   fseek((FILE*) user, n, SEEK_CUR);
+}
+
+static int stbi__stdio_eof(void *user)
+{
+   return feof((FILE*) user);
+}
+
+static stbi_io_callbacks stbi__stdio_callbacks =
+{
+   stbi__stdio_read,
+   stbi__stdio_skip,
+   stbi__stdio_eof,
+};
+
+static void stbi__start_file(stbi__context *s, FILE *f)
+{
+   stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f);
+}
+
+//static void stop_file(stbi__context *s) { }
+
+#endif // !STBI_NO_STDIO
+
+static void stbi__rewind(stbi__context *s)
+{
+   // conceptually rewind SHOULD rewind to the beginning of the stream,
+   // but we just rewind to the beginning of the initial buffer, because
+   // we only use it after doing 'test', which only ever looks at at most 92 bytes
+   s->img_buffer = s->img_buffer_original;
+}
+
+#ifndef STBI_NO_JPEG
+static int      stbi__jpeg_test(stbi__context *s);
+static stbi_uc *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int      stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PNG
+static int      stbi__png_test(stbi__context *s);
+static stbi_uc *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int      stbi__png_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_BMP
+static int      stbi__bmp_test(stbi__context *s);
+static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int      stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_TGA
+static int      stbi__tga_test(stbi__context *s);
+static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int      stbi__tga_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PSD
+static int      stbi__psd_test(stbi__context *s);
+static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int      stbi__psd_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_HDR
+static int      stbi__hdr_test(stbi__context *s);
+static float   *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int      stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PIC
+static int      stbi__pic_test(stbi__context *s);
+static stbi_uc *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int      stbi__pic_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_GIF
+static int      stbi__gif_test(stbi__context *s);
+static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int      stbi__gif_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PNM
+static int      stbi__pnm_test(stbi__context *s);
+static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int      stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+// this is not threadsafe
+static const char *stbi__g_failure_reason;
+
+STBIDEF const char *stbi_failure_reason(void)
+{
+   return stbi__g_failure_reason;
+}
+
+static int stbi__err(const char *str)
+{
+   stbi__g_failure_reason = str;
+   return 0;
+}
+
+static void *stbi__malloc(size_t size)
+{
+    return STBI_MALLOC(size);
+}
+
+// stbi__err - error
+// stbi__errpf - error returning pointer to float
+// stbi__errpuc - error returning pointer to unsigned char
+
+#ifdef STBI_NO_FAILURE_STRINGS
+   #define stbi__err(x,y)  0
+#elif defined(STBI_FAILURE_USERMSG)
+   #define stbi__err(x,y)  stbi__err(y)
+#else
+   #define stbi__err(x,y)  stbi__err(x)
+#endif
+
+#define stbi__errpf(x,y)   ((float *) (stbi__err(x,y)?NULL:NULL))
+#define stbi__errpuc(x,y)  ((unsigned char *) (stbi__err(x,y)?NULL:NULL))
+
+STBIDEF void stbi_image_free(void *retval_from_stbi_load)
+{
+   STBI_FREE(retval_from_stbi_load);
+}
+
+#ifndef STBI_NO_LINEAR
+static float   *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp);
+#endif
+
+#ifndef STBI_NO_HDR
+static stbi_uc *stbi__hdr_to_ldr(float   *data, int x, int y, int comp);
+#endif
+
+static unsigned char *stbi_load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   #ifndef STBI_NO_JPEG
+   if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp);
+   #endif
+   #ifndef STBI_NO_PNG
+   if (stbi__png_test(s))  return stbi__png_load(s,x,y,comp,req_comp);
+   #endif
+   #ifndef STBI_NO_BMP
+   if (stbi__bmp_test(s))  return stbi__bmp_load(s,x,y,comp,req_comp);
+   #endif
+   #ifndef STBI_NO_GIF
+   if (stbi__gif_test(s))  return stbi__gif_load(s,x,y,comp,req_comp);
+   #endif
+   #ifndef STBI_NO_PSD
+   if (stbi__psd_test(s))  return stbi__psd_load(s,x,y,comp,req_comp);
+   #endif
+   #ifndef STBI_NO_PIC
+   if (stbi__pic_test(s))  return stbi__pic_load(s,x,y,comp,req_comp);
+   #endif
+   #ifndef STBI_NO_PNM
+   if (stbi__pnm_test(s))  return stbi__pnm_load(s,x,y,comp,req_comp);
+   #endif
+
+   #ifndef STBI_NO_HDR
+   if (stbi__hdr_test(s)) {
+      float *hdr = stbi__hdr_load(s, x,y,comp,req_comp);
+      return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp);
+   }
+   #endif
+
+   #ifndef STBI_NO_TGA
+   // test tga last because it's a crappy test!
+   if (stbi__tga_test(s))
+      return stbi__tga_load(s,x,y,comp,req_comp);
+   #endif
+
+   return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt");
+}
+
+#ifndef STBI_NO_STDIO
+
+static FILE *stbi__fopen(char const *filename, char const *mode)
+{
+   FILE *f;
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+   if (0 != fopen_s(&f, filename, mode))
+      f=0;
+#else
+   f = fopen(filename, mode);
+#endif
+   return f;
+}
+
+
+STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp)
+{
+   FILE *f = stbi__fopen(filename, "rb");
+   unsigned char *result;
+   if (!f) return stbi__errpuc("can't fopen", "Unable to open file");
+   result = stbi_load_from_file(f,x,y,comp,req_comp);
+   fclose(f);
+   return result;
+}
+
+STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)
+{
+   unsigned char *result;
+   stbi__context s;
+   stbi__start_file(&s,f);
+   result = stbi_load_main(&s,x,y,comp,req_comp);
+   if (result) {
+      // need to 'unget' all the characters in the IO buffer
+      fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);
+   }
+   return result;
+}
+#endif //!STBI_NO_STDIO
+
+STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__context s;
+   stbi__start_mem(&s,buffer,len);
+   return stbi_load_main(&s,x,y,comp,req_comp);
+}
+
+STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__context s;
+   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+   return stbi_load_main(&s,x,y,comp,req_comp);
+}
+
+#ifndef STBI_NO_LINEAR
+static float *stbi_loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   unsigned char *data;
+   #ifndef STBI_NO_HDR
+   if (stbi__hdr_test(s))
+      return stbi__hdr_load(s,x,y,comp,req_comp);
+   #endif
+   data = stbi_load_main(s, x, y, comp, req_comp);
+   if (data)
+      return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp);
+   return stbi__errpf("unknown image type", "Image not of any known type, or corrupt");
+}
+
+STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__context s;
+   stbi__start_mem(&s,buffer,len);
+   return stbi_loadf_main(&s,x,y,comp,req_comp);
+}
+
+STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__context s;
+   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+   return stbi_loadf_main(&s,x,y,comp,req_comp);
+}
+
+#ifndef STBI_NO_STDIO
+STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp)
+{
+   float *result;
+   FILE *f = stbi__fopen(filename, "rb");
+   if (!f) return stbi__errpf("can't fopen", "Unable to open file");
+   result = stbi_loadf_from_file(f,x,y,comp,req_comp);
+   fclose(f);
+   return result;
+}
+
+STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__context s;
+   stbi__start_file(&s,f);
+   return stbi_loadf_main(&s,x,y,comp,req_comp);
+}
+#endif // !STBI_NO_STDIO
+
+#endif // !STBI_NO_LINEAR
+
+// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is
+// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always
+// reports false!
+
+STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len)
+{
+   #ifndef STBI_NO_HDR
+   stbi__context s;
+   stbi__start_mem(&s,buffer,len);
+   return stbi__hdr_test(&s);
+   #else
+   STBI_NOTUSED(buffer);
+   STBI_NOTUSED(len);
+   return 0;
+   #endif
+}
+
+#ifndef STBI_NO_STDIO
+STBIDEF int      stbi_is_hdr          (char const *filename)
+{
+   FILE *f = stbi__fopen(filename, "rb");
+   int result=0;
+   if (f) {
+      result = stbi_is_hdr_from_file(f);
+      fclose(f);
+   }
+   return result;
+}
+
+STBIDEF int      stbi_is_hdr_from_file(FILE *f)
+{
+   #ifndef STBI_NO_HDR
+   stbi__context s;
+   stbi__start_file(&s,f);
+   return stbi__hdr_test(&s);
+   #else
+   return 0;
+   #endif
+}
+#endif // !STBI_NO_STDIO
+
+STBIDEF int      stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user)
+{
+   #ifndef STBI_NO_HDR
+   stbi__context s;
+   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+   return stbi__hdr_test(&s);
+   #else
+   return 0;
+   #endif
+}
+
+static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f;
+static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f;
+
+#ifndef STBI_NO_LINEAR
+STBIDEF void   stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; }
+STBIDEF void   stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; }
+#endif
+
+STBIDEF void   stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; }
+STBIDEF void   stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; }
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Common code used by all image loaders
+//
+
+enum
+{
+   STBI__SCAN_load=0,
+   STBI__SCAN_type,
+   STBI__SCAN_header
+};
+
+static void stbi__refill_buffer(stbi__context *s)
+{
+   int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen);
+   if (n == 0) {
+      // at end of file, treat same as if from memory, but need to handle case
+      // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file
+      s->read_from_callbacks = 0;
+      s->img_buffer = s->buffer_start;
+      s->img_buffer_end = s->buffer_start+1;
+      *s->img_buffer = 0;
+   } else {
+      s->img_buffer = s->buffer_start;
+      s->img_buffer_end = s->buffer_start + n;
+   }
+}
+
+stbi_inline static stbi_uc stbi__get8(stbi__context *s)
+{
+   if (s->img_buffer < s->img_buffer_end)
+      return *s->img_buffer++;
+   if (s->read_from_callbacks) {
+      stbi__refill_buffer(s);
+      return *s->img_buffer++;
+   }
+   return 0;
+}
+
+stbi_inline static int stbi__at_eof(stbi__context *s)
+{
+   if (s->io.read) {
+      if (!(s->io.eof)(s->io_user_data)) return 0;
+      // if feof() is true, check if buffer = end
+      // special case: we've only got the special 0 character at the end
+      if (s->read_from_callbacks == 0) return 1;
+   }
+
+   return s->img_buffer >= s->img_buffer_end;
+}
+
+static void stbi__skip(stbi__context *s, int n)
+{
+   if (s->io.read) {
+      int blen = (int) (s->img_buffer_end - s->img_buffer);
+      if (blen < n) {
+         s->img_buffer = s->img_buffer_end;
+         (s->io.skip)(s->io_user_data, n - blen);
+         return;
+      }
+   }
+   s->img_buffer += n;
+}
+
+static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n)
+{
+   if (s->io.read) {
+      int blen = (int) (s->img_buffer_end - s->img_buffer);
+      if (blen < n) {
+         int res, count;
+
+         memcpy(buffer, s->img_buffer, blen);
+
+         count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen);
+         res = (count == (n-blen));
+         s->img_buffer = s->img_buffer_end;
+         return res;
+      }
+   }
+
+   if (s->img_buffer+n <= s->img_buffer_end) {
+      memcpy(buffer, s->img_buffer, n);
+      s->img_buffer += n;
+      return 1;
+   } else
+      return 0;
+}
+
+static int stbi__get16be(stbi__context *s)
+{
+   int z = stbi__get8(s);
+   return (z << 8) + stbi__get8(s);
+}
+
+static stbi__uint32 stbi__get32be(stbi__context *s)
+{
+   stbi__uint32 z = stbi__get16be(s);
+   return (z << 16) + stbi__get16be(s);
+}
+
+static int stbi__get16le(stbi__context *s)
+{
+   int z = stbi__get8(s);
+   return z + (stbi__get8(s) << 8);
+}
+
+static stbi__uint32 stbi__get32le(stbi__context *s)
+{
+   stbi__uint32 z = stbi__get16le(s);
+   return z + (stbi__get16le(s) << 16);
+}
+
+#define STBI__BYTECAST(x)  ((stbi_uc) ((x) & 255))  // truncate int to byte without warnings
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+//  generic converter from built-in img_n to req_comp
+//    individual types do this automatically as much as possible (e.g. jpeg
+//    does all cases internally since it needs to colorspace convert anyway,
+//    and it never has alpha, so very few cases ). png can automatically
+//    interleave an alpha=255 channel, but falls back to this for other cases
+//
+//  assume data buffer is malloced, so malloc a new one and free that one
+//  only failure mode is malloc failing
+
+static stbi_uc stbi__compute_y(int r, int g, int b)
+{
+   return (stbi_uc) (((r*77) + (g*150) +  (29*b)) >> 8);
+}
+
+static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y)
+{
+   int i,j;
+   unsigned char *good;
+
+   if (req_comp == img_n) return data;
+   STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
+
+   good = (unsigned char *) stbi__malloc(req_comp * x * y);
+   if (good == NULL) {
+      STBI_FREE(data);
+      return stbi__errpuc("outofmem", "Out of memory");
+   }
+
+   for (j=0; j < (int) y; ++j) {
+      unsigned char *src  = data + j * x * img_n   ;
+      unsigned char *dest = good + j * x * req_comp;
+
+      #define COMBO(a,b)  ((a)*8+(b))
+      #define CASE(a,b)   case COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
+      // convert source image with img_n components to one with req_comp components;
+      // avoid switch per pixel, so use switch per scanline and massive macros
+      switch (COMBO(img_n, req_comp)) {
+         CASE(1,2) dest[0]=src[0], dest[1]=255; break;
+         CASE(1,3) dest[0]=dest[1]=dest[2]=src[0]; break;
+         CASE(1,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; break;
+         CASE(2,1) dest[0]=src[0]; break;
+         CASE(2,3) dest[0]=dest[1]=dest[2]=src[0]; break;
+         CASE(2,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; break;
+         CASE(3,4) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; break;
+         CASE(3,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break;
+         CASE(3,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; break;
+         CASE(4,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break;
+         CASE(4,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; break;
+         CASE(4,3) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; break;
+         default: STBI_ASSERT(0);
+      }
+      #undef CASE
+   }
+
+   STBI_FREE(data);
+   return good;
+}
+
+#ifndef STBI_NO_LINEAR
+static float   *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp)
+{
+   int i,k,n;
+   float *output = (float *) stbi__malloc(x * y * comp * sizeof(float));
+   if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); }
+   // compute number of non-alpha components
+   if (comp & 1) n = comp; else n = comp-1;
+   for (i=0; i < x*y; ++i) {
+      for (k=0; k < n; ++k) {
+         output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale);
+      }
+      if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f;
+   }
+   STBI_FREE(data);
+   return output;
+}
+#endif
+
+#ifndef STBI_NO_HDR
+#define stbi__float2int(x)   ((int) (x))
+static stbi_uc *stbi__hdr_to_ldr(float   *data, int x, int y, int comp)
+{
+   int i,k,n;
+   stbi_uc *output = (stbi_uc *) stbi__malloc(x * y * comp);
+   if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); }
+   // compute number of non-alpha components
+   if (comp & 1) n = comp; else n = comp-1;
+   for (i=0; i < x*y; ++i) {
+      for (k=0; k < n; ++k) {
+         float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f;
+         if (z < 0) z = 0;
+         if (z > 255) z = 255;
+         output[i*comp + k] = (stbi_uc) stbi__float2int(z);
+      }
+      if (k < comp) {
+         float z = data[i*comp+k] * 255 + 0.5f;
+         if (z < 0) z = 0;
+         if (z > 255) z = 255;
+         output[i*comp + k] = (stbi_uc) stbi__float2int(z);
+      }
+   }
+   STBI_FREE(data);
+   return output;
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+//  "baseline" JPEG/JFIF decoder
+//
+//    simple implementation
+//      - doesn't support delayed output of y-dimension
+//      - simple interface (only one output format: 8-bit interleaved RGB)
+//      - doesn't try to recover corrupt jpegs
+//      - doesn't allow partial loading, loading multiple at once
+//      - still fast on x86 (copying globals into locals doesn't help x86)
+//      - allocates lots of intermediate memory (full size of all components)
+//        - non-interleaved case requires this anyway
+//        - allows good upsampling (see next)
+//    high-quality
+//      - upsampled channels are bilinearly interpolated, even across blocks
+//      - quality integer IDCT derived from IJG's 'slow'
+//    performance
+//      - fast huffman; reasonable integer IDCT
+//      - some SIMD kernels for common paths on targets with SSE2/NEON
+//      - uses a lot of intermediate memory, could cache poorly
+
+#ifndef STBI_NO_JPEG
+
+// huffman decoding acceleration
+#define FAST_BITS   9  // larger handles more cases; smaller stomps less cache
+
+typedef struct
+{
+   stbi_uc  fast[1 << FAST_BITS];
+   // weirdly, repacking this into AoS is a 10% speed loss, instead of a win
+   stbi__uint16 code[256];
+   stbi_uc  values[256];
+   stbi_uc  size[257];
+   unsigned int maxcode[18];
+   int    delta[17];   // old 'firstsymbol' - old 'firstcode'
+} stbi__huffman;
+
+typedef struct
+{
+   stbi__context *s;
+   stbi__huffman huff_dc[4];
+   stbi__huffman huff_ac[4];
+   stbi_uc dequant[4][64];
+   stbi__int16 fast_ac[4][1 << FAST_BITS];
+
+// sizes for components, interleaved MCUs
+   int img_h_max, img_v_max;
+   int img_mcu_x, img_mcu_y;
+   int img_mcu_w, img_mcu_h;
+
+// definition of jpeg image component
+   struct
+   {
+      int id;
+      int h,v;
+      int tq;
+      int hd,ha;
+      int dc_pred;
+
+      int x,y,w2,h2;
+      stbi_uc *data;
+      void *raw_data, *raw_coeff;
+      stbi_uc *linebuf;
+      short   *coeff;   // progressive only
+      int      coeff_w, coeff_h; // number of 8x8 coefficient blocks
+   } img_comp[4];
+
+   stbi__uint32   code_buffer; // jpeg entropy-coded buffer
+   int            code_bits;   // number of valid bits
+   unsigned char  marker;      // marker seen while filling entropy buffer
+   int            nomore;      // flag if we saw a marker so must stop
+
+   int            progressive;
+   int            spec_start;
+   int            spec_end;
+   int            succ_high;
+   int            succ_low;
+   int            eob_run;
+
+   int scan_n, order[4];
+   int restart_interval, todo;
+
+// kernels
+   void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]);
+   void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step);
+   stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs);
+} stbi__jpeg;
+
+static int stbi__build_huffman(stbi__huffman *h, int *count)
+{
+   int i,j,k=0,code;
+   // build size list for each symbol (from JPEG spec)
+   for (i=0; i < 16; ++i)
+      for (j=0; j < count[i]; ++j)
+         h->size[k++] = (stbi_uc) (i+1);
+   h->size[k] = 0;
+
+   // compute actual symbols (from jpeg spec)
+   code = 0;
+   k = 0;
+   for(j=1; j <= 16; ++j) {
+      // compute delta to add to code to compute symbol id
+      h->delta[j] = k - code;
+      if (h->size[k] == j) {
+         while (h->size[k] == j)
+            h->code[k++] = (stbi__uint16) (code++);
+         if (code-1 >= (1 << j)) return stbi__err("bad code lengths","Corrupt JPEG");
+      }
+      // compute largest code + 1 for this size, preshifted as needed later
+      h->maxcode[j] = code << (16-j);
+      code <<= 1;
+   }
+   h->maxcode[j] = 0xffffffff;
+
+   // build non-spec acceleration table; 255 is flag for not-accelerated
+   memset(h->fast, 255, 1 << FAST_BITS);
+   for (i=0; i < k; ++i) {
+      int s = h->size[i];
+      if (s <= FAST_BITS) {
+         int c = h->code[i] << (FAST_BITS-s);
+         int m = 1 << (FAST_BITS-s);
+         for (j=0; j < m; ++j) {
+            h->fast[c+j] = (stbi_uc) i;
+         }
+      }
+   }
+   return 1;
+}
+
+// build a table that decodes both magnitude and value of small ACs in
+// one go.
+static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h)
+{
+   int i;
+   for (i=0; i < (1 << FAST_BITS); ++i) {
+      stbi_uc fast = h->fast[i];
+      fast_ac[i] = 0;
+      if (fast < 255) {
+         int rs = h->values[fast];
+         int run = (rs >> 4) & 15;
+         int magbits = rs & 15;
+         int len = h->size[fast];
+
+         if (magbits && len + magbits <= FAST_BITS) {
+            // magnitude code followed by receive_extend code
+            int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits);
+            int m = 1 << (magbits - 1);
+            if (k < m) k += (-1 << magbits) + 1;
+            // if the result is small enough, we can fit it in fast_ac table
+            if (k >= -128 && k <= 127)
+               fast_ac[i] = (stbi__int16) ((k << 8) + (run << 4) + (len + magbits));
+         }
+      }
+   }
+}
+
+static void stbi__grow_buffer_unsafe(stbi__jpeg *j)
+{
+   do {
+      int b = j->nomore ? 0 : stbi__get8(j->s);
+      if (b == 0xff) {
+         int c = stbi__get8(j->s);
+         if (c != 0) {
+            j->marker = (unsigned char) c;
+            j->nomore = 1;
+            return;
+         }
+      }
+      j->code_buffer |= b << (24 - j->code_bits);
+      j->code_bits += 8;
+   } while (j->code_bits <= 24);
+}
+
+// (1 << n) - 1
+static stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};
+
+// decode a jpeg huffman value from the bitstream
+stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h)
+{
+   unsigned int temp;
+   int c,k;
+
+   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+
+   // look at the top FAST_BITS and determine what symbol ID it is,
+   // if the code is <= FAST_BITS
+   c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+   k = h->fast[c];
+   if (k < 255) {
+      int s = h->size[k];
+      if (s > j->code_bits)
+         return -1;
+      j->code_buffer <<= s;
+      j->code_bits -= s;
+      return h->values[k];
+   }
+
+   // naive test is to shift the code_buffer down so k bits are
+   // valid, then test against maxcode. To speed this up, we've
+   // preshifted maxcode left so that it has (16-k) 0s at the
+   // end; in other words, regardless of the number of bits, it
+   // wants to be compared against something shifted to have 16;
+   // that way we don't need to shift inside the loop.
+   temp = j->code_buffer >> 16;
+   for (k=FAST_BITS+1 ; ; ++k)
+      if (temp < h->maxcode[k])
+         break;
+   if (k == 17) {
+      // error! code not found
+      j->code_bits -= 16;
+      return -1;
+   }
+
+   if (k > j->code_bits)
+      return -1;
+
+   // convert the huffman code to the symbol id
+   c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k];
+   STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]);
+
+   // convert the id to a symbol
+   j->code_bits -= k;
+   j->code_buffer <<= k;
+   return h->values[c];
+}
+
+// bias[n] = (-1<<n) + 1
+static int const stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};
+
+// combined JPEG 'receive' and JPEG 'extend', since baseline
+// always extends everything it receives.
+stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n)
+{
+   unsigned int k;
+   int sgn;
+   if (j->code_bits < n) stbi__grow_buffer_unsafe(j);
+
+   sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB
+   k = stbi_lrot(j->code_buffer, n);
+   j->code_buffer = k & ~stbi__bmask[n];
+   k &= stbi__bmask[n];
+   j->code_bits -= n;
+   return k + (stbi__jbias[n] & ~sgn);
+}
+
+// get some unsigned bits
+stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n)
+{
+   unsigned int k;
+   if (j->code_bits < n) stbi__grow_buffer_unsafe(j);
+   k = stbi_lrot(j->code_buffer, n);
+   j->code_buffer = k & ~stbi__bmask[n];
+   k &= stbi__bmask[n];
+   j->code_bits -= n;
+   return k;
+}
+
+stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j)
+{
+   unsigned int k;
+   if (j->code_bits < 1) stbi__grow_buffer_unsafe(j);
+   k = j->code_buffer;
+   j->code_buffer <<= 1;
+   --j->code_bits;
+   return k & 0x80000000;
+}
+
+// given a value that's at position X in the zigzag stream,
+// where does it appear in the 8x8 matrix coded as row-major?
+static stbi_uc stbi__jpeg_dezigzag[64+15] =
+{
+    0,  1,  8, 16,  9,  2,  3, 10,
+   17, 24, 32, 25, 18, 11,  4,  5,
+   12, 19, 26, 33, 40, 48, 41, 34,
+   27, 20, 13,  6,  7, 14, 21, 28,
+   35, 42, 49, 56, 57, 50, 43, 36,
+   29, 22, 15, 23, 30, 37, 44, 51,
+   58, 59, 52, 45, 38, 31, 39, 46,
+   53, 60, 61, 54, 47, 55, 62, 63,
+   // let corrupt input sample past end
+   63, 63, 63, 63, 63, 63, 63, 63,
+   63, 63, 63, 63, 63, 63, 63
+};
+
+// decode one 64-entry block--
+static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi_uc *dequant)
+{
+   int diff,dc,k;
+   int t;
+
+   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+   t = stbi__jpeg_huff_decode(j, hdc);
+   if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+
+   // 0 all the ac values now so we can do it 32-bits at a time
+   memset(data,0,64*sizeof(data[0]));
+
+   diff = t ? stbi__extend_receive(j, t) : 0;
+   dc = j->img_comp[b].dc_pred + diff;
+   j->img_comp[b].dc_pred = dc;
+   data[0] = (short) (dc * dequant[0]);
+
+   // decode AC components, see JPEG spec
+   k = 1;
+   do {
+      unsigned int zig;
+      int c,r,s;
+      if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+      c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+      r = fac[c];
+      if (r) { // fast-AC path
+         k += (r >> 4) & 15; // run
+         s = r & 15; // combined length
+         j->code_buffer <<= s;
+         j->code_bits -= s;
+         // decode into unzigzag'd location
+         zig = stbi__jpeg_dezigzag[k++];
+         data[zig] = (short) ((r >> 8) * dequant[zig]);
+      } else {
+         int rs = stbi__jpeg_huff_decode(j, hac);
+         if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+         s = rs & 15;
+         r = rs >> 4;
+         if (s == 0) {
+            if (rs != 0xf0) break; // end block
+            k += 16;
+         } else {
+            k += r;
+            // decode into unzigzag'd location
+            zig = stbi__jpeg_dezigzag[k++];
+            data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]);
+         }
+      }
+   } while (k < 64);
+   return 1;
+}
+
+static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b)
+{
+   int diff,dc;
+   int t;
+   if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
+
+   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+
+   if (j->succ_high == 0) {
+      // first scan for DC coefficient, must be first
+      memset(data,0,64*sizeof(data[0])); // 0 all the ac values now
+      t = stbi__jpeg_huff_decode(j, hdc);
+      diff = t ? stbi__extend_receive(j, t) : 0;
+
+      dc = j->img_comp[b].dc_pred + diff;
+      j->img_comp[b].dc_pred = dc;
+      data[0] = (short) (dc << j->succ_low);
+   } else {
+      // refinement scan for DC coefficient
+      if (stbi__jpeg_get_bit(j))
+         data[0] += (short) (1 << j->succ_low);
+   }
+   return 1;
+}
+
+// @OPTIMIZE: store non-zigzagged during the decode passes,
+// and only de-zigzag when dequantizing
+static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac)
+{
+   int k;
+   if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
+
+   if (j->succ_high == 0) {
+      int shift = j->succ_low;
+
+      if (j->eob_run) {
+         --j->eob_run;
+         return 1;
+      }
+
+      k = j->spec_start;
+      do {
+         unsigned int zig;
+         int c,r,s;
+         if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+         c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+         r = fac[c];
+         if (r) { // fast-AC path
+            k += (r >> 4) & 15; // run
+            s = r & 15; // combined length
+            j->code_buffer <<= s;
+            j->code_bits -= s;
+            zig = stbi__jpeg_dezigzag[k++];
+            data[zig] = (short) ((r >> 8) << shift);
+         } else {
+            int rs = stbi__jpeg_huff_decode(j, hac);
+            if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+            s = rs & 15;
+            r = rs >> 4;
+            if (s == 0) {
+               if (r < 15) {
+                  j->eob_run = (1 << r);
+                  if (r)
+                     j->eob_run += stbi__jpeg_get_bits(j, r);
+                  --j->eob_run;
+                  break;
+               }
+               k += 16;
+            } else {
+               k += r;
+               zig = stbi__jpeg_dezigzag[k++];
+               data[zig] = (short) (stbi__extend_receive(j,s) << shift);
+            }
+         }
+      } while (k <= j->spec_end);
+   } else {
+      // refinement scan for these AC coefficients
+
+      short bit = (short) (1 << j->succ_low);
+
+      if (j->eob_run) {
+         --j->eob_run;
+         for (k = j->spec_start; k <= j->spec_end; ++k) {
+            short *p = &data[stbi__jpeg_dezigzag[k]];
+            if (*p != 0)
+               if (stbi__jpeg_get_bit(j))
+                  if ((*p & bit)==0) {
+                     if (*p > 0)
+                        *p += bit;
+                     else
+                        *p -= bit;
+                  }
+         }
+      } else {
+         k = j->spec_start;
+         do {
+            int r,s;
+            int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh
+            if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+            s = rs & 15;
+            r = rs >> 4;
+            if (s == 0) {
+               if (r < 15) {
+                  j->eob_run = (1 << r) - 1;
+                  if (r)
+                     j->eob_run += stbi__jpeg_get_bits(j, r);
+                  r = 64; // force end of block
+               } else
+                  r = 16; // r=15 is the code for 16 0s
+            } else {
+               if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG");
+               // sign bit
+               if (stbi__jpeg_get_bit(j))
+                  s = bit;
+               else
+                  s = -bit;
+            }
+
+            // advance by r
+            while (k <= j->spec_end) {
+               short *p = &data[stbi__jpeg_dezigzag[k]];
+               if (*p != 0) {
+                  if (stbi__jpeg_get_bit(j))
+                     if ((*p & bit)==0) {
+                        if (*p > 0)
+                           *p += bit;
+                        else
+                           *p -= bit;
+                     }
+                  ++k;
+               } else {
+                  if (r == 0) {
+                     if (s)
+                        data[stbi__jpeg_dezigzag[k++]] = (short) s;
+                     break;
+                  }
+                  --r;
+                  ++k;
+               }
+            }
+         } while (k <= j->spec_end);
+      }
+   }
+   return 1;
+}
+
+// take a -128..127 value and stbi__clamp it and convert to 0..255
+stbi_inline static stbi_uc stbi__clamp(int x)
+{
+   // trick to use a single test to catch both cases
+   if ((unsigned int) x > 255) {
+      if (x < 0) return 0;
+      if (x > 255) return 255;
+   }
+   return (stbi_uc) x;
+}
+
+#define stbi__f2f(x)  ((int) (((x) * 4096 + 0.5)))
+#define stbi__fsh(x)  ((x) << 12)
+
+// derived from jidctint -- DCT_ISLOW
+#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \
+   int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \
+   p2 = s2;                                    \
+   p3 = s6;                                    \
+   p1 = (p2+p3) * stbi__f2f(0.5411961f);       \
+   t2 = p1 + p3*stbi__f2f(-1.847759065f);      \
+   t3 = p1 + p2*stbi__f2f( 0.765366865f);      \
+   p2 = s0;                                    \
+   p3 = s4;                                    \
+   t0 = stbi__fsh(p2+p3);                      \
+   t1 = stbi__fsh(p2-p3);                      \
+   x0 = t0+t3;                                 \
+   x3 = t0-t3;                                 \
+   x1 = t1+t2;                                 \
+   x2 = t1-t2;                                 \
+   t0 = s7;                                    \
+   t1 = s5;                                    \
+   t2 = s3;                                    \
+   t3 = s1;                                    \
+   p3 = t0+t2;                                 \
+   p4 = t1+t3;                                 \
+   p1 = t0+t3;                                 \
+   p2 = t1+t2;                                 \
+   p5 = (p3+p4)*stbi__f2f( 1.175875602f);      \
+   t0 = t0*stbi__f2f( 0.298631336f);           \
+   t1 = t1*stbi__f2f( 2.053119869f);           \
+   t2 = t2*stbi__f2f( 3.072711026f);           \
+   t3 = t3*stbi__f2f( 1.501321110f);           \
+   p1 = p5 + p1*stbi__f2f(-0.899976223f);      \
+   p2 = p5 + p2*stbi__f2f(-2.562915447f);      \
+   p3 = p3*stbi__f2f(-1.961570560f);           \
+   p4 = p4*stbi__f2f(-0.390180644f);           \
+   t3 += p1+p4;                                \
+   t2 += p2+p3;                                \
+   t1 += p2+p4;                                \
+   t0 += p1+p3;
+
+static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64])
+{
+   int i,val[64],*v=val;
+   stbi_uc *o;
+   short *d = data;
+
+   // columns
+   for (i=0; i < 8; ++i,++d, ++v) {
+      // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing
+      if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0
+           && d[40]==0 && d[48]==0 && d[56]==0) {
+         //    no shortcut                 0     seconds
+         //    (1|2|3|4|5|6|7)==0          0     seconds
+         //    all separate               -0.047 seconds
+         //    1 && 2|3 && 4|5 && 6|7:    -0.047 seconds
+         int dcterm = d[0] << 2;
+         v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm;
+      } else {
+         STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56])
+         // constants scaled things up by 1<<12; let's bring them back
+         // down, but keep 2 extra bits of precision
+         x0 += 512; x1 += 512; x2 += 512; x3 += 512;
+         v[ 0] = (x0+t3) >> 10;
+         v[56] = (x0-t3) >> 10;
+         v[ 8] = (x1+t2) >> 10;
+         v[48] = (x1-t2) >> 10;
+         v[16] = (x2+t1) >> 10;
+         v[40] = (x2-t1) >> 10;
+         v[24] = (x3+t0) >> 10;
+         v[32] = (x3-t0) >> 10;
+      }
+   }
+
+   for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) {
+      // no fast case since the first 1D IDCT spread components out
+      STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7])
+      // constants scaled things up by 1<<12, plus we had 1<<2 from first
+      // loop, plus horizontal and vertical each scale by sqrt(8) so together
+      // we've got an extra 1<<3, so 1<<17 total we need to remove.
+      // so we want to round that, which means adding 0.5 * 1<<17,
+      // aka 65536. Also, we'll end up with -128 to 127 that we want
+      // to encode as 0..255 by adding 128, so we'll add that before the shift
+      x0 += 65536 + (128<<17);
+      x1 += 65536 + (128<<17);
+      x2 += 65536 + (128<<17);
+      x3 += 65536 + (128<<17);
+      // tried computing the shifts into temps, or'ing the temps to see
+      // if any were out of range, but that was slower
+      o[0] = stbi__clamp((x0+t3) >> 17);
+      o[7] = stbi__clamp((x0-t3) >> 17);
+      o[1] = stbi__clamp((x1+t2) >> 17);
+      o[6] = stbi__clamp((x1-t2) >> 17);
+      o[2] = stbi__clamp((x2+t1) >> 17);
+      o[5] = stbi__clamp((x2-t1) >> 17);
+      o[3] = stbi__clamp((x3+t0) >> 17);
+      o[4] = stbi__clamp((x3-t0) >> 17);
+   }
+}
+
+#ifdef STBI_SSE2
+// sse2 integer IDCT. not the fastest possible implementation but it
+// produces bit-identical results to the generic C version so it's
+// fully "transparent".
+static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])
+{
+   // This is constructed to match our regular (generic) integer IDCT exactly.
+   __m128i row0, row1, row2, row3, row4, row5, row6, row7;
+   __m128i tmp;
+
+   // dot product constant: even elems=x, odd elems=y
+   #define dct_const(x,y)  _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y))
+
+   // out(0) = c0[even]*x + c0[odd]*y   (c0, x, y 16-bit, out 32-bit)
+   // out(1) = c1[even]*x + c1[odd]*y
+   #define dct_rot(out0,out1, x,y,c0,c1) \
+      __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \
+      __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \
+      __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \
+      __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \
+      __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \
+      __m128i out1##_h = _mm_madd_epi16(c0##hi, c1)
+
+   // out = in << 12  (in 16-bit, out 32-bit)
+   #define dct_widen(out, in) \
+      __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \
+      __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4)
+
+   // wide add
+   #define dct_wadd(out, a, b) \
+      __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \
+      __m128i out##_h = _mm_add_epi32(a##_h, b##_h)
+
+   // wide sub
+   #define dct_wsub(out, a, b) \
+      __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \
+      __m128i out##_h = _mm_sub_epi32(a##_h, b##_h)
+
+   // butterfly a/b, add bias, then shift by "s" and pack
+   #define dct_bfly32o(out0, out1, a,b,bias,s) \
+      { \
+         __m128i abiased_l = _mm_add_epi32(a##_l, bias); \
+         __m128i abiased_h = _mm_add_epi32(a##_h, bias); \
+         dct_wadd(sum, abiased, b); \
+         dct_wsub(dif, abiased, b); \
+         out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \
+         out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \
+      }
+
+   // 8-bit interleave step (for transposes)
+   #define dct_interleave8(a, b) \
+      tmp = a; \
+      a = _mm_unpacklo_epi8(a, b); \
+      b = _mm_unpackhi_epi8(tmp, b)
+
+   // 16-bit interleave step (for transposes)
+   #define dct_interleave16(a, b) \
+      tmp = a; \
+      a = _mm_unpacklo_epi16(a, b); \
+      b = _mm_unpackhi_epi16(tmp, b)
+
+   #define dct_pass(bias,shift) \
+      { \
+         /* even part */ \
+         dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \
+         __m128i sum04 = _mm_add_epi16(row0, row4); \
+         __m128i dif04 = _mm_sub_epi16(row0, row4); \
+         dct_widen(t0e, sum04); \
+         dct_widen(t1e, dif04); \
+         dct_wadd(x0, t0e, t3e); \
+         dct_wsub(x3, t0e, t3e); \
+         dct_wadd(x1, t1e, t2e); \
+         dct_wsub(x2, t1e, t2e); \
+         /* odd part */ \
+         dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \
+         dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \
+         __m128i sum17 = _mm_add_epi16(row1, row7); \
+         __m128i sum35 = _mm_add_epi16(row3, row5); \
+         dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \
+         dct_wadd(x4, y0o, y4o); \
+         dct_wadd(x5, y1o, y5o); \
+         dct_wadd(x6, y2o, y5o); \
+         dct_wadd(x7, y3o, y4o); \
+         dct_bfly32o(row0,row7, x0,x7,bias,shift); \
+         dct_bfly32o(row1,row6, x1,x6,bias,shift); \
+         dct_bfly32o(row2,row5, x2,x5,bias,shift); \
+         dct_bfly32o(row3,row4, x3,x4,bias,shift); \
+      }
+
+   __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f));
+   __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f));
+   __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f));
+   __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f));
+   __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f));
+   __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f));
+   __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f));
+   __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f));
+
+   // rounding biases in column/row passes, see stbi__idct_block for explanation.
+   __m128i bias_0 = _mm_set1_epi32(512);
+   __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17));
+
+   // load
+   row0 = _mm_load_si128((const __m128i *) (data + 0*8));
+   row1 = _mm_load_si128((const __m128i *) (data + 1*8));
+   row2 = _mm_load_si128((const __m128i *) (data + 2*8));
+   row3 = _mm_load_si128((const __m128i *) (data + 3*8));
+   row4 = _mm_load_si128((const __m128i *) (data + 4*8));
+   row5 = _mm_load_si128((const __m128i *) (data + 5*8));
+   row6 = _mm_load_si128((const __m128i *) (data + 6*8));
+   row7 = _mm_load_si128((const __m128i *) (data + 7*8));
+
+   // column pass
+   dct_pass(bias_0, 10);
+
+   {
+      // 16bit 8x8 transpose pass 1
+      dct_interleave16(row0, row4);
+      dct_interleave16(row1, row5);
+      dct_interleave16(row2, row6);
+      dct_interleave16(row3, row7);
+
+      // transpose pass 2
+      dct_interleave16(row0, row2);
+      dct_interleave16(row1, row3);
+      dct_interleave16(row4, row6);
+      dct_interleave16(row5, row7);
+
+      // transpose pass 3
+      dct_interleave16(row0, row1);
+      dct_interleave16(row2, row3);
+      dct_interleave16(row4, row5);
+      dct_interleave16(row6, row7);
+   }
+
+   // row pass
+   dct_pass(bias_1, 17);
+
+   {
+      // pack
+      __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7
+      __m128i p1 = _mm_packus_epi16(row2, row3);
+      __m128i p2 = _mm_packus_epi16(row4, row5);
+      __m128i p3 = _mm_packus_epi16(row6, row7);
+
+      // 8bit 8x8 transpose pass 1
+      dct_interleave8(p0, p2); // a0e0a1e1...
+      dct_interleave8(p1, p3); // c0g0c1g1...
+
+      // transpose pass 2
+      dct_interleave8(p0, p1); // a0c0e0g0...
+      dct_interleave8(p2, p3); // b0d0f0h0...
+
+      // transpose pass 3
+      dct_interleave8(p0, p2); // a0b0c0d0...
+      dct_interleave8(p1, p3); // a4b4c4d4...
+
+      // store
+      _mm_storel_epi64((__m128i *) out, p0); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, p2); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, p1); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, p3); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e));
+   }
+
+#undef dct_const
+#undef dct_rot
+#undef dct_widen
+#undef dct_wadd
+#undef dct_wsub
+#undef dct_bfly32o
+#undef dct_interleave8
+#undef dct_interleave16
+#undef dct_pass
+}
+
+#endif // STBI_SSE2
+
+#ifdef STBI_NEON
+
+// NEON integer IDCT. should produce bit-identical
+// results to the generic C version.
+static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])
+{
+   int16x8_t row0, row1, row2, row3, row4, row5, row6, row7;
+
+   int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f));
+   int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f));
+   int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f));
+   int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f));
+   int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f));
+   int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f));
+   int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f));
+   int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f));
+   int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f));
+   int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f));
+   int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f));
+   int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f));
+
+#define dct_long_mul(out, inq, coeff) \
+   int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \
+   int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff)
+
+#define dct_long_mac(out, acc, inq, coeff) \
+   int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \
+   int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff)
+
+#define dct_widen(out, inq) \
+   int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \
+   int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12)
+
+// wide add
+#define dct_wadd(out, a, b) \
+   int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \
+   int32x4_t out##_h = vaddq_s32(a##_h, b##_h)
+
+// wide sub
+#define dct_wsub(out, a, b) \
+   int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \
+   int32x4_t out##_h = vsubq_s32(a##_h, b##_h)
+
+// butterfly a/b, then shift using "shiftop" by "s" and pack
+#define dct_bfly32o(out0,out1, a,b,shiftop,s) \
+   { \
+      dct_wadd(sum, a, b); \
+      dct_wsub(dif, a, b); \
+      out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \
+      out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \
+   }
+
+#define dct_pass(shiftop, shift) \
+   { \
+      /* even part */ \
+      int16x8_t sum26 = vaddq_s16(row2, row6); \
+      dct_long_mul(p1e, sum26, rot0_0); \
+      dct_long_mac(t2e, p1e, row6, rot0_1); \
+      dct_long_mac(t3e, p1e, row2, rot0_2); \
+      int16x8_t sum04 = vaddq_s16(row0, row4); \
+      int16x8_t dif04 = vsubq_s16(row0, row4); \
+      dct_widen(t0e, sum04); \
+      dct_widen(t1e, dif04); \
+      dct_wadd(x0, t0e, t3e); \
+      dct_wsub(x3, t0e, t3e); \
+      dct_wadd(x1, t1e, t2e); \
+      dct_wsub(x2, t1e, t2e); \
+      /* odd part */ \
+      int16x8_t sum15 = vaddq_s16(row1, row5); \
+      int16x8_t sum17 = vaddq_s16(row1, row7); \
+      int16x8_t sum35 = vaddq_s16(row3, row5); \
+      int16x8_t sum37 = vaddq_s16(row3, row7); \
+      int16x8_t sumodd = vaddq_s16(sum17, sum35); \
+      dct_long_mul(p5o, sumodd, rot1_0); \
+      dct_long_mac(p1o, p5o, sum17, rot1_1); \
+      dct_long_mac(p2o, p5o, sum35, rot1_2); \
+      dct_long_mul(p3o, sum37, rot2_0); \
+      dct_long_mul(p4o, sum15, rot2_1); \
+      dct_wadd(sump13o, p1o, p3o); \
+      dct_wadd(sump24o, p2o, p4o); \
+      dct_wadd(sump23o, p2o, p3o); \
+      dct_wadd(sump14o, p1o, p4o); \
+      dct_long_mac(x4, sump13o, row7, rot3_0); \
+      dct_long_mac(x5, sump24o, row5, rot3_1); \
+      dct_long_mac(x6, sump23o, row3, rot3_2); \
+      dct_long_mac(x7, sump14o, row1, rot3_3); \
+      dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \
+      dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \
+      dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \
+      dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \
+   }
+
+   // load
+   row0 = vld1q_s16(data + 0*8);
+   row1 = vld1q_s16(data + 1*8);
+   row2 = vld1q_s16(data + 2*8);
+   row3 = vld1q_s16(data + 3*8);
+   row4 = vld1q_s16(data + 4*8);
+   row5 = vld1q_s16(data + 5*8);
+   row6 = vld1q_s16(data + 6*8);
+   row7 = vld1q_s16(data + 7*8);
+
+   // add DC bias
+   row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0));
+
+   // column pass
+   dct_pass(vrshrn_n_s32, 10);
+
+   // 16bit 8x8 transpose
+   {
+// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively.
+// whether compilers actually get this is another story, sadly.
+#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; }
+#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); }
+#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); }
+
+      // pass 1
+      dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6
+      dct_trn16(row2, row3);
+      dct_trn16(row4, row5);
+      dct_trn16(row6, row7);
+
+      // pass 2
+      dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4
+      dct_trn32(row1, row3);
+      dct_trn32(row4, row6);
+      dct_trn32(row5, row7);
+
+      // pass 3
+      dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0
+      dct_trn64(row1, row5);
+      dct_trn64(row2, row6);
+      dct_trn64(row3, row7);
+
+#undef dct_trn16
+#undef dct_trn32
+#undef dct_trn64
+   }
+
+   // row pass
+   // vrshrn_n_s32 only supports shifts up to 16, we need
+   // 17. so do a non-rounding shift of 16 first then follow
+   // up with a rounding shift by 1.
+   dct_pass(vshrn_n_s32, 16);
+
+   {
+      // pack and round
+      uint8x8_t p0 = vqrshrun_n_s16(row0, 1);
+      uint8x8_t p1 = vqrshrun_n_s16(row1, 1);
+      uint8x8_t p2 = vqrshrun_n_s16(row2, 1);
+      uint8x8_t p3 = vqrshrun_n_s16(row3, 1);
+      uint8x8_t p4 = vqrshrun_n_s16(row4, 1);
+      uint8x8_t p5 = vqrshrun_n_s16(row5, 1);
+      uint8x8_t p6 = vqrshrun_n_s16(row6, 1);
+      uint8x8_t p7 = vqrshrun_n_s16(row7, 1);
+
+      // again, these can translate into one instruction, but often don't.
+#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; }
+#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); }
+#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); }
+
+      // sadly can't use interleaved stores here since we only write
+      // 8 bytes to each scan line!
+
+      // 8x8 8-bit transpose pass 1
+      dct_trn8_8(p0, p1);
+      dct_trn8_8(p2, p3);
+      dct_trn8_8(p4, p5);
+      dct_trn8_8(p6, p7);
+
+      // pass 2
+      dct_trn8_16(p0, p2);
+      dct_trn8_16(p1, p3);
+      dct_trn8_16(p4, p6);
+      dct_trn8_16(p5, p7);
+
+      // pass 3
+      dct_trn8_32(p0, p4);
+      dct_trn8_32(p1, p5);
+      dct_trn8_32(p2, p6);
+      dct_trn8_32(p3, p7);
+
+      // store
+      vst1_u8(out, p0); out += out_stride;
+      vst1_u8(out, p1); out += out_stride;
+      vst1_u8(out, p2); out += out_stride;
+      vst1_u8(out, p3); out += out_stride;
+      vst1_u8(out, p4); out += out_stride;
+      vst1_u8(out, p5); out += out_stride;
+      vst1_u8(out, p6); out += out_stride;
+      vst1_u8(out, p7);
+
+#undef dct_trn8_8
+#undef dct_trn8_16
+#undef dct_trn8_32
+   }
+
+#undef dct_long_mul
+#undef dct_long_mac
+#undef dct_widen
+#undef dct_wadd
+#undef dct_wsub
+#undef dct_bfly32o
+#undef dct_pass
+}
+
+#endif // STBI_NEON
+
+#define STBI__MARKER_none  0xff
+// if there's a pending marker from the entropy stream, return that
+// otherwise, fetch from the stream and get a marker. if there's no
+// marker, return 0xff, which is never a valid marker value
+static stbi_uc stbi__get_marker(stbi__jpeg *j)
+{
+   stbi_uc x;
+   if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; }
+   x = stbi__get8(j->s);
+   if (x != 0xff) return STBI__MARKER_none;
+   while (x == 0xff)
+      x = stbi__get8(j->s);
+   return x;
+}
+
+// in each scan, we'll have scan_n components, and the order
+// of the components is specified by order[]
+#define STBI__RESTART(x)     ((x) >= 0xd0 && (x) <= 0xd7)
+
+// after a restart interval, stbi__jpeg_reset the entropy decoder and
+// the dc prediction
+static void stbi__jpeg_reset(stbi__jpeg *j)
+{
+   j->code_bits = 0;
+   j->code_buffer = 0;
+   j->nomore = 0;
+   j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = 0;
+   j->marker = STBI__MARKER_none;
+   j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff;
+   j->eob_run = 0;
+   // no more than 1<<31 MCUs if no restart_interal? that's plenty safe,
+   // since we don't even allow 1<<30 pixels
+}
+
+static int stbi__parse_entropy_coded_data(stbi__jpeg *z)
+{
+   stbi__jpeg_reset(z);
+   if (!z->progressive) {
+      if (z->scan_n == 1) {
+         int i,j;
+         STBI_SIMD_ALIGN(short, data[64]);
+         int n = z->order[0];
+         // non-interleaved data, we just need to process one block at a time,
+         // in trivial scanline order
+         // number of blocks to do just depends on how many actual "pixels" this
+         // component has, independent of interleaved MCU blocking and such
+         int w = (z->img_comp[n].x+7) >> 3;
+         int h = (z->img_comp[n].y+7) >> 3;
+         for (j=0; j < h; ++j) {
+            for (i=0; i < w; ++i) {
+               int ha = z->img_comp[n].ha;
+               if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0;
+               z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data);
+               // every data block is an MCU, so countdown the restart interval
+               if (--z->todo <= 0) {
+                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+                  // if it's NOT a restart, then just bail, so we get corrupt data
+                  // rather than no data
+                  if (!STBI__RESTART(z->marker)) return 1;
+                  stbi__jpeg_reset(z);
+               }
+            }
+         }
+         return 1;
+      } else { // interleaved
+         int i,j,k,x,y;
+         STBI_SIMD_ALIGN(short, data[64]);
+         for (j=0; j < z->img_mcu_y; ++j) {
+            for (i=0; i < z->img_mcu_x; ++i) {
+               // scan an interleaved mcu... process scan_n components in order
+               for (k=0; k < z->scan_n; ++k) {
+                  int n = z->order[k];
+                  // scan out an mcu's worth of this component; that's just determined
+                  // by the basic H and V specified for the component
+                  for (y=0; y < z->img_comp[n].v; ++y) {
+                     for (x=0; x < z->img_comp[n].h; ++x) {
+                        int x2 = (i*z->img_comp[n].h + x)*8;
+                        int y2 = (j*z->img_comp[n].v + y)*8;
+                        int ha = z->img_comp[n].ha;
+                        if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0;
+                        z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data);
+                     }
+                  }
+               }
+               // after all interleaved components, that's an interleaved MCU,
+               // so now count down the restart interval
+               if (--z->todo <= 0) {
+                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+                  if (!STBI__RESTART(z->marker)) return 1;
+                  stbi__jpeg_reset(z);
+               }
+            }
+         }
+         return 1;
+      }
+   } else {
+      if (z->scan_n == 1) {
+         int i,j;
+         int n = z->order[0];
+         // non-interleaved data, we just need to process one block at a time,
+         // in trivial scanline order
+         // number of blocks to do just depends on how many actual "pixels" this
+         // component has, independent of interleaved MCU blocking and such
+         int w = (z->img_comp[n].x+7) >> 3;
+         int h = (z->img_comp[n].y+7) >> 3;
+         for (j=0; j < h; ++j) {
+            for (i=0; i < w; ++i) {
+               short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);
+               if (z->spec_start == 0) {
+                  if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))
+                     return 0;
+               } else {
+                  int ha = z->img_comp[n].ha;
+                  if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha]))
+                     return 0;
+               }
+               // every data block is an MCU, so countdown the restart interval
+               if (--z->todo <= 0) {
+                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+                  if (!STBI__RESTART(z->marker)) return 1;
+                  stbi__jpeg_reset(z);
+               }
+            }
+         }
+         return 1;
+      } else { // interleaved
+         int i,j,k,x,y;
+         for (j=0; j < z->img_mcu_y; ++j) {
+            for (i=0; i < z->img_mcu_x; ++i) {
+               // scan an interleaved mcu... process scan_n components in order
+               for (k=0; k < z->scan_n; ++k) {
+                  int n = z->order[k];
+                  // scan out an mcu's worth of this component; that's just determined
+                  // by the basic H and V specified for the component
+                  for (y=0; y < z->img_comp[n].v; ++y) {
+                     for (x=0; x < z->img_comp[n].h; ++x) {
+                        int x2 = (i*z->img_comp[n].h + x);
+                        int y2 = (j*z->img_comp[n].v + y);
+                        short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w);
+                        if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))
+                           return 0;
+                     }
+                  }
+               }
+               // after all interleaved components, that's an interleaved MCU,
+               // so now count down the restart interval
+               if (--z->todo <= 0) {
+                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+                  if (!STBI__RESTART(z->marker)) return 1;
+                  stbi__jpeg_reset(z);
+               }
+            }
+         }
+         return 1;
+      }
+   }
+}
+
+static void stbi__jpeg_dequantize(short *data, stbi_uc *dequant)
+{
+   int i;
+   for (i=0; i < 64; ++i)
+      data[i] *= dequant[i];
+}
+
+static void stbi__jpeg_finish(stbi__jpeg *z)
+{
+   if (z->progressive) {
+      // dequantize and idct the data
+      int i,j,n;
+      for (n=0; n < z->s->img_n; ++n) {
+         int w = (z->img_comp[n].x+7) >> 3;
+         int h = (z->img_comp[n].y+7) >> 3;
+         for (j=0; j < h; ++j) {
+            for (i=0; i < w; ++i) {
+               short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);
+               stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]);
+               z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data);
+            }
+         }
+      }
+   }
+}
+
+static int stbi__process_marker(stbi__jpeg *z, int m)
+{
+   int L;
+   switch (m) {
+      case STBI__MARKER_none: // no marker found
+         return stbi__err("expected marker","Corrupt JPEG");
+
+      case 0xDD: // DRI - specify restart interval
+         if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG");
+         z->restart_interval = stbi__get16be(z->s);
+         return 1;
+
+      case 0xDB: // DQT - define quantization table
+         L = stbi__get16be(z->s)-2;
+         while (L > 0) {
+            int q = stbi__get8(z->s);
+            int p = q >> 4;
+            int t = q & 15,i;
+            if (p != 0) return stbi__err("bad DQT type","Corrupt JPEG");
+            if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG");
+            for (i=0; i < 64; ++i)
+               z->dequant[t][stbi__jpeg_dezigzag[i]] = stbi__get8(z->s);
+            L -= 65;
+         }
+         return L==0;
+
+      case 0xC4: // DHT - define huffman table
+         L = stbi__get16be(z->s)-2;
+         while (L > 0) {
+            stbi_uc *v;
+            int sizes[16],i,n=0;
+            int q = stbi__get8(z->s);
+            int tc = q >> 4;
+            int th = q & 15;
+            if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG");
+            for (i=0; i < 16; ++i) {
+               sizes[i] = stbi__get8(z->s);
+               n += sizes[i];
+            }
+            L -= 17;
+            if (tc == 0) {
+               if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0;
+               v = z->huff_dc[th].values;
+            } else {
+               if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0;
+               v = z->huff_ac[th].values;
+            }
+            for (i=0; i < n; ++i)
+               v[i] = stbi__get8(z->s);
+            if (tc != 0)
+               stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th);
+            L -= n;
+         }
+         return L==0;
+   }
+   // check for comment block or APP blocks
+   if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) {
+      stbi__skip(z->s, stbi__get16be(z->s)-2);
+      return 1;
+   }
+   return 0;
+}
+
+// after we see SOS
+static int stbi__process_scan_header(stbi__jpeg *z)
+{
+   int i;
+   int Ls = stbi__get16be(z->s);
+   z->scan_n = stbi__get8(z->s);
+   if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG");
+   if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG");
+   for (i=0; i < z->scan_n; ++i) {
+      int id = stbi__get8(z->s), which;
+      int q = stbi__get8(z->s);
+      for (which = 0; which < z->s->img_n; ++which)
+         if (z->img_comp[which].id == id)
+            break;
+      if (which == z->s->img_n) return 0; // no match
+      z->img_comp[which].hd = q >> 4;   if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG");
+      z->img_comp[which].ha = q & 15;   if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG");
+      z->order[i] = which;
+   }
+
+   {
+      int aa;
+      z->spec_start = stbi__get8(z->s);
+      z->spec_end   = stbi__get8(z->s); // should be 63, but might be 0
+      aa = stbi__get8(z->s);
+      z->succ_high = (aa >> 4);
+      z->succ_low  = (aa & 15);
+      if (z->progressive) {
+         if (z->spec_start > 63 || z->spec_end > 63  || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13)
+            return stbi__err("bad SOS", "Corrupt JPEG");
+      } else {
+         if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG");
+         if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG");
+         z->spec_end = 63;
+      }
+   }
+
+   return 1;
+}
+
+static int stbi__process_frame_header(stbi__jpeg *z, int scan)
+{
+   stbi__context *s = z->s;
+   int Lf,p,i,q, h_max=1,v_max=1,c;
+   Lf = stbi__get16be(s);         if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG
+   p  = stbi__get8(s);            if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline
+   s->img_y = stbi__get16be(s);   if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG
+   s->img_x = stbi__get16be(s);   if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires
+   c = stbi__get8(s);
+   if (c != 3 && c != 1) return stbi__err("bad component count","Corrupt JPEG");    // JFIF requires
+   s->img_n = c;
+   for (i=0; i < c; ++i) {
+      z->img_comp[i].data = NULL;
+      z->img_comp[i].linebuf = NULL;
+   }
+
+   if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG");
+
+   for (i=0; i < s->img_n; ++i) {
+      z->img_comp[i].id = stbi__get8(s);
+      if (z->img_comp[i].id != i+1)   // JFIF requires
+         if (z->img_comp[i].id != i)  // some version of jpegtran outputs non-JFIF-compliant files!
+            return stbi__err("bad component ID","Corrupt JPEG");
+      q = stbi__get8(s);
+      z->img_comp[i].h = (q >> 4);  if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG");
+      z->img_comp[i].v = q & 15;    if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG");
+      z->img_comp[i].tq = stbi__get8(s);  if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG");
+   }
+
+   if (scan != STBI__SCAN_load) return 1;
+
+   if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode");
+
+   for (i=0; i < s->img_n; ++i) {
+      if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h;
+      if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v;
+   }
+
+   // compute interleaved mcu info
+   z->img_h_max = h_max;
+   z->img_v_max = v_max;
+   z->img_mcu_w = h_max * 8;
+   z->img_mcu_h = v_max * 8;
+   z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w;
+   z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h;
+
+   for (i=0; i < s->img_n; ++i) {
+      // number of effective pixels (e.g. for non-interleaved MCU)
+      z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max;
+      z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max;
+      // to simplify generation, we'll allocate enough memory to decode
+      // the bogus oversized data from using interleaved MCUs and their
+      // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't
+      // discard the extra data until colorspace conversion
+      z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8;
+      z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8;
+      z->img_comp[i].raw_data = stbi__malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15);
+
+      if (z->img_comp[i].raw_data == NULL) {
+         for(--i; i >= 0; --i) {
+            STBI_FREE(z->img_comp[i].raw_data);
+            z->img_comp[i].data = NULL;
+         }
+         return stbi__err("outofmem", "Out of memory");
+      }
+      // align blocks for idct using mmx/sse
+      z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15);
+      z->img_comp[i].linebuf = NULL;
+      if (z->progressive) {
+         z->img_comp[i].coeff_w = (z->img_comp[i].w2 + 7) >> 3;
+         z->img_comp[i].coeff_h = (z->img_comp[i].h2 + 7) >> 3;
+         z->img_comp[i].raw_coeff = STBI_MALLOC(z->img_comp[i].coeff_w * z->img_comp[i].coeff_h * 64 * sizeof(short) + 15);
+         z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15);
+      } else {
+         z->img_comp[i].coeff = 0;
+         z->img_comp[i].raw_coeff = 0;
+      }
+   }
+
+   return 1;
+}
+
+// use comparisons since in some cases we handle more than one case (e.g. SOF)
+#define stbi__DNL(x)         ((x) == 0xdc)
+#define stbi__SOI(x)         ((x) == 0xd8)
+#define stbi__EOI(x)         ((x) == 0xd9)
+#define stbi__SOF(x)         ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2)
+#define stbi__SOS(x)         ((x) == 0xda)
+
+#define stbi__SOF_progressive(x)   ((x) == 0xc2)
+
+static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)
+{
+   int m;
+   z->marker = STBI__MARKER_none; // initialize cached marker to empty
+   m = stbi__get_marker(z);
+   if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG");
+   if (scan == STBI__SCAN_type) return 1;
+   m = stbi__get_marker(z);
+   while (!stbi__SOF(m)) {
+      if (!stbi__process_marker(z,m)) return 0;
+      m = stbi__get_marker(z);
+      while (m == STBI__MARKER_none) {
+         // some files have extra padding after their blocks, so ok, we'll scan
+         if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG");
+         m = stbi__get_marker(z);
+      }
+   }
+   z->progressive = stbi__SOF_progressive(m);
+   if (!stbi__process_frame_header(z, scan)) return 0;
+   return 1;
+}
+
+// decode image to YCbCr format
+static int stbi__decode_jpeg_image(stbi__jpeg *j)
+{
+   int m;
+   j->restart_interval = 0;
+   if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0;
+   m = stbi__get_marker(j);
+   while (!stbi__EOI(m)) {
+      if (stbi__SOS(m)) {
+         if (!stbi__process_scan_header(j)) return 0;
+         if (!stbi__parse_entropy_coded_data(j)) return 0;
+         if (j->marker == STBI__MARKER_none ) {
+            // handle 0s at the end of image data from IP Kamera 9060
+            while (!stbi__at_eof(j->s)) {
+               int x = stbi__get8(j->s);
+               if (x == 255) {
+                  j->marker = stbi__get8(j->s);
+                  break;
+               } else if (x != 0) {
+                  return stbi__err("junk before marker", "Corrupt JPEG");
+               }
+            }
+            // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0
+         }
+      } else {
+         if (!stbi__process_marker(j, m)) return 0;
+      }
+      m = stbi__get_marker(j);
+   }
+   if (j->progressive)
+      stbi__jpeg_finish(j);
+   return 1;
+}
+
+// static jfif-centered resampling (across block boundaries)
+
+typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1,
+                                    int w, int hs);
+
+#define stbi__div4(x) ((stbi_uc) ((x) >> 2))
+
+static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+   STBI_NOTUSED(out);
+   STBI_NOTUSED(in_far);
+   STBI_NOTUSED(w);
+   STBI_NOTUSED(hs);
+   return in_near;
+}
+
+static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+   // need to generate two samples vertically for every one in input
+   int i;
+   STBI_NOTUSED(hs);
+   for (i=0; i < w; ++i)
+      out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2);
+   return out;
+}
+
+static stbi_uc*  stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+   // need to generate two samples horizontally for every one in input
+   int i;
+   stbi_uc *input = in_near;
+
+   if (w == 1) {
+      // if only one sample, can't do any interpolation
+      out[0] = out[1] = input[0];
+      return out;
+   }
+
+   out[0] = input[0];
+   out[1] = stbi__div4(input[0]*3 + input[1] + 2);
+   for (i=1; i < w-1; ++i) {
+      int n = 3*input[i]+2;
+      out[i*2+0] = stbi__div4(n+input[i-1]);
+      out[i*2+1] = stbi__div4(n+input[i+1]);
+   }
+   out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2);
+   out[i*2+1] = input[w-1];
+
+   STBI_NOTUSED(in_far);
+   STBI_NOTUSED(hs);
+
+   return out;
+}
+
+#define stbi__div16(x) ((stbi_uc) ((x) >> 4))
+
+static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+   // need to generate 2x2 samples for every one in input
+   int i,t0,t1;
+   if (w == 1) {
+      out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);
+      return out;
+   }
+
+   t1 = 3*in_near[0] + in_far[0];
+   out[0] = stbi__div4(t1+2);
+   for (i=1; i < w; ++i) {
+      t0 = t1;
+      t1 = 3*in_near[i]+in_far[i];
+      out[i*2-1] = stbi__div16(3*t0 + t1 + 8);
+      out[i*2  ] = stbi__div16(3*t1 + t0 + 8);
+   }
+   out[w*2-1] = stbi__div4(t1+2);
+
+   STBI_NOTUSED(hs);
+
+   return out;
+}
+
+#if defined(STBI_SSE2) || defined(STBI_NEON)
+static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+   // need to generate 2x2 samples for every one in input
+   int i=0,t0,t1;
+
+   if (w == 1) {
+      out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);
+      return out;
+   }
+
+   t1 = 3*in_near[0] + in_far[0];
+   // process groups of 8 pixels for as long as we can.
+   // note we can't handle the last pixel in a row in this loop
+   // because we need to handle the filter boundary conditions.
+   for (; i < ((w-1) & ~7); i += 8) {
+#if defined(STBI_SSE2)
+      // load and perform the vertical filtering pass
+      // this uses 3*x + y = 4*x + (y - x)
+      __m128i zero  = _mm_setzero_si128();
+      __m128i farb  = _mm_loadl_epi64((__m128i *) (in_far + i));
+      __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i));
+      __m128i farw  = _mm_unpacklo_epi8(farb, zero);
+      __m128i nearw = _mm_unpacklo_epi8(nearb, zero);
+      __m128i diff  = _mm_sub_epi16(farw, nearw);
+      __m128i nears = _mm_slli_epi16(nearw, 2);
+      __m128i curr  = _mm_add_epi16(nears, diff); // current row
+
+      // horizontal filter works the same based on shifted vers of current
+      // row. "prev" is current row shifted right by 1 pixel; we need to
+      // insert the previous pixel value (from t1).
+      // "next" is current row shifted left by 1 pixel, with first pixel
+      // of next block of 8 pixels added in.
+      __m128i prv0 = _mm_slli_si128(curr, 2);
+      __m128i nxt0 = _mm_srli_si128(curr, 2);
+      __m128i prev = _mm_insert_epi16(prv0, t1, 0);
+      __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7);
+
+      // horizontal filter, polyphase implementation since it's convenient:
+      // even pixels = 3*cur + prev = cur*4 + (prev - cur)
+      // odd  pixels = 3*cur + next = cur*4 + (next - cur)
+      // note the shared term.
+      __m128i bias  = _mm_set1_epi16(8);
+      __m128i curs = _mm_slli_epi16(curr, 2);
+      __m128i prvd = _mm_sub_epi16(prev, curr);
+      __m128i nxtd = _mm_sub_epi16(next, curr);
+      __m128i curb = _mm_add_epi16(curs, bias);
+      __m128i even = _mm_add_epi16(prvd, curb);
+      __m128i odd  = _mm_add_epi16(nxtd, curb);
+
+      // interleave even and odd pixels, then undo scaling.
+      __m128i int0 = _mm_unpacklo_epi16(even, odd);
+      __m128i int1 = _mm_unpackhi_epi16(even, odd);
+      __m128i de0  = _mm_srli_epi16(int0, 4);
+      __m128i de1  = _mm_srli_epi16(int1, 4);
+
+      // pack and write output
+      __m128i outv = _mm_packus_epi16(de0, de1);
+      _mm_storeu_si128((__m128i *) (out + i*2), outv);
+#elif defined(STBI_NEON)
+      // load and perform the vertical filtering pass
+      // this uses 3*x + y = 4*x + (y - x)
+      uint8x8_t farb  = vld1_u8(in_far + i);
+      uint8x8_t nearb = vld1_u8(in_near + i);
+      int16x8_t diff  = vreinterpretq_s16_u16(vsubl_u8(farb, nearb));
+      int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2));
+      int16x8_t curr  = vaddq_s16(nears, diff); // current row
+
+      // horizontal filter works the same based on shifted vers of current
+      // row. "prev" is current row shifted right by 1 pixel; we need to
+      // insert the previous pixel value (from t1).
+      // "next" is current row shifted left by 1 pixel, with first pixel
+      // of next block of 8 pixels added in.
+      int16x8_t prv0 = vextq_s16(curr, curr, 7);
+      int16x8_t nxt0 = vextq_s16(curr, curr, 1);
+      int16x8_t prev = vsetq_lane_s16(t1, prv0, 0);
+      int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7);
+
+      // horizontal filter, polyphase implementation since it's convenient:
+      // even pixels = 3*cur + prev = cur*4 + (prev - cur)
+      // odd  pixels = 3*cur + next = cur*4 + (next - cur)
+      // note the shared term.
+      int16x8_t curs = vshlq_n_s16(curr, 2);
+      int16x8_t prvd = vsubq_s16(prev, curr);
+      int16x8_t nxtd = vsubq_s16(next, curr);
+      int16x8_t even = vaddq_s16(curs, prvd);
+      int16x8_t odd  = vaddq_s16(curs, nxtd);
+
+      // undo scaling and round, then store with even/odd phases interleaved
+      uint8x8x2_t o;
+      o.val[0] = vqrshrun_n_s16(even, 4);
+      o.val[1] = vqrshrun_n_s16(odd,  4);
+      vst2_u8(out + i*2, o);
+#endif
+
+      // "previous" value for next iter
+      t1 = 3*in_near[i+7] + in_far[i+7];
+   }
+
+   t0 = t1;
+   t1 = 3*in_near[i] + in_far[i];
+   out[i*2] = stbi__div16(3*t1 + t0 + 8);
+
+   for (++i; i < w; ++i) {
+      t0 = t1;
+      t1 = 3*in_near[i]+in_far[i];
+      out[i*2-1] = stbi__div16(3*t0 + t1 + 8);
+      out[i*2  ] = stbi__div16(3*t1 + t0 + 8);
+   }
+   out[w*2-1] = stbi__div4(t1+2);
+
+   STBI_NOTUSED(hs);
+
+   return out;
+}
+#endif
+
+static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+   // resample with nearest-neighbor
+   int i,j;
+   STBI_NOTUSED(in_far);
+   for (i=0; i < w; ++i)
+      for (j=0; j < hs; ++j)
+         out[i*hs+j] = in_near[i];
+   return out;
+}
+
+#ifdef STBI_JPEG_OLD
+// this is the same YCbCr-to-RGB calculation that stb_image has used
+// historically before the algorithm changes in 1.49
+#define float2fixed(x)  ((int) ((x) * 65536 + 0.5))
+static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step)
+{
+   int i;
+   for (i=0; i < count; ++i) {
+      int y_fixed = (y[i] << 16) + 32768; // rounding
+      int r,g,b;
+      int cr = pcr[i] - 128;
+      int cb = pcb[i] - 128;
+      r = y_fixed + cr*float2fixed(1.40200f);
+      g = y_fixed - cr*float2fixed(0.71414f) - cb*float2fixed(0.34414f);
+      b = y_fixed                            + cb*float2fixed(1.77200f);
+      r >>= 16;
+      g >>= 16;
+      b >>= 16;
+      if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }
+      if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }
+      if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }
+      out[0] = (stbi_uc)r;
+      out[1] = (stbi_uc)g;
+      out[2] = (stbi_uc)b;
+      out[3] = 255;
+      out += step;
+   }
+}
+#else
+// this is a reduced-precision calculation of YCbCr-to-RGB introduced
+// to make sure the code produces the same results in both SIMD and scalar
+#define float2fixed(x)  (((int) ((x) * 4096.0f + 0.5f)) << 8)
+static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step)
+{
+   int i;
+   for (i=0; i < count; ++i) {
+      int y_fixed = (y[i] << 20) + (1<<19); // rounding
+      int r,g,b;
+      int cr = pcr[i] - 128;
+      int cb = pcb[i] - 128;
+      r = y_fixed +  cr* float2fixed(1.40200f);
+      g = y_fixed + (cr*-float2fixed(0.71414f)) + ((cb*-float2fixed(0.34414f)) & 0xffff0000);
+      b = y_fixed                               +   cb* float2fixed(1.77200f);
+      r >>= 20;
+      g >>= 20;
+      b >>= 20;
+      if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }
+      if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }
+      if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }
+      out[0] = (stbi_uc)r;
+      out[1] = (stbi_uc)g;
+      out[2] = (stbi_uc)b;
+      out[3] = 255;
+      out += step;
+   }
+}
+#endif
+
+#if defined(STBI_SSE2) || defined(STBI_NEON)
+static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step)
+{
+   int i = 0;
+
+#ifdef STBI_SSE2
+   // step == 3 is pretty ugly on the final interleave, and i'm not convinced
+   // it's useful in practice (you wouldn't use it for textures, for example).
+   // so just accelerate step == 4 case.
+   if (step == 4) {
+      // this is a fairly straightforward implementation and not super-optimized.
+      __m128i signflip  = _mm_set1_epi8(-0x80);
+      __m128i cr_const0 = _mm_set1_epi16(   (short) ( 1.40200f*4096.0f+0.5f));
+      __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f));
+      __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f));
+      __m128i cb_const1 = _mm_set1_epi16(   (short) ( 1.77200f*4096.0f+0.5f));
+      __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128);
+      __m128i xw = _mm_set1_epi16(255); // alpha channel
+
+      for (; i+7 < count; i += 8) {
+         // load
+         __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i));
+         __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i));
+         __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i));
+         __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128
+         __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128
+
+         // unpack to short (and left-shift cr, cb by 8)
+         __m128i yw  = _mm_unpacklo_epi8(y_bias, y_bytes);
+         __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased);
+         __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased);
+
+         // color transform
+         __m128i yws = _mm_srli_epi16(yw, 4);
+         __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw);
+         __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw);
+         __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1);
+         __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1);
+         __m128i rws = _mm_add_epi16(cr0, yws);
+         __m128i gwt = _mm_add_epi16(cb0, yws);
+         __m128i bws = _mm_add_epi16(yws, cb1);
+         __m128i gws = _mm_add_epi16(gwt, cr1);
+
+         // descale
+         __m128i rw = _mm_srai_epi16(rws, 4);
+         __m128i bw = _mm_srai_epi16(bws, 4);
+         __m128i gw = _mm_srai_epi16(gws, 4);
+
+         // back to byte, set up for transpose
+         __m128i brb = _mm_packus_epi16(rw, bw);
+         __m128i gxb = _mm_packus_epi16(gw, xw);
+
+         // transpose to interleave channels
+         __m128i t0 = _mm_unpacklo_epi8(brb, gxb);
+         __m128i t1 = _mm_unpackhi_epi8(brb, gxb);
+         __m128i o0 = _mm_unpacklo_epi16(t0, t1);
+         __m128i o1 = _mm_unpackhi_epi16(t0, t1);
+
+         // store
+         _mm_storeu_si128((__m128i *) (out + 0), o0);
+         _mm_storeu_si128((__m128i *) (out + 16), o1);
+         out += 32;
+      }
+   }
+#endif
+
+#ifdef STBI_NEON
+   // in this version, step=3 support would be easy to add. but is there demand?
+   if (step == 4) {
+      // this is a fairly straightforward implementation and not super-optimized.
+      uint8x8_t signflip = vdup_n_u8(0x80);
+      int16x8_t cr_const0 = vdupq_n_s16(   (short) ( 1.40200f*4096.0f+0.5f));
+      int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f));
+      int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f));
+      int16x8_t cb_const1 = vdupq_n_s16(   (short) ( 1.77200f*4096.0f+0.5f));
+
+      for (; i+7 < count; i += 8) {
+         // load
+         uint8x8_t y_bytes  = vld1_u8(y + i);
+         uint8x8_t cr_bytes = vld1_u8(pcr + i);
+         uint8x8_t cb_bytes = vld1_u8(pcb + i);
+         int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip));
+         int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip));
+
+         // expand to s16
+         int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4));
+         int16x8_t crw = vshll_n_s8(cr_biased, 7);
+         int16x8_t cbw = vshll_n_s8(cb_biased, 7);
+
+         // color transform
+         int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0);
+         int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0);
+         int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1);
+         int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1);
+         int16x8_t rws = vaddq_s16(yws, cr0);
+         int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1);
+         int16x8_t bws = vaddq_s16(yws, cb1);
+
+         // undo scaling, round, convert to byte
+         uint8x8x4_t o;
+         o.val[0] = vqrshrun_n_s16(rws, 4);
+         o.val[1] = vqrshrun_n_s16(gws, 4);
+         o.val[2] = vqrshrun_n_s16(bws, 4);
+         o.val[3] = vdup_n_u8(255);
+
+         // store, interleaving r/g/b/a
+         vst4_u8(out, o);
+         out += 8*4;
+      }
+   }
+#endif
+
+   for (; i < count; ++i) {
+      int y_fixed = (y[i] << 20) + (1<<19); // rounding
+      int r,g,b;
+      int cr = pcr[i] - 128;
+      int cb = pcb[i] - 128;
+      r = y_fixed + cr* float2fixed(1.40200f);
+      g = y_fixed + cr*-float2fixed(0.71414f) + ((cb*-float2fixed(0.34414f)) & 0xffff0000);
+      b = y_fixed                             +   cb* float2fixed(1.77200f);
+      r >>= 20;
+      g >>= 20;
+      b >>= 20;
+      if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }
+      if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }
+      if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }
+      out[0] = (stbi_uc)r;
+      out[1] = (stbi_uc)g;
+      out[2] = (stbi_uc)b;
+      out[3] = 255;
+      out += step;
+   }
+}
+#endif
+
+// set up the kernels
+static void stbi__setup_jpeg(stbi__jpeg *j)
+{
+   j->idct_block_kernel = stbi__idct_block;
+   j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row;
+   j->resample_row_hv_2_kernel = stbi__resample_row_hv_2;
+
+#ifdef STBI_SSE2
+   if (stbi__sse2_available()) {
+      j->idct_block_kernel = stbi__idct_simd;
+      #ifndef STBI_JPEG_OLD
+      j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;
+      #endif
+      j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;
+   }
+#endif
+
+#ifdef STBI_NEON
+   j->idct_block_kernel = stbi__idct_simd;
+   #ifndef STBI_JPEG_OLD
+   j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;
+   #endif
+   j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;
+#endif
+}
+
+// clean up the temporary component buffers
+static void stbi__cleanup_jpeg(stbi__jpeg *j)
+{
+   int i;
+   for (i=0; i < j->s->img_n; ++i) {
+      if (j->img_comp[i].raw_data) {
+         STBI_FREE(j->img_comp[i].raw_data);
+         j->img_comp[i].raw_data = NULL;
+         j->img_comp[i].data = NULL;
+      }
+      if (j->img_comp[i].raw_coeff) {
+         STBI_FREE(j->img_comp[i].raw_coeff);
+         j->img_comp[i].raw_coeff = 0;
+         j->img_comp[i].coeff = 0;
+      }
+      if (j->img_comp[i].linebuf) {
+         STBI_FREE(j->img_comp[i].linebuf);
+         j->img_comp[i].linebuf = NULL;
+      }
+   }
+}
+
+typedef struct
+{
+   resample_row_func resample;
+   stbi_uc *line0,*line1;
+   int hs,vs;   // expansion factor in each axis
+   int w_lores; // horizontal pixels pre-expansion
+   int ystep;   // how far through vertical expansion we are
+   int ypos;    // which pre-expansion row we're on
+} stbi__resample;
+
+static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp)
+{
+   int n, decode_n;
+   z->s->img_n = 0; // make stbi__cleanup_jpeg safe
+
+   // validate req_comp
+   if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error");
+
+   // load a jpeg image from whichever source, but leave in YCbCr format
+   if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; }
+
+   // determine actual number of components to generate
+   n = req_comp ? req_comp : z->s->img_n;
+
+   if (z->s->img_n == 3 && n < 3)
+      decode_n = 1;
+   else
+      decode_n = z->s->img_n;
+
+   // resample and color-convert
+   {
+      int k;
+      unsigned int i,j;
+      stbi_uc *output;
+      stbi_uc *coutput[4];
+
+      stbi__resample res_comp[4];
+
+      for (k=0; k < decode_n; ++k) {
+         stbi__resample *r = &res_comp[k];
+
+         // allocate line buffer big enough for upsampling off the edges
+         // with upsample factor of 4
+         z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3);
+         if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); }
+
+         r->hs      = z->img_h_max / z->img_comp[k].h;
+         r->vs      = z->img_v_max / z->img_comp[k].v;
+         r->ystep   = r->vs >> 1;
+         r->w_lores = (z->s->img_x + r->hs-1) / r->hs;
+         r->ypos    = 0;
+         r->line0   = r->line1 = z->img_comp[k].data;
+
+         if      (r->hs == 1 && r->vs == 1) r->resample = resample_row_1;
+         else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2;
+         else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2;
+         else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel;
+         else                               r->resample = stbi__resample_row_generic;
+      }
+
+      // can't error after this so, this is safe
+      output = (stbi_uc *) stbi__malloc(n * z->s->img_x * z->s->img_y + 1);
+      if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); }
+
+      // now go ahead and resample
+      for (j=0; j < z->s->img_y; ++j) {
+         stbi_uc *out = output + n * z->s->img_x * j;
+         for (k=0; k < decode_n; ++k) {
+            stbi__resample *r = &res_comp[k];
+            int y_bot = r->ystep >= (r->vs >> 1);
+            coutput[k] = r->resample(z->img_comp[k].linebuf,
+                                     y_bot ? r->line1 : r->line0,
+                                     y_bot ? r->line0 : r->line1,
+                                     r->w_lores, r->hs);
+            if (++r->ystep >= r->vs) {
+               r->ystep = 0;
+               r->line0 = r->line1;
+               if (++r->ypos < z->img_comp[k].y)
+                  r->line1 += z->img_comp[k].w2;
+            }
+         }
+         if (n >= 3) {
+            stbi_uc *y = coutput[0];
+            if (z->s->img_n == 3) {
+               z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);
+            } else
+               for (i=0; i < z->s->img_x; ++i) {
+                  out[0] = out[1] = out[2] = y[i];
+                  out[3] = 255; // not used if n==3
+                  out += n;
+               }
+         } else {
+            stbi_uc *y = coutput[0];
+            if (n == 1)
+               for (i=0; i < z->s->img_x; ++i) out[i] = y[i];
+            else
+               for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255;
+         }
+      }
+      stbi__cleanup_jpeg(z);
+      *out_x = z->s->img_x;
+      *out_y = z->s->img_y;
+      if (comp) *comp  = z->s->img_n; // report original components, not output
+      return output;
+   }
+}
+
+static unsigned char *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__jpeg j;
+   j.s = s;
+   stbi__setup_jpeg(&j);
+   return load_jpeg_image(&j, x,y,comp,req_comp);
+}
+
+static int stbi__jpeg_test(stbi__context *s)
+{
+   int r;
+   stbi__jpeg j;
+   j.s = s;
+   stbi__setup_jpeg(&j);
+   r = stbi__decode_jpeg_header(&j, STBI__SCAN_type);
+   stbi__rewind(s);
+   return r;
+}
+
+static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp)
+{
+   if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) {
+      stbi__rewind( j->s );
+      return 0;
+   }
+   if (x) *x = j->s->img_x;
+   if (y) *y = j->s->img_y;
+   if (comp) *comp = j->s->img_n;
+   return 1;
+}
+
+static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   stbi__jpeg j;
+   j.s = s;
+   return stbi__jpeg_info_raw(&j, x, y, comp);
+}
+#endif
+
+// public domain zlib decode    v0.2  Sean Barrett 2006-11-18
+//    simple implementation
+//      - all input must be provided in an upfront buffer
+//      - all output is written to a single output buffer (can malloc/realloc)
+//    performance
+//      - fast huffman
+
+#ifndef STBI_NO_ZLIB
+
+// fast-way is faster to check than jpeg huffman, but slow way is slower
+#define STBI__ZFAST_BITS  9 // accelerate all cases in default tables
+#define STBI__ZFAST_MASK  ((1 << STBI__ZFAST_BITS) - 1)
+
+// zlib-style huffman encoding
+// (jpegs packs from left, zlib from right, so can't share code)
+typedef struct
+{
+   stbi__uint16 fast[1 << STBI__ZFAST_BITS];
+   stbi__uint16 firstcode[16];
+   int maxcode[17];
+   stbi__uint16 firstsymbol[16];
+   stbi_uc  size[288];
+   stbi__uint16 value[288];
+} stbi__zhuffman;
+
+stbi_inline static int stbi__bitreverse16(int n)
+{
+  n = ((n & 0xAAAA) >>  1) | ((n & 0x5555) << 1);
+  n = ((n & 0xCCCC) >>  2) | ((n & 0x3333) << 2);
+  n = ((n & 0xF0F0) >>  4) | ((n & 0x0F0F) << 4);
+  n = ((n & 0xFF00) >>  8) | ((n & 0x00FF) << 8);
+  return n;
+}
+
+stbi_inline static int stbi__bit_reverse(int v, int bits)
+{
+   STBI_ASSERT(bits <= 16);
+   // to bit reverse n bits, reverse 16 and shift
+   // e.g. 11 bits, bit reverse and shift away 5
+   return stbi__bitreverse16(v) >> (16-bits);
+}
+
+static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num)
+{
+   int i,k=0;
+   int code, next_code[16], sizes[17];
+
+   // DEFLATE spec for generating codes
+   memset(sizes, 0, sizeof(sizes));
+   memset(z->fast, 0, sizeof(z->fast));
+   for (i=0; i < num; ++i)
+      ++sizes[sizelist[i]];
+   sizes[0] = 0;
+   for (i=1; i < 16; ++i)
+      STBI_ASSERT(sizes[i] <= (1 << i));
+   code = 0;
+   for (i=1; i < 16; ++i) {
+      next_code[i] = code;
+      z->firstcode[i] = (stbi__uint16) code;
+      z->firstsymbol[i] = (stbi__uint16) k;
+      code = (code + sizes[i]);
+      if (sizes[i])
+         if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt JPEG");
+      z->maxcode[i] = code << (16-i); // preshift for inner loop
+      code <<= 1;
+      k += sizes[i];
+   }
+   z->maxcode[16] = 0x10000; // sentinel
+   for (i=0; i < num; ++i) {
+      int s = sizelist[i];
+      if (s) {
+         int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s];
+         stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i);
+         z->size [c] = (stbi_uc     ) s;
+         z->value[c] = (stbi__uint16) i;
+         if (s <= STBI__ZFAST_BITS) {
+            int k = stbi__bit_reverse(next_code[s],s);
+            while (k < (1 << STBI__ZFAST_BITS)) {
+               z->fast[k] = fastv;
+               k += (1 << s);
+            }
+         }
+         ++next_code[s];
+      }
+   }
+   return 1;
+}
+
+// zlib-from-memory implementation for PNG reading
+//    because PNG allows splitting the zlib stream arbitrarily,
+//    and it's annoying structurally to have PNG call ZLIB call PNG,
+//    we require PNG read all the IDATs and combine them into a single
+//    memory buffer
+
+typedef struct
+{
+   stbi_uc *zbuffer, *zbuffer_end;
+   int num_bits;
+   stbi__uint32 code_buffer;
+
+   char *zout;
+   char *zout_start;
+   char *zout_end;
+   int   z_expandable;
+
+   stbi__zhuffman z_length, z_distance;
+} stbi__zbuf;
+
+stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z)
+{
+   if (z->zbuffer >= z->zbuffer_end) return 0;
+   return *z->zbuffer++;
+}
+
+static void stbi__fill_bits(stbi__zbuf *z)
+{
+   do {
+      STBI_ASSERT(z->code_buffer < (1U << z->num_bits));
+      z->code_buffer |= stbi__zget8(z) << z->num_bits;
+      z->num_bits += 8;
+   } while (z->num_bits <= 24);
+}
+
+stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n)
+{
+   unsigned int k;
+   if (z->num_bits < n) stbi__fill_bits(z);
+   k = z->code_buffer & ((1 << n) - 1);
+   z->code_buffer >>= n;
+   z->num_bits -= n;
+   return k;
+}
+
+static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z)
+{
+   int b,s,k;
+   // not resolved by fast table, so compute it the slow way
+   // use jpeg approach, which requires MSbits at top
+   k = stbi__bit_reverse(a->code_buffer, 16);
+   for (s=STBI__ZFAST_BITS+1; ; ++s)
+      if (k < z->maxcode[s])
+         break;
+   if (s == 16) return -1; // invalid code!
+   // code size is s, so:
+   b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s];
+   STBI_ASSERT(z->size[b] == s);
+   a->code_buffer >>= s;
+   a->num_bits -= s;
+   return z->value[b];
+}
+
+stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)
+{
+   int b,s;
+   if (a->num_bits < 16) stbi__fill_bits(a);
+   b = z->fast[a->code_buffer & STBI__ZFAST_MASK];
+   if (b) {
+      s = b >> 9;
+      a->code_buffer >>= s;
+      a->num_bits -= s;
+      return b & 511;
+   }
+   return stbi__zhuffman_decode_slowpath(a, z);
+}
+
+static int stbi__zexpand(stbi__zbuf *z, char *zout, int n)  // need to make room for n bytes
+{
+   char *q;
+   int cur, limit;
+   z->zout = zout;
+   if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG");
+   cur   = (int) (z->zout     - z->zout_start);
+   limit = (int) (z->zout_end - z->zout_start);
+   while (cur + n > limit)
+      limit *= 2;
+   q = (char *) STBI_REALLOC(z->zout_start, limit);
+   if (q == NULL) return stbi__err("outofmem", "Out of memory");
+   z->zout_start = q;
+   z->zout       = q + cur;
+   z->zout_end   = q + limit;
+   return 1;
+}
+
+static int stbi__zlength_base[31] = {
+   3,4,5,6,7,8,9,10,11,13,
+   15,17,19,23,27,31,35,43,51,59,
+   67,83,99,115,131,163,195,227,258,0,0 };
+
+static int stbi__zlength_extra[31]=
+{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
+
+static int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,
+257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
+
+static int stbi__zdist_extra[32] =
+{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+static int stbi__parse_huffman_block(stbi__zbuf *a)
+{
+   char *zout = a->zout;
+   for(;;) {
+      int z = stbi__zhuffman_decode(a, &a->z_length);
+      if (z < 256) {
+         if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes
+         if (zout >= a->zout_end) {
+            if (!stbi__zexpand(a, zout, 1)) return 0;
+            zout = a->zout;
+         }
+         *zout++ = (char) z;
+      } else {
+         stbi_uc *p;
+         int len,dist;
+         if (z == 256) {
+            a->zout = zout;
+            return 1;
+         }
+         z -= 257;
+         len = stbi__zlength_base[z];
+         if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]);
+         z = stbi__zhuffman_decode(a, &a->z_distance);
+         if (z < 0) return stbi__err("bad huffman code","Corrupt PNG");
+         dist = stbi__zdist_base[z];
+         if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]);
+         if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG");
+         if (zout + len > a->zout_end) {
+            if (!stbi__zexpand(a, zout, len)) return 0;
+            zout = a->zout;
+         }
+         p = (stbi_uc *) (zout - dist);
+         if (dist == 1) { // run of one byte; common in images.
+            stbi_uc v = *p;
+            do *zout++ = v; while (--len);
+         } else {
+            do *zout++ = *p++; while (--len);
+         }
+      }
+   }
+}
+
+static int stbi__compute_huffman_codes(stbi__zbuf *a)
+{
+   static stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
+   stbi__zhuffman z_codelength;
+   stbi_uc lencodes[286+32+137];//padding for maximum single op
+   stbi_uc codelength_sizes[19];
+   int i,n;
+
+   int hlit  = stbi__zreceive(a,5) + 257;
+   int hdist = stbi__zreceive(a,5) + 1;
+   int hclen = stbi__zreceive(a,4) + 4;
+
+   memset(codelength_sizes, 0, sizeof(codelength_sizes));
+   for (i=0; i < hclen; ++i) {
+      int s = stbi__zreceive(a,3);
+      codelength_sizes[length_dezigzag[i]] = (stbi_uc) s;
+   }
+   if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0;
+
+   n = 0;
+   while (n < hlit + hdist) {
+      int c = stbi__zhuffman_decode(a, &z_codelength);
+      STBI_ASSERT(c >= 0 && c < 19);
+      if (c < 16)
+         lencodes[n++] = (stbi_uc) c;
+      else if (c == 16) {
+         c = stbi__zreceive(a,2)+3;
+         memset(lencodes+n, lencodes[n-1], c);
+         n += c;
+      } else if (c == 17) {
+         c = stbi__zreceive(a,3)+3;
+         memset(lencodes+n, 0, c);
+         n += c;
+      } else {
+         STBI_ASSERT(c == 18);
+         c = stbi__zreceive(a,7)+11;
+         memset(lencodes+n, 0, c);
+         n += c;
+      }
+   }
+   if (n != hlit+hdist) return stbi__err("bad codelengths","Corrupt PNG");
+   if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0;
+   if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0;
+   return 1;
+}
+
+static int stbi__parse_uncomperssed_block(stbi__zbuf *a)
+{
+   stbi_uc header[4];
+   int len,nlen,k;
+   if (a->num_bits & 7)
+      stbi__zreceive(a, a->num_bits & 7); // discard
+   // drain the bit-packed data into header
+   k = 0;
+   while (a->num_bits > 0) {
+      header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check
+      a->code_buffer >>= 8;
+      a->num_bits -= 8;
+   }
+   STBI_ASSERT(a->num_bits == 0);
+   // now fill header the normal way
+   while (k < 4)
+      header[k++] = stbi__zget8(a);
+   len  = header[1] * 256 + header[0];
+   nlen = header[3] * 256 + header[2];
+   if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG");
+   if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG");
+   if (a->zout + len > a->zout_end)
+      if (!stbi__zexpand(a, a->zout, len)) return 0;
+   memcpy(a->zout, a->zbuffer, len);
+   a->zbuffer += len;
+   a->zout += len;
+   return 1;
+}
+
+static int stbi__parse_zlib_header(stbi__zbuf *a)
+{
+   int cmf   = stbi__zget8(a);
+   int cm    = cmf & 15;
+   /* int cinfo = cmf >> 4; */
+   int flg   = stbi__zget8(a);
+   if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec
+   if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png
+   if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png
+   // window = 1 << (8 + cinfo)... but who cares, we fully buffer output
+   return 1;
+}
+
+// @TODO: should statically initialize these for optimal thread safety
+static stbi_uc stbi__zdefault_length[288], stbi__zdefault_distance[32];
+static void stbi__init_zdefaults(void)
+{
+   int i;   // use <= to match clearly with spec
+   for (i=0; i <= 143; ++i)     stbi__zdefault_length[i]   = 8;
+   for (   ; i <= 255; ++i)     stbi__zdefault_length[i]   = 9;
+   for (   ; i <= 279; ++i)     stbi__zdefault_length[i]   = 7;
+   for (   ; i <= 287; ++i)     stbi__zdefault_length[i]   = 8;
+
+   for (i=0; i <=  31; ++i)     stbi__zdefault_distance[i] = 5;
+}
+
+static int stbi__parse_zlib(stbi__zbuf *a, int parse_header)
+{
+   int final, type;
+   if (parse_header)
+      if (!stbi__parse_zlib_header(a)) return 0;
+   a->num_bits = 0;
+   a->code_buffer = 0;
+   do {
+      final = stbi__zreceive(a,1);
+      type = stbi__zreceive(a,2);
+      if (type == 0) {
+         if (!stbi__parse_uncomperssed_block(a)) return 0;
+      } else if (type == 3) {
+         return 0;
+      } else {
+         if (type == 1) {
+            // use fixed code lengths
+            if (!stbi__zdefault_distance[31]) stbi__init_zdefaults();
+            if (!stbi__zbuild_huffman(&a->z_length  , stbi__zdefault_length  , 288)) return 0;
+            if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance,  32)) return 0;
+         } else {
+            if (!stbi__compute_huffman_codes(a)) return 0;
+         }
+         if (!stbi__parse_huffman_block(a)) return 0;
+      }
+   } while (!final);
+   return 1;
+}
+
+static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header)
+{
+   a->zout_start = obuf;
+   a->zout       = obuf;
+   a->zout_end   = obuf + olen;
+   a->z_expandable = exp;
+
+   return stbi__parse_zlib(a, parse_header);
+}
+
+STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen)
+{
+   stbi__zbuf a;
+   char *p = (char *) stbi__malloc(initial_size);
+   if (p == NULL) return NULL;
+   a.zbuffer = (stbi_uc *) buffer;
+   a.zbuffer_end = (stbi_uc *) buffer + len;
+   if (stbi__do_zlib(&a, p, initial_size, 1, 1)) {
+      if (outlen) *outlen = (int) (a.zout - a.zout_start);
+      return a.zout_start;
+   } else {
+      STBI_FREE(a.zout_start);
+      return NULL;
+   }
+}
+
+STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen)
+{
+   return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen);
+}
+
+STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header)
+{
+   stbi__zbuf a;
+   char *p = (char *) stbi__malloc(initial_size);
+   if (p == NULL) return NULL;
+   a.zbuffer = (stbi_uc *) buffer;
+   a.zbuffer_end = (stbi_uc *) buffer + len;
+   if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) {
+      if (outlen) *outlen = (int) (a.zout - a.zout_start);
+      return a.zout_start;
+   } else {
+      STBI_FREE(a.zout_start);
+      return NULL;
+   }
+}
+
+STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen)
+{
+   stbi__zbuf a;
+   a.zbuffer = (stbi_uc *) ibuffer;
+   a.zbuffer_end = (stbi_uc *) ibuffer + ilen;
+   if (stbi__do_zlib(&a, obuffer, olen, 0, 1))
+      return (int) (a.zout - a.zout_start);
+   else
+      return -1;
+}
+
+STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen)
+{
+   stbi__zbuf a;
+   char *p = (char *) stbi__malloc(16384);
+   if (p == NULL) return NULL;
+   a.zbuffer = (stbi_uc *) buffer;
+   a.zbuffer_end = (stbi_uc *) buffer+len;
+   if (stbi__do_zlib(&a, p, 16384, 1, 0)) {
+      if (outlen) *outlen = (int) (a.zout - a.zout_start);
+      return a.zout_start;
+   } else {
+      STBI_FREE(a.zout_start);
+      return NULL;
+   }
+}
+
+STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen)
+{
+   stbi__zbuf a;
+   a.zbuffer = (stbi_uc *) ibuffer;
+   a.zbuffer_end = (stbi_uc *) ibuffer + ilen;
+   if (stbi__do_zlib(&a, obuffer, olen, 0, 0))
+      return (int) (a.zout - a.zout_start);
+   else
+      return -1;
+}
+#endif
+
+// public domain "baseline" PNG decoder   v0.10  Sean Barrett 2006-11-18
+//    simple implementation
+//      - only 8-bit samples
+//      - no CRC checking
+//      - allocates lots of intermediate memory
+//        - avoids problem of streaming data between subsystems
+//        - avoids explicit window management
+//    performance
+//      - uses stb_zlib, a PD zlib implementation with fast huffman decoding
+
+#ifndef STBI_NO_PNG
+typedef struct
+{
+   stbi__uint32 length;
+   stbi__uint32 type;
+} stbi__pngchunk;
+
+static stbi__pngchunk stbi__get_chunk_header(stbi__context *s)
+{
+   stbi__pngchunk c;
+   c.length = stbi__get32be(s);
+   c.type   = stbi__get32be(s);
+   return c;
+}
+
+static int stbi__check_png_header(stbi__context *s)
+{
+   static stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 };
+   int i;
+   for (i=0; i < 8; ++i)
+      if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG");
+   return 1;
+}
+
+typedef struct
+{
+   stbi__context *s;
+   stbi_uc *idata, *expanded, *out;
+} stbi__png;
+
+
+enum {
+   STBI__F_none=0,
+   STBI__F_sub=1,
+   STBI__F_up=2,
+   STBI__F_avg=3,
+   STBI__F_paeth=4,
+   // synthetic filters used for first scanline to avoid needing a dummy row of 0s
+   STBI__F_avg_first,
+   STBI__F_paeth_first
+};
+
+static stbi_uc first_row_filter[5] =
+{
+   STBI__F_none,
+   STBI__F_sub,
+   STBI__F_none,
+   STBI__F_avg_first,
+   STBI__F_paeth_first
+};
+
+static int stbi__paeth(int a, int b, int c)
+{
+   int p = a + b - c;
+   int pa = abs(p-a);
+   int pb = abs(p-b);
+   int pc = abs(p-c);
+   if (pa <= pb && pa <= pc) return a;
+   if (pb <= pc) return b;
+   return c;
+}
+
+static stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
+
+// create the png data from post-deflated data
+static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)
+{
+   stbi__context *s = a->s;
+   stbi__uint32 i,j,stride = x*out_n;
+   stbi__uint32 img_len, img_width_bytes;
+   int k;
+   int img_n = s->img_n; // copy it into a local for later
+
+   STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1);
+   a->out = (stbi_uc *) stbi__malloc(x * y * out_n); // extra bytes to write off the end into
+   if (!a->out) return stbi__err("outofmem", "Out of memory");
+
+   img_width_bytes = (((img_n * x * depth) + 7) >> 3);
+   img_len = (img_width_bytes + 1) * y;
+   if (s->img_x == x && s->img_y == y) {
+      if (raw_len != img_len) return stbi__err("not enough pixels","Corrupt PNG");
+   } else { // interlaced:
+      if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG");
+   }
+
+   for (j=0; j < y; ++j) {
+      stbi_uc *cur = a->out + stride*j;
+      stbi_uc *prior = cur - stride;
+      int filter = *raw++;
+      int filter_bytes = img_n;
+      int width = x;
+      if (filter > 4)
+         return stbi__err("invalid filter","Corrupt PNG");
+
+      if (depth < 8) {
+         STBI_ASSERT(img_width_bytes <= x);
+         cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place
+         filter_bytes = 1;
+         width = img_width_bytes;
+      }
+
+      // if first row, use special filter that doesn't sample previous row
+      if (j == 0) filter = first_row_filter[filter];
+
+      // handle first byte explicitly
+      for (k=0; k < filter_bytes; ++k) {
+         switch (filter) {
+            case STBI__F_none       : cur[k] = raw[k]; break;
+            case STBI__F_sub        : cur[k] = raw[k]; break;
+            case STBI__F_up         : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;
+            case STBI__F_avg        : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break;
+            case STBI__F_paeth      : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break;
+            case STBI__F_avg_first  : cur[k] = raw[k]; break;
+            case STBI__F_paeth_first: cur[k] = raw[k]; break;
+         }
+      }
+
+      if (depth == 8) {
+         if (img_n != out_n)
+            cur[img_n] = 255; // first pixel
+         raw += img_n;
+         cur += out_n;
+         prior += out_n;
+      } else {
+         raw += 1;
+         cur += 1;
+         prior += 1;
+      }
+
+      // this is a little gross, so that we don't switch per-pixel or per-component
+      if (depth < 8 || img_n == out_n) {
+         int nk = (width - 1)*img_n;
+         #define CASE(f) \
+             case f:     \
+                for (k=0; k < nk; ++k)
+         switch (filter) {
+            // "none" filter turns into a memcpy here; make that explicit.
+            case STBI__F_none:         memcpy(cur, raw, nk); break;
+            CASE(STBI__F_sub)          cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); break;
+            CASE(STBI__F_up)           cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;
+            CASE(STBI__F_avg)          cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); break;
+            CASE(STBI__F_paeth)        cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); break;
+            CASE(STBI__F_avg_first)    cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); break;
+            CASE(STBI__F_paeth_first)  cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); break;
+         }
+         #undef CASE
+         raw += nk;
+      } else {
+         STBI_ASSERT(img_n+1 == out_n);
+         #define CASE(f) \
+             case f:     \
+                for (i=x-1; i >= 1; --i, cur[img_n]=255,raw+=img_n,cur+=out_n,prior+=out_n) \
+                   for (k=0; k < img_n; ++k)
+         switch (filter) {
+            CASE(STBI__F_none)         cur[k] = raw[k]; break;
+            CASE(STBI__F_sub)          cur[k] = STBI__BYTECAST(raw[k] + cur[k-out_n]); break;
+            CASE(STBI__F_up)           cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;
+            CASE(STBI__F_avg)          cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-out_n])>>1)); break;
+            CASE(STBI__F_paeth)        cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-out_n],prior[k],prior[k-out_n])); break;
+            CASE(STBI__F_avg_first)    cur[k] = STBI__BYTECAST(raw[k] + (cur[k-out_n] >> 1)); break;
+            CASE(STBI__F_paeth_first)  cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-out_n],0,0)); break;
+         }
+         #undef CASE
+      }
+   }
+
+   // we make a separate pass to expand bits to pixels; for performance,
+   // this could run two scanlines behind the above code, so it won't
+   // intefere with filtering but will still be in the cache.
+   if (depth < 8) {
+      for (j=0; j < y; ++j) {
+         stbi_uc *cur = a->out + stride*j;
+         stbi_uc *in  = a->out + stride*j + x*out_n - img_width_bytes;
+         // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit
+         // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop
+         stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range
+
+         // note that the final byte might overshoot and write more data than desired.
+         // we can allocate enough data that this never writes out of memory, but it
+         // could also overwrite the next scanline. can it overwrite non-empty data
+         // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel.
+         // so we need to explicitly clamp the final ones
+
+         if (depth == 4) {
+            for (k=x*img_n; k >= 2; k-=2, ++in) {
+               *cur++ = scale * ((*in >> 4)       );
+               *cur++ = scale * ((*in     ) & 0x0f);
+            }
+            if (k > 0) *cur++ = scale * ((*in >> 4)       );
+         } else if (depth == 2) {
+            for (k=x*img_n; k >= 4; k-=4, ++in) {
+               *cur++ = scale * ((*in >> 6)       );
+               *cur++ = scale * ((*in >> 4) & 0x03);
+               *cur++ = scale * ((*in >> 2) & 0x03);
+               *cur++ = scale * ((*in     ) & 0x03);
+            }
+            if (k > 0) *cur++ = scale * ((*in >> 6)       );
+            if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03);
+            if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03);
+         } else if (depth == 1) {
+            for (k=x*img_n; k >= 8; k-=8, ++in) {
+               *cur++ = scale * ((*in >> 7)       );
+               *cur++ = scale * ((*in >> 6) & 0x01);
+               *cur++ = scale * ((*in >> 5) & 0x01);
+               *cur++ = scale * ((*in >> 4) & 0x01);
+               *cur++ = scale * ((*in >> 3) & 0x01);
+               *cur++ = scale * ((*in >> 2) & 0x01);
+               *cur++ = scale * ((*in >> 1) & 0x01);
+               *cur++ = scale * ((*in     ) & 0x01);
+            }
+            if (k > 0) *cur++ = scale * ((*in >> 7)       );
+            if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01);
+            if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01);
+            if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01);
+            if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01);
+            if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01);
+            if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01);
+         }
+         if (img_n != out_n) {
+            // insert alpha = 255
+            stbi_uc *cur = a->out + stride*j;
+            int i;
+            if (img_n == 1) {
+               for (i=x-1; i >= 0; --i) {
+                  cur[i*2+1] = 255;
+                  cur[i*2+0] = cur[i];
+               }
+            } else {
+               STBI_ASSERT(img_n == 3);
+               for (i=x-1; i >= 0; --i) {
+                  cur[i*4+3] = 255;
+                  cur[i*4+2] = cur[i*3+2];
+                  cur[i*4+1] = cur[i*3+1];
+                  cur[i*4+0] = cur[i*3+0];
+               }
+            }
+         }
+      }
+   }
+
+   return 1;
+}
+
+static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced)
+{
+   stbi_uc *final;
+   int p;
+   if (!interlaced)
+      return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color);
+
+   // de-interlacing
+   final = (stbi_uc *) stbi__malloc(a->s->img_x * a->s->img_y * out_n);
+   for (p=0; p < 7; ++p) {
+      int xorig[] = { 0,4,0,2,0,1,0 };
+      int yorig[] = { 0,0,4,0,2,0,1 };
+      int xspc[]  = { 8,8,4,4,2,2,1 };
+      int yspc[]  = { 8,8,8,4,4,2,2 };
+      int i,j,x,y;
+      // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1
+      x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p];
+      y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p];
+      if (x && y) {
+         stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y;
+         if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) {
+            STBI_FREE(final);
+            return 0;
+         }
+         for (j=0; j < y; ++j) {
+            for (i=0; i < x; ++i) {
+               int out_y = j*yspc[p]+yorig[p];
+               int out_x = i*xspc[p]+xorig[p];
+               memcpy(final + out_y*a->s->img_x*out_n + out_x*out_n,
+                      a->out + (j*x+i)*out_n, out_n);
+            }
+         }
+         STBI_FREE(a->out);
+         image_data += img_len;
+         image_data_len -= img_len;
+      }
+   }
+   a->out = final;
+
+   return 1;
+}
+
+static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n)
+{
+   stbi__context *s = z->s;
+   stbi__uint32 i, pixel_count = s->img_x * s->img_y;
+   stbi_uc *p = z->out;
+
+   // compute color-based transparency, assuming we've
+   // already got 255 as the alpha value in the output
+   STBI_ASSERT(out_n == 2 || out_n == 4);
+
+   if (out_n == 2) {
+      for (i=0; i < pixel_count; ++i) {
+         p[1] = (p[0] == tc[0] ? 0 : 255);
+         p += 2;
+      }
+   } else {
+      for (i=0; i < pixel_count; ++i) {
+         if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
+            p[3] = 0;
+         p += 4;
+      }
+   }
+   return 1;
+}
+
+static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n)
+{
+   stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y;
+   stbi_uc *p, *temp_out, *orig = a->out;
+
+   p = (stbi_uc *) stbi__malloc(pixel_count * pal_img_n);
+   if (p == NULL) return stbi__err("outofmem", "Out of memory");
+
+   // between here and free(out) below, exitting would leak
+   temp_out = p;
+
+   if (pal_img_n == 3) {
+      for (i=0; i < pixel_count; ++i) {
+         int n = orig[i]*4;
+         p[0] = palette[n  ];
+         p[1] = palette[n+1];
+         p[2] = palette[n+2];
+         p += 3;
+      }
+   } else {
+      for (i=0; i < pixel_count; ++i) {
+         int n = orig[i]*4;
+         p[0] = palette[n  ];
+         p[1] = palette[n+1];
+         p[2] = palette[n+2];
+         p[3] = palette[n+3];
+         p += 4;
+      }
+   }
+   STBI_FREE(a->out);
+   a->out = temp_out;
+
+   STBI_NOTUSED(len);
+
+   return 1;
+}
+
+static int stbi__unpremultiply_on_load = 0;
+static int stbi__de_iphone_flag = 0;
+
+STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply)
+{
+   stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply;
+}
+
+STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert)
+{
+   stbi__de_iphone_flag = flag_true_if_should_convert;
+}
+
+static void stbi__de_iphone(stbi__png *z)
+{
+   stbi__context *s = z->s;
+   stbi__uint32 i, pixel_count = s->img_x * s->img_y;
+   stbi_uc *p = z->out;
+
+   if (s->img_out_n == 3) {  // convert bgr to rgb
+      for (i=0; i < pixel_count; ++i) {
+         stbi_uc t = p[0];
+         p[0] = p[2];
+         p[2] = t;
+         p += 3;
+      }
+   } else {
+      STBI_ASSERT(s->img_out_n == 4);
+      if (stbi__unpremultiply_on_load) {
+         // convert bgr to rgb and unpremultiply
+         for (i=0; i < pixel_count; ++i) {
+            stbi_uc a = p[3];
+            stbi_uc t = p[0];
+            if (a) {
+               p[0] = p[2] * 255 / a;
+               p[1] = p[1] * 255 / a;
+               p[2] =  t   * 255 / a;
+            } else {
+               p[0] = p[2];
+               p[2] = t;
+            }
+            p += 4;
+         }
+      } else {
+         // convert bgr to rgb
+         for (i=0; i < pixel_count; ++i) {
+            stbi_uc t = p[0];
+            p[0] = p[2];
+            p[2] = t;
+            p += 4;
+         }
+      }
+   }
+}
+
+#define STBI__PNG_TYPE(a,b,c,d)  (((a) << 24) + ((b) << 16) + ((c) << 8) + (d))
+
+static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
+{
+   stbi_uc palette[1024], pal_img_n=0;
+   stbi_uc has_trans=0, tc[3];
+   stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0;
+   int first=1,k,interlace=0, color=0, depth=0, is_iphone=0;
+   stbi__context *s = z->s;
+
+   z->expanded = NULL;
+   z->idata = NULL;
+   z->out = NULL;
+
+   if (!stbi__check_png_header(s)) return 0;
+
+   if (scan == STBI__SCAN_type) return 1;
+
+   for (;;) {
+      stbi__pngchunk c = stbi__get_chunk_header(s);
+      switch (c.type) {
+         case STBI__PNG_TYPE('C','g','B','I'):
+            is_iphone = 1;
+            stbi__skip(s, c.length);
+            break;
+         case STBI__PNG_TYPE('I','H','D','R'): {
+            int comp,filter;
+            if (!first) return stbi__err("multiple IHDR","Corrupt PNG");
+            first = 0;
+            if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG");
+            s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)");
+            s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)");
+            depth = stbi__get8(s);  if (depth != 1 && depth != 2 && depth != 4 && depth != 8)  return stbi__err("1/2/4/8-bit only","PNG not supported: 1/2/4/8-bit only");
+            color = stbi__get8(s);  if (color > 6)         return stbi__err("bad ctype","Corrupt PNG");
+            if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG");
+            comp  = stbi__get8(s);  if (comp) return stbi__err("bad comp method","Corrupt PNG");
+            filter= stbi__get8(s);  if (filter) return stbi__err("bad filter method","Corrupt PNG");
+            interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG");
+            if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG");
+            if (!pal_img_n) {
+               s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0);
+               if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode");
+               if (scan == STBI__SCAN_header) return 1;
+            } else {
+               // if paletted, then pal_n is our final components, and
+               // img_n is # components to decompress/filter.
+               s->img_n = 1;
+               if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG");
+               // if SCAN_header, have to scan to see if we have a tRNS
+            }
+            break;
+         }
+
+         case STBI__PNG_TYPE('P','L','T','E'):  {
+            if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+            if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG");
+            pal_len = c.length / 3;
+            if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG");
+            for (i=0; i < pal_len; ++i) {
+               palette[i*4+0] = stbi__get8(s);
+               palette[i*4+1] = stbi__get8(s);
+               palette[i*4+2] = stbi__get8(s);
+               palette[i*4+3] = 255;
+            }
+            break;
+         }
+
+         case STBI__PNG_TYPE('t','R','N','S'): {
+            if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+            if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG");
+            if (pal_img_n) {
+               if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; }
+               if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG");
+               if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG");
+               pal_img_n = 4;
+               for (i=0; i < c.length; ++i)
+                  palette[i*4+3] = stbi__get8(s);
+            } else {
+               if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG");
+               if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG");
+               has_trans = 1;
+               for (k=0; k < s->img_n; ++k)
+                  tc[k] = (stbi_uc) (stbi__get16be(s) & 255) * stbi__depth_scale_table[depth]; // non 8-bit images will be larger
+            }
+            break;
+         }
+
+         case STBI__PNG_TYPE('I','D','A','T'): {
+            if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+            if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG");
+            if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; }
+            if (ioff + c.length > idata_limit) {
+               stbi_uc *p;
+               if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096;
+               while (ioff + c.length > idata_limit)
+                  idata_limit *= 2;
+               p = (stbi_uc *) STBI_REALLOC(z->idata, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory");
+               z->idata = p;
+            }
+            if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG");
+            ioff += c.length;
+            break;
+         }
+
+         case STBI__PNG_TYPE('I','E','N','D'): {
+            stbi__uint32 raw_len, bpl;
+            if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+            if (scan != STBI__SCAN_load) return 1;
+            if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG");
+            // initial guess for decoded data size to avoid unnecessary reallocs
+            bpl = (s->img_x * depth + 7) / 8; // bytes per line, per component
+            raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */;
+            z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone);
+            if (z->expanded == NULL) return 0; // zlib should set error
+            STBI_FREE(z->idata); z->idata = NULL;
+            if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans)
+               s->img_out_n = s->img_n+1;
+            else
+               s->img_out_n = s->img_n;
+            if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, depth, color, interlace)) return 0;
+            if (has_trans)
+               if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0;
+            if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2)
+               stbi__de_iphone(z);
+            if (pal_img_n) {
+               // pal_img_n == 3 or 4
+               s->img_n = pal_img_n; // record the actual colors we had
+               s->img_out_n = pal_img_n;
+               if (req_comp >= 3) s->img_out_n = req_comp;
+               if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n))
+                  return 0;
+            }
+            STBI_FREE(z->expanded); z->expanded = NULL;
+            return 1;
+         }
+
+         default:
+            // if critical, fail
+            if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+            if ((c.type & (1 << 29)) == 0) {
+               #ifndef STBI_NO_FAILURE_STRINGS
+               // not threadsafe
+               static char invalid_chunk[] = "XXXX PNG chunk not known";
+               invalid_chunk[0] = STBI__BYTECAST(c.type >> 24);
+               invalid_chunk[1] = STBI__BYTECAST(c.type >> 16);
+               invalid_chunk[2] = STBI__BYTECAST(c.type >>  8);
+               invalid_chunk[3] = STBI__BYTECAST(c.type >>  0);
+               #endif
+               return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type");
+            }
+            stbi__skip(s, c.length);
+            break;
+      }
+      // end of PNG chunk, read and skip CRC
+      stbi__get32be(s);
+   }
+}
+
+static unsigned char *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp)
+{
+   unsigned char *result=NULL;
+   if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error");
+   if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) {
+      result = p->out;
+      p->out = NULL;
+      if (req_comp && req_comp != p->s->img_out_n) {
+         result = stbi__convert_format(result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
+         p->s->img_out_n = req_comp;
+         if (result == NULL) return result;
+      }
+      *x = p->s->img_x;
+      *y = p->s->img_y;
+      if (n) *n = p->s->img_out_n;
+   }
+   STBI_FREE(p->out);      p->out      = NULL;
+   STBI_FREE(p->expanded); p->expanded = NULL;
+   STBI_FREE(p->idata);    p->idata    = NULL;
+
+   return result;
+}
+
+static unsigned char *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__png p;
+   p.s = s;
+   return stbi__do_png(&p, x,y,comp,req_comp);
+}
+
+static int stbi__png_test(stbi__context *s)
+{
+   int r;
+   r = stbi__check_png_header(s);
+   stbi__rewind(s);
+   return r;
+}
+
+static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp)
+{
+   if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) {
+      stbi__rewind( p->s );
+      return 0;
+   }
+   if (x) *x = p->s->img_x;
+   if (y) *y = p->s->img_y;
+   if (comp) *comp = p->s->img_n;
+   return 1;
+}
+
+static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   stbi__png p;
+   p.s = s;
+   return stbi__png_info_raw(&p, x, y, comp);
+}
+#endif
+
+// Microsoft/Windows BMP image
+
+#ifndef STBI_NO_BMP
+static int stbi__bmp_test_raw(stbi__context *s)
+{
+   int r;
+   int sz;
+   if (stbi__get8(s) != 'B') return 0;
+   if (stbi__get8(s) != 'M') return 0;
+   stbi__get32le(s); // discard filesize
+   stbi__get16le(s); // discard reserved
+   stbi__get16le(s); // discard reserved
+   stbi__get32le(s); // discard data offset
+   sz = stbi__get32le(s);
+   r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124);
+   return r;
+}
+
+static int stbi__bmp_test(stbi__context *s)
+{
+   int r = stbi__bmp_test_raw(s);
+   stbi__rewind(s);
+   return r;
+}
+
+
+// returns 0..31 for the highest set bit
+static int stbi__high_bit(unsigned int z)
+{
+   int n=0;
+   if (z == 0) return -1;
+   if (z >= 0x10000) n += 16, z >>= 16;
+   if (z >= 0x00100) n +=  8, z >>=  8;
+   if (z >= 0x00010) n +=  4, z >>=  4;
+   if (z >= 0x00004) n +=  2, z >>=  2;
+   if (z >= 0x00002) n +=  1, z >>=  1;
+   return n;
+}
+
+static int stbi__bitcount(unsigned int a)
+{
+   a = (a & 0x55555555) + ((a >>  1) & 0x55555555); // max 2
+   a = (a & 0x33333333) + ((a >>  2) & 0x33333333); // max 4
+   a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits
+   a = (a + (a >> 8)); // max 16 per 8 bits
+   a = (a + (a >> 16)); // max 32 per 8 bits
+   return a & 0xff;
+}
+
+static int stbi__shiftsigned(int v, int shift, int bits)
+{
+   int result;
+   int z=0;
+
+   if (shift < 0) v <<= -shift;
+   else v >>= shift;
+   result = v;
+
+   z = bits;
+   while (z < 8) {
+      result += v >> z;
+      z += bits;
+   }
+   return result;
+}
+
+static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   stbi_uc *out;
+   unsigned int mr=0,mg=0,mb=0,ma=0, fake_a=0;
+   stbi_uc pal[256][4];
+   int psize=0,i,j,compress=0,width;
+   int bpp, flip_vertically, pad, target, offset, hsz;
+   if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP");
+   stbi__get32le(s); // discard filesize
+   stbi__get16le(s); // discard reserved
+   stbi__get16le(s); // discard reserved
+   offset = stbi__get32le(s);
+   hsz = stbi__get32le(s);
+   if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown");
+   if (hsz == 12) {
+      s->img_x = stbi__get16le(s);
+      s->img_y = stbi__get16le(s);
+   } else {
+      s->img_x = stbi__get32le(s);
+      s->img_y = stbi__get32le(s);
+   }
+   if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP");
+   bpp = stbi__get16le(s);
+   if (bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit");
+   flip_vertically = ((int) s->img_y) > 0;
+   s->img_y = abs((int) s->img_y);
+   if (hsz == 12) {
+      if (bpp < 24)
+         psize = (offset - 14 - 24) / 3;
+   } else {
+      compress = stbi__get32le(s);
+      if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE");
+      stbi__get32le(s); // discard sizeof
+      stbi__get32le(s); // discard hres
+      stbi__get32le(s); // discard vres
+      stbi__get32le(s); // discard colorsused
+      stbi__get32le(s); // discard max important
+      if (hsz == 40 || hsz == 56) {
+         if (hsz == 56) {
+            stbi__get32le(s);
+            stbi__get32le(s);
+            stbi__get32le(s);
+            stbi__get32le(s);
+         }
+         if (bpp == 16 || bpp == 32) {
+            mr = mg = mb = 0;
+            if (compress == 0) {
+               if (bpp == 32) {
+                  mr = 0xffu << 16;
+                  mg = 0xffu <<  8;
+                  mb = 0xffu <<  0;
+                  ma = 0xffu << 24;
+                  fake_a = 1; // @TODO: check for cases like alpha value is all 0 and switch it to 255
+                  STBI_NOTUSED(fake_a);
+               } else {
+                  mr = 31u << 10;
+                  mg = 31u <<  5;
+                  mb = 31u <<  0;
+               }
+            } else if (compress == 3) {
+               mr = stbi__get32le(s);
+               mg = stbi__get32le(s);
+               mb = stbi__get32le(s);
+               // not documented, but generated by photoshop and handled by mspaint
+               if (mr == mg && mg == mb) {
+                  // ?!?!?
+                  return stbi__errpuc("bad BMP", "bad BMP");
+               }
+            } else
+               return stbi__errpuc("bad BMP", "bad BMP");
+         }
+      } else {
+         STBI_ASSERT(hsz == 108 || hsz == 124);
+         mr = stbi__get32le(s);
+         mg = stbi__get32le(s);
+         mb = stbi__get32le(s);
+         ma = stbi__get32le(s);
+         stbi__get32le(s); // discard color space
+         for (i=0; i < 12; ++i)
+            stbi__get32le(s); // discard color space parameters
+         if (hsz == 124) {
+            stbi__get32le(s); // discard rendering intent
+            stbi__get32le(s); // discard offset of profile data
+            stbi__get32le(s); // discard size of profile data
+            stbi__get32le(s); // discard reserved
+         }
+      }
+      if (bpp < 16)
+         psize = (offset - 14 - hsz) >> 2;
+   }
+   s->img_n = ma ? 4 : 3;
+   if (req_comp && req_comp >= 3) // we can directly decode 3 or 4
+      target = req_comp;
+   else
+      target = s->img_n; // if they want monochrome, we'll post-convert
+   out = (stbi_uc *) stbi__malloc(target * s->img_x * s->img_y);
+   if (!out) return stbi__errpuc("outofmem", "Out of memory");
+   if (bpp < 16) {
+      int z=0;
+      if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); }
+      for (i=0; i < psize; ++i) {
+         pal[i][2] = stbi__get8(s);
+         pal[i][1] = stbi__get8(s);
+         pal[i][0] = stbi__get8(s);
+         if (hsz != 12) stbi__get8(s);
+         pal[i][3] = 255;
+      }
+      stbi__skip(s, offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4));
+      if (bpp == 4) width = (s->img_x + 1) >> 1;
+      else if (bpp == 8) width = s->img_x;
+      else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); }
+      pad = (-width)&3;
+      for (j=0; j < (int) s->img_y; ++j) {
+         for (i=0; i < (int) s->img_x; i += 2) {
+            int v=stbi__get8(s),v2=0;
+            if (bpp == 4) {
+               v2 = v & 15;
+               v >>= 4;
+            }
+            out[z++] = pal[v][0];
+            out[z++] = pal[v][1];
+            out[z++] = pal[v][2];
+            if (target == 4) out[z++] = 255;
+            if (i+1 == (int) s->img_x) break;
+            v = (bpp == 8) ? stbi__get8(s) : v2;
+            out[z++] = pal[v][0];
+            out[z++] = pal[v][1];
+            out[z++] = pal[v][2];
+            if (target == 4) out[z++] = 255;
+         }
+         stbi__skip(s, pad);
+      }
+   } else {
+      int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0;
+      int z = 0;
+      int easy=0;
+      stbi__skip(s, offset - 14 - hsz);
+      if (bpp == 24) width = 3 * s->img_x;
+      else if (bpp == 16) width = 2*s->img_x;
+      else /* bpp = 32 and pad = 0 */ width=0;
+      pad = (-width) & 3;
+      if (bpp == 24) {
+         easy = 1;
+      } else if (bpp == 32) {
+         if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000)
+            easy = 2;
+      }
+      if (!easy) {
+         if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); }
+         // right shift amt to put high bit in position #7
+         rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr);
+         gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg);
+         bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb);
+         ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma);
+      }
+      for (j=0; j < (int) s->img_y; ++j) {
+         if (easy) {
+            for (i=0; i < (int) s->img_x; ++i) {
+               unsigned char a;
+               out[z+2] = stbi__get8(s);
+               out[z+1] = stbi__get8(s);
+               out[z+0] = stbi__get8(s);
+               z += 3;
+               a = (easy == 2 ? stbi__get8(s) : 255);
+               if (target == 4) out[z++] = a;
+            }
+         } else {
+            for (i=0; i < (int) s->img_x; ++i) {
+               stbi__uint32 v = (stbi__uint32) (bpp == 16 ? stbi__get16le(s) : stbi__get32le(s));
+               int a;
+               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount));
+               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount));
+               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount));
+               a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255);
+               if (target == 4) out[z++] = STBI__BYTECAST(a);
+            }
+         }
+         stbi__skip(s, pad);
+      }
+   }
+   if (flip_vertically) {
+      stbi_uc t;
+      for (j=0; j < (int) s->img_y>>1; ++j) {
+         stbi_uc *p1 = out +      j     *s->img_x*target;
+         stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target;
+         for (i=0; i < (int) s->img_x*target; ++i) {
+            t = p1[i], p1[i] = p2[i], p2[i] = t;
+         }
+      }
+   }
+
+   if (req_comp && req_comp != target) {
+      out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y);
+      if (out == NULL) return out; // stbi__convert_format frees input on failure
+   }
+
+   *x = s->img_x;
+   *y = s->img_y;
+   if (comp) *comp = s->img_n;
+   return out;
+}
+#endif
+
+// Targa Truevision - TGA
+// by Jonathan Dummer
+#ifndef STBI_NO_TGA
+static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp)
+{
+    int tga_w, tga_h, tga_comp;
+    int sz;
+    stbi__get8(s);                   // discard Offset
+    sz = stbi__get8(s);              // color type
+    if( sz > 1 ) {
+        stbi__rewind(s);
+        return 0;      // only RGB or indexed allowed
+    }
+    sz = stbi__get8(s);              // image type
+    // only RGB or grey allowed, +/- RLE
+    if ((sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11)) return 0;
+    stbi__skip(s,9);
+    tga_w = stbi__get16le(s);
+    if( tga_w < 1 ) {
+        stbi__rewind(s);
+        return 0;   // test width
+    }
+    tga_h = stbi__get16le(s);
+    if( tga_h < 1 ) {
+        stbi__rewind(s);
+        return 0;   // test height
+    }
+    sz = stbi__get8(s);               // bits per pixel
+    // only RGB or RGBA or grey allowed
+    if ((sz != 8) && (sz != 16) && (sz != 24) && (sz != 32)) {
+        stbi__rewind(s);
+        return 0;
+    }
+    tga_comp = sz;
+    if (x) *x = tga_w;
+    if (y) *y = tga_h;
+    if (comp) *comp = tga_comp / 8;
+    return 1;                   // seems to have passed everything
+}
+
+static int stbi__tga_test(stbi__context *s)
+{
+   int res;
+   int sz;
+   stbi__get8(s);      //   discard Offset
+   sz = stbi__get8(s);   //   color type
+   if ( sz > 1 ) return 0;   //   only RGB or indexed allowed
+   sz = stbi__get8(s);   //   image type
+   if ( (sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11) ) return 0;   //   only RGB or grey allowed, +/- RLE
+   stbi__get16be(s);      //   discard palette start
+   stbi__get16be(s);      //   discard palette length
+   stbi__get8(s);         //   discard bits per palette color entry
+   stbi__get16be(s);      //   discard x origin
+   stbi__get16be(s);      //   discard y origin
+   if ( stbi__get16be(s) < 1 ) return 0;      //   test width
+   if ( stbi__get16be(s) < 1 ) return 0;      //   test height
+   sz = stbi__get8(s);   //   bits per pixel
+   if ( (sz != 8) && (sz != 16) && (sz != 24) && (sz != 32) )
+      res = 0;
+   else
+      res = 1;
+   stbi__rewind(s);
+   return res;
+}
+
+static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   //   read in the TGA header stuff
+   int tga_offset = stbi__get8(s);
+   int tga_indexed = stbi__get8(s);
+   int tga_image_type = stbi__get8(s);
+   int tga_is_RLE = 0;
+   int tga_palette_start = stbi__get16le(s);
+   int tga_palette_len = stbi__get16le(s);
+   int tga_palette_bits = stbi__get8(s);
+   int tga_x_origin = stbi__get16le(s);
+   int tga_y_origin = stbi__get16le(s);
+   int tga_width = stbi__get16le(s);
+   int tga_height = stbi__get16le(s);
+   int tga_bits_per_pixel = stbi__get8(s);
+   int tga_comp = tga_bits_per_pixel / 8;
+   int tga_inverted = stbi__get8(s);
+   //   image data
+   unsigned char *tga_data;
+   unsigned char *tga_palette = NULL;
+   int i, j;
+   unsigned char raw_data[4];
+   int RLE_count = 0;
+   int RLE_repeating = 0;
+   int read_next_pixel = 1;
+
+   //   do a tiny bit of precessing
+   if ( tga_image_type >= 8 )
+   {
+      tga_image_type -= 8;
+      tga_is_RLE = 1;
+   }
+   /* int tga_alpha_bits = tga_inverted & 15; */
+   tga_inverted = 1 - ((tga_inverted >> 5) & 1);
+
+   //   error check
+   if ( //(tga_indexed) ||
+      (tga_width < 1) || (tga_height < 1) ||
+      (tga_image_type < 1) || (tga_image_type > 3) ||
+      ((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16) &&
+      (tga_bits_per_pixel != 24) && (tga_bits_per_pixel != 32))
+      )
+   {
+      return NULL; // we don't report this as a bad TGA because we don't even know if it's TGA
+   }
+
+   //   If I'm paletted, then I'll use the number of bits from the palette
+   if ( tga_indexed )
+   {
+      tga_comp = tga_palette_bits / 8;
+   }
+
+   //   tga info
+   *x = tga_width;
+   *y = tga_height;
+   if (comp) *comp = tga_comp;
+
+   tga_data = (unsigned char*)stbi__malloc( tga_width * tga_height * tga_comp );
+   if (!tga_data) return stbi__errpuc("outofmem", "Out of memory");
+
+   // skip to the data's starting position (offset usually = 0)
+   stbi__skip(s, tga_offset );
+
+   if ( !tga_indexed && !tga_is_RLE) {
+      for (i=0; i < tga_height; ++i) {
+         int y = tga_inverted ? tga_height -i - 1 : i;
+         stbi_uc *tga_row = tga_data + y*tga_width*tga_comp;
+         stbi__getn(s, tga_row, tga_width * tga_comp);
+      }
+   } else  {
+      //   do I need to load a palette?
+      if ( tga_indexed)
+      {
+         //   any data to skip? (offset usually = 0)
+         stbi__skip(s, tga_palette_start );
+         //   load the palette
+         tga_palette = (unsigned char*)stbi__malloc( tga_palette_len * tga_palette_bits / 8 );
+         if (!tga_palette) {
+            STBI_FREE(tga_data);
+            return stbi__errpuc("outofmem", "Out of memory");
+         }
+         if (!stbi__getn(s, tga_palette, tga_palette_len * tga_palette_bits / 8 )) {
+            STBI_FREE(tga_data);
+            STBI_FREE(tga_palette);
+            return stbi__errpuc("bad palette", "Corrupt TGA");
+         }
+      }
+      //   load the data
+      for (i=0; i < tga_width * tga_height; ++i)
+      {
+         //   if I'm in RLE mode, do I need to get a RLE stbi__pngchunk?
+         if ( tga_is_RLE )
+         {
+            if ( RLE_count == 0 )
+            {
+               //   yep, get the next byte as a RLE command
+               int RLE_cmd = stbi__get8(s);
+               RLE_count = 1 + (RLE_cmd & 127);
+               RLE_repeating = RLE_cmd >> 7;
+               read_next_pixel = 1;
+            } else if ( !RLE_repeating )
+            {
+               read_next_pixel = 1;
+            }
+         } else
+         {
+            read_next_pixel = 1;
+         }
+         //   OK, if I need to read a pixel, do it now
+         if ( read_next_pixel )
+         {
+            //   load however much data we did have
+            if ( tga_indexed )
+            {
+               //   read in 1 byte, then perform the lookup
+               int pal_idx = stbi__get8(s);
+               if ( pal_idx >= tga_palette_len )
+               {
+                  //   invalid index
+                  pal_idx = 0;
+               }
+               pal_idx *= tga_bits_per_pixel / 8;
+               for (j = 0; j*8 < tga_bits_per_pixel; ++j)
+               {
+                  raw_data[j] = tga_palette[pal_idx+j];
+               }
+            } else
+            {
+               //   read in the data raw
+               for (j = 0; j*8 < tga_bits_per_pixel; ++j)
+               {
+                  raw_data[j] = stbi__get8(s);
+               }
+            }
+            //   clear the reading flag for the next pixel
+            read_next_pixel = 0;
+         } // end of reading a pixel
+
+         // copy data
+         for (j = 0; j < tga_comp; ++j)
+           tga_data[i*tga_comp+j] = raw_data[j];
+
+         //   in case we're in RLE mode, keep counting down
+         --RLE_count;
+      }
+      //   do I need to invert the image?
+      if ( tga_inverted )
+      {
+         for (j = 0; j*2 < tga_height; ++j)
+         {
+            int index1 = j * tga_width * tga_comp;
+            int index2 = (tga_height - 1 - j) * tga_width * tga_comp;
+            for (i = tga_width * tga_comp; i > 0; --i)
+            {
+               unsigned char temp = tga_data[index1];
+               tga_data[index1] = tga_data[index2];
+               tga_data[index2] = temp;
+               ++index1;
+               ++index2;
+            }
+         }
+      }
+      //   clear my palette, if I had one
+      if ( tga_palette != NULL )
+      {
+         STBI_FREE( tga_palette );
+      }
+   }
+
+   // swap RGB
+   if (tga_comp >= 3)
+   {
+      unsigned char* tga_pixel = tga_data;
+      for (i=0; i < tga_width * tga_height; ++i)
+      {
+         unsigned char temp = tga_pixel[0];
+         tga_pixel[0] = tga_pixel[2];
+         tga_pixel[2] = temp;
+         tga_pixel += tga_comp;
+      }
+   }
+
+   // convert to target component count
+   if (req_comp && req_comp != tga_comp)
+      tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height);
+
+   //   the things I do to get rid of an error message, and yet keep
+   //   Microsoft's C compilers happy... [8^(
+   tga_palette_start = tga_palette_len = tga_palette_bits =
+         tga_x_origin = tga_y_origin = 0;
+   //   OK, done
+   return tga_data;
+}
+#endif
+
+// *************************************************************************************************
+// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB
+
+#ifndef STBI_NO_PSD
+static int stbi__psd_test(stbi__context *s)
+{
+   int r = (stbi__get32be(s) == 0x38425053);
+   stbi__rewind(s);
+   return r;
+}
+
+static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   int   pixelCount;
+   int channelCount, compression;
+   int channel, i, count, len;
+   int w,h;
+   stbi_uc *out;
+
+   // Check identifier
+   if (stbi__get32be(s) != 0x38425053)   // "8BPS"
+      return stbi__errpuc("not PSD", "Corrupt PSD image");
+
+   // Check file type version.
+   if (stbi__get16be(s) != 1)
+      return stbi__errpuc("wrong version", "Unsupported version of PSD image");
+
+   // Skip 6 reserved bytes.
+   stbi__skip(s, 6 );
+
+   // Read the number of channels (R, G, B, A, etc).
+   channelCount = stbi__get16be(s);
+   if (channelCount < 0 || channelCount > 16)
+      return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image");
+
+   // Read the rows and columns of the image.
+   h = stbi__get32be(s);
+   w = stbi__get32be(s);
+
+   // Make sure the depth is 8 bits.
+   if (stbi__get16be(s) != 8)
+      return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 bit");
+
+   // Make sure the color mode is RGB.
+   // Valid options are:
+   //   0: Bitmap
+   //   1: Grayscale
+   //   2: Indexed color
+   //   3: RGB color
+   //   4: CMYK color
+   //   7: Multichannel
+   //   8: Duotone
+   //   9: Lab color
+   if (stbi__get16be(s) != 3)
+      return stbi__errpuc("wrong color format", "PSD is not in RGB color format");
+
+   // Skip the Mode Data.  (It's the palette for indexed color; other info for other modes.)
+   stbi__skip(s,stbi__get32be(s) );
+
+   // Skip the image resources.  (resolution, pen tool paths, etc)
+   stbi__skip(s, stbi__get32be(s) );
+
+   // Skip the reserved data.
+   stbi__skip(s, stbi__get32be(s) );
+
+   // Find out if the data is compressed.
+   // Known values:
+   //   0: no compression
+   //   1: RLE compressed
+   compression = stbi__get16be(s);
+   if (compression > 1)
+      return stbi__errpuc("bad compression", "PSD has an unknown compression format");
+
+   // Create the destination image.
+   out = (stbi_uc *) stbi__malloc(4 * w*h);
+   if (!out) return stbi__errpuc("outofmem", "Out of memory");
+   pixelCount = w*h;
+
+   // Initialize the data to zero.
+   //memset( out, 0, pixelCount * 4 );
+
+   // Finally, the image data.
+   if (compression) {
+      // RLE as used by .PSD and .TIFF
+      // Loop until you get the number of unpacked bytes you are expecting:
+      //     Read the next source byte into n.
+      //     If n is between 0 and 127 inclusive, copy the next n+1 bytes literally.
+      //     Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times.
+      //     Else if n is 128, noop.
+      // Endloop
+
+      // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data,
+      // which we're going to just skip.
+      stbi__skip(s, h * channelCount * 2 );
+
+      // Read the RLE data by channel.
+      for (channel = 0; channel < 4; channel++) {
+         stbi_uc *p;
+
+         p = out+channel;
+         if (channel >= channelCount) {
+            // Fill this channel with default data.
+            for (i = 0; i < pixelCount; i++) *p = (channel == 3 ? 255 : 0), p += 4;
+         } else {
+            // Read the RLE data.
+            count = 0;
+            while (count < pixelCount) {
+               len = stbi__get8(s);
+               if (len == 128) {
+                  // No-op.
+               } else if (len < 128) {
+                  // Copy next len+1 bytes literally.
+                  len++;
+                  count += len;
+                  while (len) {
+                     *p = stbi__get8(s);
+                     p += 4;
+                     len--;
+                  }
+               } else if (len > 128) {
+                  stbi_uc   val;
+                  // Next -len+1 bytes in the dest are replicated from next source byte.
+                  // (Interpret len as a negative 8-bit int.)
+                  len ^= 0x0FF;
+                  len += 2;
+                  val = stbi__get8(s);
+                  count += len;
+                  while (len) {
+                     *p = val;
+                     p += 4;
+                     len--;
+                  }
+               }
+            }
+         }
+      }
+
+   } else {
+      // We're at the raw image data.  It's each channel in order (Red, Green, Blue, Alpha, ...)
+      // where each channel consists of an 8-bit value for each pixel in the image.
+
+      // Read the data by channel.
+      for (channel = 0; channel < 4; channel++) {
+         stbi_uc *p;
+
+         p = out + channel;
+         if (channel > channelCount) {
+            // Fill this channel with default data.
+            for (i = 0; i < pixelCount; i++) *p = channel == 3 ? 255 : 0, p += 4;
+         } else {
+            // Read the data.
+            for (i = 0; i < pixelCount; i++)
+               *p = stbi__get8(s), p += 4;
+         }
+      }
+   }
+
+   if (req_comp && req_comp != 4) {
+      out = stbi__convert_format(out, 4, req_comp, w, h);
+      if (out == NULL) return out; // stbi__convert_format frees input on failure
+   }
+
+   if (comp) *comp = channelCount;
+   *y = h;
+   *x = w;
+
+   return out;
+}
+#endif
+
+// *************************************************************************************************
+// Softimage PIC loader
+// by Tom Seddon
+//
+// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format
+// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/
+
+#ifndef STBI_NO_PIC
+static int stbi__pic_is4(stbi__context *s,const char *str)
+{
+   int i;
+   for (i=0; i<4; ++i)
+      if (stbi__get8(s) != (stbi_uc)str[i])
+         return 0;
+
+   return 1;
+}
+
+static int stbi__pic_test_core(stbi__context *s)
+{
+   int i;
+
+   if (!stbi__pic_is4(s,"\x53\x80\xF6\x34"))
+      return 0;
+
+   for(i=0;i<84;++i)
+      stbi__get8(s);
+
+   if (!stbi__pic_is4(s,"PICT"))
+      return 0;
+
+   return 1;
+}
+
+typedef struct
+{
+   stbi_uc size,type,channel;
+} stbi__pic_packet;
+
+static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest)
+{
+   int mask=0x80, i;
+
+   for (i=0; i<4; ++i, mask>>=1) {
+      if (channel & mask) {
+         if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short");
+         dest[i]=stbi__get8(s);
+      }
+   }
+
+   return dest;
+}
+
+static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src)
+{
+   int mask=0x80,i;
+
+   for (i=0;i<4; ++i, mask>>=1)
+      if (channel&mask)
+         dest[i]=src[i];
+}
+
+static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result)
+{
+   int act_comp=0,num_packets=0,y,chained;
+   stbi__pic_packet packets[10];
+
+   // this will (should...) cater for even some bizarre stuff like having data
+    // for the same channel in multiple packets.
+   do {
+      stbi__pic_packet *packet;
+
+      if (num_packets==sizeof(packets)/sizeof(packets[0]))
+         return stbi__errpuc("bad format","too many packets");
+
+      packet = &packets[num_packets++];
+
+      chained = stbi__get8(s);
+      packet->size    = stbi__get8(s);
+      packet->type    = stbi__get8(s);
+      packet->channel = stbi__get8(s);
+
+      act_comp |= packet->channel;
+
+      if (stbi__at_eof(s))          return stbi__errpuc("bad file","file too short (reading packets)");
+      if (packet->size != 8)  return stbi__errpuc("bad format","packet isn't 8bpp");
+   } while (chained);
+
+   *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel?
+
+   for(y=0; y<height; ++y) {
+      int packet_idx;
+
+      for(packet_idx=0; packet_idx < num_packets; ++packet_idx) {
+         stbi__pic_packet *packet = &packets[packet_idx];
+         stbi_uc *dest = result+y*width*4;
+
+         switch (packet->type) {
+            default:
+               return stbi__errpuc("bad format","packet has bad compression type");
+
+            case 0: {//uncompressed
+               int x;
+
+               for(x=0;x<width;++x, dest+=4)
+                  if (!stbi__readval(s,packet->channel,dest))
+                     return 0;
+               break;
+            }
+
+            case 1://Pure RLE
+               {
+                  int left=width, i;
+
+                  while (left>0) {
+                     stbi_uc count,value[4];
+
+                     count=stbi__get8(s);
+                     if (stbi__at_eof(s))   return stbi__errpuc("bad file","file too short (pure read count)");
+
+                     if (count > left)
+                        count = (stbi_uc) left;
+
+                     if (!stbi__readval(s,packet->channel,value))  return 0;
+
+                     for(i=0; i<count; ++i,dest+=4)
+                        stbi__copyval(packet->channel,dest,value);
+                     left -= count;
+                  }
+               }
+               break;
+
+            case 2: {//Mixed RLE
+               int left=width;
+               while (left>0) {
+                  int count = stbi__get8(s), i;
+                  if (stbi__at_eof(s))  return stbi__errpuc("bad file","file too short (mixed read count)");
+
+                  if (count >= 128) { // Repeated
+                     stbi_uc value[4];
+                     int i;
+
+                     if (count==128)
+                        count = stbi__get16be(s);
+                     else
+                        count -= 127;
+                     if (count > left)
+                        return stbi__errpuc("bad file","scanline overrun");
+
+                     if (!stbi__readval(s,packet->channel,value))
+                        return 0;
+
+                     for(i=0;i<count;++i, dest += 4)
+                        stbi__copyval(packet->channel,dest,value);
+                  } else { // Raw
+                     ++count;
+                     if (count>left) return stbi__errpuc("bad file","scanline overrun");
+
+                     for(i=0;i<count;++i, dest+=4)
+                        if (!stbi__readval(s,packet->channel,dest))
+                           return 0;
+                  }
+                  left-=count;
+               }
+               break;
+            }
+         }
+      }
+   }
+
+   return result;
+}
+
+static stbi_uc *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp)
+{
+   stbi_uc *result;
+   int i, x,y;
+
+   for (i=0; i<92; ++i)
+      stbi__get8(s);
+
+   x = stbi__get16be(s);
+   y = stbi__get16be(s);
+   if (stbi__at_eof(s))  return stbi__errpuc("bad file","file too short (pic header)");
+   if ((1 << 28) / x < y) return stbi__errpuc("too large", "Image too large to decode");
+
+   stbi__get32be(s); //skip `ratio'
+   stbi__get16be(s); //skip `fields'
+   stbi__get16be(s); //skip `pad'
+
+   // intermediate buffer is RGBA
+   result = (stbi_uc *) stbi__malloc(x*y*4);
+   memset(result, 0xff, x*y*4);
+
+   if (!stbi__pic_load_core(s,x,y,comp, result)) {
+      STBI_FREE(result);
+      result=0;
+   }
+   *px = x;
+   *py = y;
+   if (req_comp == 0) req_comp = *comp;
+   result=stbi__convert_format(result,4,req_comp,x,y);
+
+   return result;
+}
+
+static int stbi__pic_test(stbi__context *s)
+{
+   int r = stbi__pic_test_core(s);
+   stbi__rewind(s);
+   return r;
+}
+#endif
+
+// *************************************************************************************************
+// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb
+
+#ifndef STBI_NO_GIF
+typedef struct
+{
+   stbi__int16 prefix;
+   stbi_uc first;
+   stbi_uc suffix;
+} stbi__gif_lzw;
+
+typedef struct
+{
+   int w,h;
+   stbi_uc *out;                 // output buffer (always 4 components)
+   int flags, bgindex, ratio, transparent, eflags;
+   stbi_uc  pal[256][4];
+   stbi_uc lpal[256][4];
+   stbi__gif_lzw codes[4096];
+   stbi_uc *color_table;
+   int parse, step;
+   int lflags;
+   int start_x, start_y;
+   int max_x, max_y;
+   int cur_x, cur_y;
+   int line_size;
+} stbi__gif;
+
+static int stbi__gif_test_raw(stbi__context *s)
+{
+   int sz;
+   if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0;
+   sz = stbi__get8(s);
+   if (sz != '9' && sz != '7') return 0;
+   if (stbi__get8(s) != 'a') return 0;
+   return 1;
+}
+
+static int stbi__gif_test(stbi__context *s)
+{
+   int r = stbi__gif_test_raw(s);
+   stbi__rewind(s);
+   return r;
+}
+
+static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp)
+{
+   int i;
+   for (i=0; i < num_entries; ++i) {
+      pal[i][2] = stbi__get8(s);
+      pal[i][1] = stbi__get8(s);
+      pal[i][0] = stbi__get8(s);
+      pal[i][3] = transp == i ? 0 : 255;
+   }
+}
+
+static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info)
+{
+   stbi_uc version;
+   if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8')
+      return stbi__err("not GIF", "Corrupt GIF");
+
+   version = stbi__get8(s);
+   if (version != '7' && version != '9')    return stbi__err("not GIF", "Corrupt GIF");
+   if (stbi__get8(s) != 'a')                return stbi__err("not GIF", "Corrupt GIF");
+
+   stbi__g_failure_reason = "";
+   g->w = stbi__get16le(s);
+   g->h = stbi__get16le(s);
+   g->flags = stbi__get8(s);
+   g->bgindex = stbi__get8(s);
+   g->ratio = stbi__get8(s);
+   g->transparent = -1;
+
+   if (comp != 0) *comp = 4;  // can't actually tell whether it's 3 or 4 until we parse the comments
+
+   if (is_info) return 1;
+
+   if (g->flags & 0x80)
+      stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1);
+
+   return 1;
+}
+
+static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp)
+{
+   stbi__gif g;
+   if (!stbi__gif_header(s, &g, comp, 1)) {
+      stbi__rewind( s );
+      return 0;
+   }
+   if (x) *x = g.w;
+   if (y) *y = g.h;
+   return 1;
+}
+
+static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
+{
+   stbi_uc *p, *c;
+
+   // recurse to decode the prefixes, since the linked-list is backwards,
+   // and working backwards through an interleaved image would be nasty
+   if (g->codes[code].prefix >= 0)
+      stbi__out_gif_code(g, g->codes[code].prefix);
+
+   if (g->cur_y >= g->max_y) return;
+
+   p = &g->out[g->cur_x + g->cur_y];
+   c = &g->color_table[g->codes[code].suffix * 4];
+
+   if (c[3] >= 128) {
+      p[0] = c[2];
+      p[1] = c[1];
+      p[2] = c[0];
+      p[3] = c[3];
+   }
+   g->cur_x += 4;
+
+   if (g->cur_x >= g->max_x) {
+      g->cur_x = g->start_x;
+      g->cur_y += g->step;
+
+      while (g->cur_y >= g->max_y && g->parse > 0) {
+         g->step = (1 << g->parse) * g->line_size;
+         g->cur_y = g->start_y + (g->step >> 1);
+         --g->parse;
+      }
+   }
+}
+
+static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)
+{
+   stbi_uc lzw_cs;
+   stbi__int32 len, code;
+   stbi__uint32 first;
+   stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear;
+   stbi__gif_lzw *p;
+
+   lzw_cs = stbi__get8(s);
+   clear = 1 << lzw_cs;
+   first = 1;
+   codesize = lzw_cs + 1;
+   codemask = (1 << codesize) - 1;
+   bits = 0;
+   valid_bits = 0;
+   for (code = 0; code < clear; code++) {
+      g->codes[code].prefix = -1;
+      g->codes[code].first = (stbi_uc) code;
+      g->codes[code].suffix = (stbi_uc) code;
+   }
+
+   // support no starting clear code
+   avail = clear+2;
+   oldcode = -1;
+
+   len = 0;
+   for(;;) {
+      if (valid_bits < codesize) {
+         if (len == 0) {
+            len = stbi__get8(s); // start new block
+            if (len == 0)
+               return g->out;
+         }
+         --len;
+         bits |= (stbi__int32) stbi__get8(s) << valid_bits;
+         valid_bits += 8;
+      } else {
+         stbi__int32 code = bits & codemask;
+         bits >>= codesize;
+         valid_bits -= codesize;
+         // @OPTIMIZE: is there some way we can accelerate the non-clear path?
+         if (code == clear) {  // clear code
+            codesize = lzw_cs + 1;
+            codemask = (1 << codesize) - 1;
+            avail = clear + 2;
+            oldcode = -1;
+            first = 0;
+         } else if (code == clear + 1) { // end of stream code
+            stbi__skip(s, len);
+            while ((len = stbi__get8(s)) > 0)
+               stbi__skip(s,len);
+            return g->out;
+         } else if (code <= avail) {
+            if (first) return stbi__errpuc("no clear code", "Corrupt GIF");
+
+            if (oldcode >= 0) {
+               p = &g->codes[avail++];
+               if (avail > 4096)        return stbi__errpuc("too many codes", "Corrupt GIF");
+               p->prefix = (stbi__int16) oldcode;
+               p->first = g->codes[oldcode].first;
+               p->suffix = (code == avail) ? p->first : g->codes[code].first;
+            } else if (code == avail)
+               return stbi__errpuc("illegal code in raster", "Corrupt GIF");
+
+            stbi__out_gif_code(g, (stbi__uint16) code);
+
+            if ((avail & codemask) == 0 && avail <= 0x0FFF) {
+               codesize++;
+               codemask = (1 << codesize) - 1;
+            }
+
+            oldcode = code;
+         } else {
+            return stbi__errpuc("illegal code in raster", "Corrupt GIF");
+         }
+      }
+   }
+}
+
+static void stbi__fill_gif_background(stbi__gif *g)
+{
+   int i;
+   stbi_uc *c = g->pal[g->bgindex];
+   // @OPTIMIZE: write a dword at a time
+   for (i = 0; i < g->w * g->h * 4; i += 4) {
+      stbi_uc *p  = &g->out[i];
+      p[0] = c[2];
+      p[1] = c[1];
+      p[2] = c[0];
+      p[3] = c[3];
+   }
+}
+
+// this function is designed to support animated gifs, although stb_image doesn't support it
+static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp)
+{
+   int i;
+   stbi_uc *old_out = 0;
+
+   if (g->out == 0) {
+      if (!stbi__gif_header(s, g, comp,0))     return 0; // stbi__g_failure_reason set by stbi__gif_header
+      g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h);
+      if (g->out == 0)                      return stbi__errpuc("outofmem", "Out of memory");
+      stbi__fill_gif_background(g);
+   } else {
+      // animated-gif-only path
+      if (((g->eflags & 0x1C) >> 2) == 3) {
+         old_out = g->out;
+         g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h);
+         if (g->out == 0)                   return stbi__errpuc("outofmem", "Out of memory");
+         memcpy(g->out, old_out, g->w*g->h*4);
+      }
+   }
+
+   for (;;) {
+      switch (stbi__get8(s)) {
+         case 0x2C: /* Image Descriptor */
+         {
+            stbi__int32 x, y, w, h;
+            stbi_uc *o;
+
+            x = stbi__get16le(s);
+            y = stbi__get16le(s);
+            w = stbi__get16le(s);
+            h = stbi__get16le(s);
+            if (((x + w) > (g->w)) || ((y + h) > (g->h)))
+               return stbi__errpuc("bad Image Descriptor", "Corrupt GIF");
+
+            g->line_size = g->w * 4;
+            g->start_x = x * 4;
+            g->start_y = y * g->line_size;
+            g->max_x   = g->start_x + w * 4;
+            g->max_y   = g->start_y + h * g->line_size;
+            g->cur_x   = g->start_x;
+            g->cur_y   = g->start_y;
+
+            g->lflags = stbi__get8(s);
+
+            if (g->lflags & 0x40) {
+               g->step = 8 * g->line_size; // first interlaced spacing
+               g->parse = 3;
+            } else {
+               g->step = g->line_size;
+               g->parse = 0;
+            }
+
+            if (g->lflags & 0x80) {
+               stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1);
+               g->color_table = (stbi_uc *) g->lpal;
+            } else if (g->flags & 0x80) {
+               for (i=0; i < 256; ++i)  // @OPTIMIZE: stbi__jpeg_reset only the previous transparent
+                  g->pal[i][3] = 255;
+               if (g->transparent >= 0 && (g->eflags & 0x01))
+                  g->pal[g->transparent][3] = 0;
+               g->color_table = (stbi_uc *) g->pal;
+            } else
+               return stbi__errpuc("missing color table", "Corrupt GIF");
+
+            o = stbi__process_gif_raster(s, g);
+            if (o == NULL) return NULL;
+
+            if (req_comp && req_comp != 4)
+               o = stbi__convert_format(o, 4, req_comp, g->w, g->h);
+            return o;
+         }
+
+         case 0x21: // Comment Extension.
+         {
+            int len;
+            if (stbi__get8(s) == 0xF9) { // Graphic Control Extension.
+               len = stbi__get8(s);
+               if (len == 4) {
+                  g->eflags = stbi__get8(s);
+                  stbi__get16le(s); // delay
+                  g->transparent = stbi__get8(s);
+               } else {
+                  stbi__skip(s, len);
+                  break;
+               }
+            }
+            while ((len = stbi__get8(s)) != 0)
+               stbi__skip(s, len);
+            break;
+         }
+
+         case 0x3B: // gif stream termination code
+            return (stbi_uc *) s; // using '1' causes warning on some compilers
+
+         default:
+            return stbi__errpuc("unknown code", "Corrupt GIF");
+      }
+   }
+}
+
+static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   stbi_uc *u = 0;
+   stbi__gif g;
+   memset(&g, 0, sizeof(g));
+
+   u = stbi__gif_load_next(s, &g, comp, req_comp);
+   if (u == (stbi_uc *) s) u = 0;  // end of animated gif marker
+   if (u) {
+      *x = g.w;
+      *y = g.h;
+   }
+
+   return u;
+}
+
+static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   return stbi__gif_info_raw(s,x,y,comp);
+}
+#endif
+
+// *************************************************************************************************
+// Radiance RGBE HDR loader
+// originally by Nicolas Schulz
+#ifndef STBI_NO_HDR
+static int stbi__hdr_test_core(stbi__context *s)
+{
+   const char *signature = "#?RADIANCE\n";
+   int i;
+   for (i=0; signature[i]; ++i)
+      if (stbi__get8(s) != signature[i])
+         return 0;
+   return 1;
+}
+
+static int stbi__hdr_test(stbi__context* s)
+{
+   int r = stbi__hdr_test_core(s);
+   stbi__rewind(s);
+   return r;
+}
+
+#define STBI__HDR_BUFLEN  1024
+static char *stbi__hdr_gettoken(stbi__context *z, char *buffer)
+{
+   int len=0;
+   char c = '\0';
+
+   c = (char) stbi__get8(z);
+
+   while (!stbi__at_eof(z) && c != '\n') {
+      buffer[len++] = c;
+      if (len == STBI__HDR_BUFLEN-1) {
+         // flush to end of line
+         while (!stbi__at_eof(z) && stbi__get8(z) != '\n')
+            ;
+         break;
+      }
+      c = (char) stbi__get8(z);
+   }
+
+   buffer[len] = 0;
+   return buffer;
+}
+
+static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp)
+{
+   if ( input[3] != 0 ) {
+      float f1;
+      // Exponent
+      f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8));
+      if (req_comp <= 2)
+         output[0] = (input[0] + input[1] + input[2]) * f1 / 3;
+      else {
+         output[0] = input[0] * f1;
+         output[1] = input[1] * f1;
+         output[2] = input[2] * f1;
+      }
+      if (req_comp == 2) output[1] = 1;
+      if (req_comp == 4) output[3] = 1;
+   } else {
+      switch (req_comp) {
+         case 4: output[3] = 1; /* fallthrough */
+         case 3: output[0] = output[1] = output[2] = 0;
+                 break;
+         case 2: output[1] = 1; /* fallthrough */
+         case 1: output[0] = 0;
+                 break;
+      }
+   }
+}
+
+static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   char buffer[STBI__HDR_BUFLEN];
+   char *token;
+   int valid = 0;
+   int width, height;
+   stbi_uc *scanline;
+   float *hdr_data;
+   int len;
+   unsigned char count, value;
+   int i, j, k, c1,c2, z;
+
+
+   // Check identifier
+   if (strcmp(stbi__hdr_gettoken(s,buffer), "#?RADIANCE") != 0)
+      return stbi__errpf("not HDR", "Corrupt HDR image");
+
+   // Parse header
+   for(;;) {
+      token = stbi__hdr_gettoken(s,buffer);
+      if (token[0] == 0) break;
+      if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1;
+   }
+
+   if (!valid)    return stbi__errpf("unsupported format", "Unsupported HDR format");
+
+   // Parse width and height
+   // can't use sscanf() if we're not using stdio!
+   token = stbi__hdr_gettoken(s,buffer);
+   if (strncmp(token, "-Y ", 3))  return stbi__errpf("unsupported data layout", "Unsupported HDR format");
+   token += 3;
+   height = (int) strtol(token, &token, 10);
+   while (*token == ' ') ++token;
+   if (strncmp(token, "+X ", 3))  return stbi__errpf("unsupported data layout", "Unsupported HDR format");
+   token += 3;
+   width = (int) strtol(token, NULL, 10);
+
+   *x = width;
+   *y = height;
+
+   if (comp) *comp = 3;
+   if (req_comp == 0) req_comp = 3;
+
+   // Read data
+   hdr_data = (float *) stbi__malloc(height * width * req_comp * sizeof(float));
+
+   // Load image data
+   // image data is stored as some number of sca
+   if ( width < 8 || width >= 32768) {
+      // Read flat data
+      for (j=0; j < height; ++j) {
+         for (i=0; i < width; ++i) {
+            stbi_uc rgbe[4];
+           main_decode_loop:
+            stbi__getn(s, rgbe, 4);
+            stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp);
+         }
+      }
+   } else {
+      // Read RLE-encoded data
+      scanline = NULL;
+
+      for (j = 0; j < height; ++j) {
+         c1 = stbi__get8(s);
+         c2 = stbi__get8(s);
+         len = stbi__get8(s);
+         if (c1 != 2 || c2 != 2 || (len & 0x80)) {
+            // not run-length encoded, so we have to actually use THIS data as a decoded
+            // pixel (note this can't be a valid pixel--one of RGB must be >= 128)
+            stbi_uc rgbe[4];
+            rgbe[0] = (stbi_uc) c1;
+            rgbe[1] = (stbi_uc) c2;
+            rgbe[2] = (stbi_uc) len;
+            rgbe[3] = (stbi_uc) stbi__get8(s);
+            stbi__hdr_convert(hdr_data, rgbe, req_comp);
+            i = 1;
+            j = 0;
+            STBI_FREE(scanline);
+            goto main_decode_loop; // yes, this makes no sense
+         }
+         len <<= 8;
+         len |= stbi__get8(s);
+         if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); }
+         if (scanline == NULL) scanline = (stbi_uc *) stbi__malloc(width * 4);
+
+         for (k = 0; k < 4; ++k) {
+            i = 0;
+            while (i < width) {
+               count = stbi__get8(s);
+               if (count > 128) {
+                  // Run
+                  value = stbi__get8(s);
+                  count -= 128;
+                  for (z = 0; z < count; ++z)
+                     scanline[i++ * 4 + k] = value;
+               } else {
+                  // Dump
+                  for (z = 0; z < count; ++z)
+                     scanline[i++ * 4 + k] = stbi__get8(s);
+               }
+            }
+         }
+         for (i=0; i < width; ++i)
+            stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp);
+      }
+      STBI_FREE(scanline);
+   }
+
+   return hdr_data;
+}
+
+static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   char buffer[STBI__HDR_BUFLEN];
+   char *token;
+   int valid = 0;
+
+   if (strcmp(stbi__hdr_gettoken(s,buffer), "#?RADIANCE") != 0) {
+       stbi__rewind( s );
+       return 0;
+   }
+
+   for(;;) {
+      token = stbi__hdr_gettoken(s,buffer);
+      if (token[0] == 0) break;
+      if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1;
+   }
+
+   if (!valid) {
+       stbi__rewind( s );
+       return 0;
+   }
+   token = stbi__hdr_gettoken(s,buffer);
+   if (strncmp(token, "-Y ", 3)) {
+       stbi__rewind( s );
+       return 0;
+   }
+   token += 3;
+   *y = (int) strtol(token, &token, 10);
+   while (*token == ' ') ++token;
+   if (strncmp(token, "+X ", 3)) {
+       stbi__rewind( s );
+       return 0;
+   }
+   token += 3;
+   *x = (int) strtol(token, NULL, 10);
+   *comp = 3;
+   return 1;
+}
+#endif // STBI_NO_HDR
+
+#ifndef STBI_NO_BMP
+static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   int hsz;
+   if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') {
+       stbi__rewind( s );
+       return 0;
+   }
+   stbi__skip(s,12);
+   hsz = stbi__get32le(s);
+   if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) {
+       stbi__rewind( s );
+       return 0;
+   }
+   if (hsz == 12) {
+      *x = stbi__get16le(s);
+      *y = stbi__get16le(s);
+   } else {
+      *x = stbi__get32le(s);
+      *y = stbi__get32le(s);
+   }
+   if (stbi__get16le(s) != 1) {
+       stbi__rewind( s );
+       return 0;
+   }
+   *comp = stbi__get16le(s) / 8;
+   return 1;
+}
+#endif
+
+#ifndef STBI_NO_PSD
+static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   int channelCount;
+   if (stbi__get32be(s) != 0x38425053) {
+       stbi__rewind( s );
+       return 0;
+   }
+   if (stbi__get16be(s) != 1) {
+       stbi__rewind( s );
+       return 0;
+   }
+   stbi__skip(s, 6);
+   channelCount = stbi__get16be(s);
+   if (channelCount < 0 || channelCount > 16) {
+       stbi__rewind( s );
+       return 0;
+   }
+   *y = stbi__get32be(s);
+   *x = stbi__get32be(s);
+   if (stbi__get16be(s) != 8) {
+       stbi__rewind( s );
+       return 0;
+   }
+   if (stbi__get16be(s) != 3) {
+       stbi__rewind( s );
+       return 0;
+   }
+   *comp = 4;
+   return 1;
+}
+#endif
+
+#ifndef STBI_NO_PIC
+static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   int act_comp=0,num_packets=0,chained;
+   stbi__pic_packet packets[10];
+
+   stbi__skip(s, 92);
+
+   *x = stbi__get16be(s);
+   *y = stbi__get16be(s);
+   if (stbi__at_eof(s))  return 0;
+   if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) {
+       stbi__rewind( s );
+       return 0;
+   }
+
+   stbi__skip(s, 8);
+
+   do {
+      stbi__pic_packet *packet;
+
+      if (num_packets==sizeof(packets)/sizeof(packets[0]))
+         return 0;
+
+      packet = &packets[num_packets++];
+      chained = stbi__get8(s);
+      packet->size    = stbi__get8(s);
+      packet->type    = stbi__get8(s);
+      packet->channel = stbi__get8(s);
+      act_comp |= packet->channel;
+
+      if (stbi__at_eof(s)) {
+          stbi__rewind( s );
+          return 0;
+      }
+      if (packet->size != 8) {
+          stbi__rewind( s );
+          return 0;
+      }
+   } while (chained);
+
+   *comp = (act_comp & 0x10 ? 4 : 3);
+
+   return 1;
+}
+#endif
+
+// *************************************************************************************************
+// Portable Gray Map and Portable Pixel Map loader
+// by Ken Miller
+//
+// PGM: http://netpbm.sourceforge.net/doc/pgm.html
+// PPM: http://netpbm.sourceforge.net/doc/ppm.html
+//
+// Known limitations:
+//    Does not support comments in the header section
+//    Does not support ASCII image data (formats P2 and P3)
+//    Does not support 16-bit-per-channel
+
+#ifndef STBI_NO_PNM
+
+static int      stbi__pnm_test(stbi__context *s)
+{
+   char p, t;
+   p = (char) stbi__get8(s);
+   t = (char) stbi__get8(s);
+   if (p != 'P' || (t != '5' && t != '6')) {
+       stbi__rewind( s );
+       return 0;
+   }
+   return 1;
+}
+
+static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   stbi_uc *out;
+   if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n))
+      return 0;
+   *x = s->img_x;
+   *y = s->img_y;
+   *comp = s->img_n;
+
+   out = (stbi_uc *) stbi__malloc(s->img_n * s->img_x * s->img_y);
+   if (!out) return stbi__errpuc("outofmem", "Out of memory");
+   stbi__getn(s, out, s->img_n * s->img_x * s->img_y);
+
+   if (req_comp && req_comp != s->img_n) {
+      out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y);
+      if (out == NULL) return out; // stbi__convert_format frees input on failure
+   }
+   return out;
+}
+
+static int      stbi__pnm_isspace(char c)
+{
+   return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r';
+}
+
+static void     stbi__pnm_skip_whitespace(stbi__context *s, char *c)
+{
+   while (!stbi__at_eof(s) && stbi__pnm_isspace(*c))
+      *c = (char) stbi__get8(s);
+}
+
+static int      stbi__pnm_isdigit(char c)
+{
+   return c >= '0' && c <= '9';
+}
+
+static int      stbi__pnm_getinteger(stbi__context *s, char *c)
+{
+   int value = 0;
+
+   while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) {
+      value = value*10 + (*c - '0');
+      *c = (char) stbi__get8(s);
+   }
+
+   return value;
+}
+
+static int      stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   int maxv;
+   char c, p, t;
+
+   stbi__rewind( s );
+
+   // Get identifier
+   p = (char) stbi__get8(s);
+   t = (char) stbi__get8(s);
+   if (p != 'P' || (t != '5' && t != '6')) {
+       stbi__rewind( s );
+       return 0;
+   }
+
+   *comp = (t == '6') ? 3 : 1;  // '5' is 1-component .pgm; '6' is 3-component .ppm
+
+   c = (char) stbi__get8(s);
+   stbi__pnm_skip_whitespace(s, &c);
+
+   *x = stbi__pnm_getinteger(s, &c); // read width
+   stbi__pnm_skip_whitespace(s, &c);
+
+   *y = stbi__pnm_getinteger(s, &c); // read height
+   stbi__pnm_skip_whitespace(s, &c);
+
+   maxv = stbi__pnm_getinteger(s, &c);  // read max value
+
+   if (maxv > 255)
+      return stbi__err("max value > 255", "PPM image not 8-bit");
+   else
+      return 1;
+}
+#endif
+
+static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp)
+{
+   #ifndef STBI_NO_JPEG
+   if (stbi__jpeg_info(s, x, y, comp)) return 1;
+   #endif
+
+   #ifndef STBI_NO_PNG
+   if (stbi__png_info(s, x, y, comp))  return 1;
+   #endif
+
+   #ifndef STBI_NO_GIF
+   if (stbi__gif_info(s, x, y, comp))  return 1;
+   #endif
+
+   #ifndef STBI_NO_BMP
+   if (stbi__bmp_info(s, x, y, comp))  return 1;
+   #endif
+
+   #ifndef STBI_NO_PSD
+   if (stbi__psd_info(s, x, y, comp))  return 1;
+   #endif
+
+   #ifndef STBI_NO_PIC
+   if (stbi__pic_info(s, x, y, comp))  return 1;
+   #endif
+
+   #ifndef STBI_NO_PNM
+   if (stbi__pnm_info(s, x, y, comp))  return 1;
+   #endif
+
+   #ifndef STBI_NO_HDR
+   if (stbi__hdr_info(s, x, y, comp))  return 1;
+   #endif
+
+   // test tga last because it's a crappy test!
+   #ifndef STBI_NO_TGA
+   if (stbi__tga_info(s, x, y, comp))
+       return 1;
+   #endif
+   return stbi__err("unknown image type", "Image not of any known type, or corrupt");
+}
+
+#ifndef STBI_NO_STDIO
+STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp)
+{
+    FILE *f = stbi__fopen(filename, "rb");
+    int result;
+    if (!f) return stbi__err("can't fopen", "Unable to open file");
+    result = stbi_info_from_file(f, x, y, comp);
+    fclose(f);
+    return result;
+}
+
+STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp)
+{
+   int r;
+   stbi__context s;
+   long pos = ftell(f);
+   stbi__start_file(&s, f);
+   r = stbi__info_main(&s,x,y,comp);
+   fseek(f,pos,SEEK_SET);
+   return r;
+}
+#endif // !STBI_NO_STDIO
+
+STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp)
+{
+   stbi__context s;
+   stbi__start_mem(&s,buffer,len);
+   return stbi__info_main(&s,x,y,comp);
+}
+
+STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp)
+{
+   stbi__context s;
+   stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user);
+   return stbi__info_main(&s,x,y,comp);
+}
+
+#endif // STB_IMAGE_IMPLEMENTATION
+
+/*
+   revision history:
+      2.02  (2015-01-19) fix incorrect assert, fix warning
+      2.01  (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2
+      2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG
+      2.00  (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg)
+                         progressive JPEG (stb)
+                         PGM/PPM support (Ken Miller)
+                         STBI_MALLOC,STBI_REALLOC,STBI_FREE
+                         GIF bugfix -- seemingly never worked
+                         STBI_NO_*, STBI_ONLY_*
+      1.48  (2014-12-14) fix incorrectly-named assert()
+      1.47  (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb)
+                         optimize PNG (ryg)
+                         fix bug in interlaced PNG with user-specified channel count (stb)
+      1.46  (2014-08-26)
+              fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG
+      1.45  (2014-08-16)
+              fix MSVC-ARM internal compiler error by wrapping malloc
+      1.44  (2014-08-07)
+              various warning fixes from Ronny Chevalier
+      1.43  (2014-07-15)
+              fix MSVC-only compiler problem in code changed in 1.42
+      1.42  (2014-07-09)
+              don't define _CRT_SECURE_NO_WARNINGS (affects user code)
+              fixes to stbi__cleanup_jpeg path
+              added STBI_ASSERT to avoid requiring assert.h
+      1.41  (2014-06-25)
+              fix search&replace from 1.36 that messed up comments/error messages
+      1.40  (2014-06-22)
+              fix gcc struct-initialization warning
+      1.39  (2014-06-15)
+              fix to TGA optimization when req_comp != number of components in TGA;
+              fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite)
+              add support for BMP version 5 (more ignored fields)
+      1.38  (2014-06-06)
+              suppress MSVC warnings on integer casts truncating values
+              fix accidental rename of 'skip' field of I/O
+      1.37  (2014-06-04)
+              remove duplicate typedef
+      1.36  (2014-06-03)
+              convert to header file single-file library
+              if de-iphone isn't set, load iphone images color-swapped instead of returning NULL
+      1.35  (2014-05-27)
+              various warnings
+              fix broken STBI_SIMD path
+              fix bug where stbi_load_from_file no longer left file pointer in correct place
+              fix broken non-easy path for 32-bit BMP (possibly never used)
+              TGA optimization by Arseny Kapoulkine
+      1.34  (unknown)
+              use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case
+      1.33  (2011-07-14)
+              make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements
+      1.32  (2011-07-13)
+              support for "info" function for all supported filetypes (SpartanJ)
+      1.31  (2011-06-20)
+              a few more leak fixes, bug in PNG handling (SpartanJ)
+      1.30  (2011-06-11)
+              added ability to load files via callbacks to accomidate custom input streams (Ben Wenger)
+              removed deprecated format-specific test/load functions
+              removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway
+              error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha)
+              fix inefficiency in decoding 32-bit BMP (David Woo)
+      1.29  (2010-08-16)
+              various warning fixes from Aurelien Pocheville
+      1.28  (2010-08-01)
+              fix bug in GIF palette transparency (SpartanJ)
+      1.27  (2010-08-01)
+              cast-to-stbi_uc to fix warnings
+      1.26  (2010-07-24)
+              fix bug in file buffering for PNG reported by SpartanJ
+      1.25  (2010-07-17)
+              refix trans_data warning (Won Chun)
+      1.24  (2010-07-12)
+              perf improvements reading from files on platforms with lock-heavy fgetc()
+              minor perf improvements for jpeg
+              deprecated type-specific functions so we'll get feedback if they're needed
+              attempt to fix trans_data warning (Won Chun)
+      1.23    fixed bug in iPhone support
+      1.22  (2010-07-10)
+              removed image *writing* support
+              stbi_info support from Jetro Lauha
+              GIF support from Jean-Marc Lienher
+              iPhone PNG-extensions from James Brown
+              warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva)
+      1.21    fix use of 'stbi_uc' in header (reported by jon blow)
+      1.20    added support for Softimage PIC, by Tom Seddon
+      1.19    bug in interlaced PNG corruption check (found by ryg)
+      1.18 2008-08-02
+              fix a threading bug (local mutable static)
+      1.17    support interlaced PNG
+      1.16    major bugfix - stbi__convert_format converted one too many pixels
+      1.15    initialize some fields for thread safety
+      1.14    fix threadsafe conversion bug
+              header-file-only version (#define STBI_HEADER_FILE_ONLY before including)
+      1.13    threadsafe
+      1.12    const qualifiers in the API
+      1.11    Support installable IDCT, colorspace conversion routines
+      1.10    Fixes for 64-bit (don't use "unsigned long")
+              optimized upsampling by Fabian "ryg" Giesen
+      1.09    Fix format-conversion for PSD code (bad global variables!)
+      1.08    Thatcher Ulrich's PSD code integrated by Nicolas Schulz
+      1.07    attempt to fix C++ warning/errors again
+      1.06    attempt to fix C++ warning/errors again
+      1.05    fix TGA loading to return correct *comp and use good luminance calc
+      1.04    default float alpha is 1, not 255; use 'void *' for stbi_image_free
+      1.03    bugfixes to STBI_NO_STDIO, STBI_NO_HDR
+      1.02    support for (subset of) HDR files, float interface for preferred access to them
+      1.01    fix bug: possible bug in handling right-side up bmps... not sure
+              fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all
+      1.00    interface to zlib that skips zlib header
+      0.99    correct handling of alpha in palette
+      0.98    TGA loader by lonesock; dynamically add loaders (untested)
+      0.97    jpeg errors on too large a file; also catch another malloc failure
+      0.96    fix detection of invalid v value - particleman@mollyrocket forum
+      0.95    during header scan, seek to markers in case of padding
+      0.94    STBI_NO_STDIO to disable stdio usage; rename all #defines the same
+      0.93    handle jpegtran output; verbose errors
+      0.92    read 4,8,16,24,32-bit BMP files of several formats
+      0.91    output 24-bit Windows 3.0 BMP files
+      0.90    fix a few more warnings; bump version number to approach 1.0
+      0.61    bugfixes due to Marc LeBlanc, Christopher Lloyd
+      0.60    fix compiling as c++
+      0.59    fix warnings: merge Dave Moore's -Wall fixes
+      0.58    fix bug: zlib uncompressed mode len/nlen was wrong endian
+      0.57    fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available
+      0.56    fix bug: zlib uncompressed mode len vs. nlen
+      0.55    fix bug: restart_interval not initialized to 0
+      0.54    allow NULL for 'int *comp'
+      0.53    fix bug in png 3->4; speedup png decoding
+      0.52    png handles req_comp=3,4 directly; minor cleanup; jpeg comments
+      0.51    obey req_comp requests, 1-component jpegs return as 1-component,
+              on 'test' only check type, not whether we support this variant
+      0.50    first released version
+*/

+ 928 - 0
direct/src/plugin_npapi/npapi.h

@@ -0,0 +1,928 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef npapi_h_
+#define npapi_h_
+
+#if defined(__OS2__)
+#pragma pack(1)
+#endif
+
+#include "nptypes.h"
+
+#if defined(__OS2__) || defined(OS2)
+#ifndef XP_OS2
+#define XP_OS2 1
+#endif
+#endif
+
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
+#include <windef.h>
+#ifndef XP_WIN
+#define XP_WIN 1
+#endif
+#endif
+
+#if defined(__SYMBIAN32__)
+#ifndef XP_SYMBIAN
+#define XP_SYMBIAN 1
+#undef XP_WIN
+#endif
+#endif
+
+#if defined(__APPLE_CC__) && !defined(XP_UNIX)
+#ifndef XP_MACOSX
+#define XP_MACOSX 1
+#endif
+#endif
+
+#if defined(XP_MACOSX)
+#if !defined(NP_NO_OPENGL)
+#define NP_NO_OPENGL 1
+#endif /* !defined(NP_NO_OPENGL) */
+#if defined(__LP64__)
+#define NP_NO_QUICKDRAW
+#define NP_NO_CARBON
+#endif /* defined(__LP64__) */
+#endif
+
+#if defined(XP_MACOSX)
+#include <ApplicationServices/ApplicationServices.h>
+#if !NP_NO_OPENGL
+#include <OpenGL/OpenGL.h>
+#endif /* !NP_NO_OPENGL */
+#ifndef NP_NO_CARBON
+#include <Carbon/Carbon.h>
+#endif
+#endif
+
+#if defined(XP_UNIX)
+#include <stdio.h>
+#if defined(MOZ_X11)
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#endif
+#endif
+
+#if defined(XP_SYMBIAN)
+#include <QEvent>
+#include <QRegion>
+#endif
+
+/*----------------------------------------------------------------------*/
+/*                        Plugin Version Constants                      */
+/*----------------------------------------------------------------------*/
+
+#define NP_VERSION_MAJOR 0
+#define NP_VERSION_MINOR 28
+
+
+/* The OS/2 version of Netscape uses RC_DATA to define the
+   mime types, file extensions, etc that are required.
+   Use a vertical bar to separate types, end types with \0.
+   FileVersion and ProductVersion are 32bit ints, all other
+   entries are strings that MUST be terminated with a \0.
+
+AN EXAMPLE:
+
+RCDATA NP_INFO_ProductVersion { 1,0,0,1,}
+
+RCDATA NP_INFO_MIMEType    { "video/x-video|",
+                             "video/x-flick\0" }
+RCDATA NP_INFO_FileExtents { "avi|",
+                             "flc\0" }
+RCDATA NP_INFO_FileOpenName{ "MMOS2 video player(*.avi)|",
+                             "MMOS2 Flc/Fli player(*.flc)\0" }
+
+RCDATA NP_INFO_FileVersion       { 1,0,0,1 }
+RCDATA NP_INFO_CompanyName       { "Netscape Communications\0" }
+RCDATA NP_INFO_FileDescription   { "NPAVI32 Extension DLL\0"
+RCDATA NP_INFO_InternalName      { "NPAVI32\0" )
+RCDATA NP_INFO_LegalCopyright    { "Copyright Netscape Communications \251 1996\0"
+RCDATA NP_INFO_OriginalFilename  { "NVAPI32.DLL" }
+RCDATA NP_INFO_ProductName       { "NPAVI32 Dynamic Link Library\0" }
+*/
+/* RC_DATA types for version info - required */
+#define NP_INFO_ProductVersion      1
+#define NP_INFO_MIMEType            2
+#define NP_INFO_FileOpenName        3
+#define NP_INFO_FileExtents         4
+/* RC_DATA types for version info - used if found */
+#define NP_INFO_FileDescription     5
+#define NP_INFO_ProductName         6
+/* RC_DATA types for version info - optional */
+#define NP_INFO_CompanyName         7
+#define NP_INFO_FileVersion         8
+#define NP_INFO_InternalName        9
+#define NP_INFO_LegalCopyright      10
+#define NP_INFO_OriginalFilename    11
+
+#ifndef RC_INVOKED
+
+/*----------------------------------------------------------------------*/
+/*                       Definition of Basic Types                      */
+/*----------------------------------------------------------------------*/
+
+typedef unsigned char NPBool;
+typedef int16_t       NPError;
+typedef int16_t       NPReason;
+typedef char*         NPMIMEType;
+
+/*----------------------------------------------------------------------*/
+/*                       Structures and definitions                     */
+/*----------------------------------------------------------------------*/
+
+#if !defined(__LP64__)
+#if defined(XP_MACOSX)
+#pragma options align=mac68k
+#endif
+#endif /* __LP64__ */
+
+/*
+ *  NPP is a plug-in's opaque instance handle
+ */
+typedef struct _NPP
+{
+  void* pdata;      /* plug-in private data */
+  void* ndata;      /* netscape private data */
+} NPP_t;
+
+typedef NPP_t*  NPP;
+
+typedef struct _NPStream
+{
+  void*    pdata; /* plug-in private data */
+  void*    ndata; /* netscape private data */
+  const    char* url;
+  uint32_t end;
+  uint32_t lastmodified;
+  void*    notifyData;
+  const    char* headers; /* Response headers from host.
+                           * Exists only for >= NPVERS_HAS_RESPONSE_HEADERS.
+                           * Used for HTTP only; NULL for non-HTTP.
+                           * Available from NPP_NewStream onwards.
+                           * Plugin should copy this data before storing it.
+                           * Includes HTTP status line and all headers,
+                           * preferably verbatim as received from server,
+                           * headers formatted as in HTTP ("Header: Value"),
+                           * and newlines (\n, NOT \r\n) separating lines.
+                           * Terminated by \n\0 (NOT \n\n\0). */
+} NPStream;
+
+typedef struct _NPByteRange
+{
+  int32_t  offset; /* negative offset means from the end */
+  uint32_t length;
+  struct _NPByteRange* next;
+} NPByteRange;
+
+typedef struct _NPSavedData
+{
+  int32_t len;
+  void*   buf;
+} NPSavedData;
+
+typedef struct _NPRect
+{
+  uint16_t top;
+  uint16_t left;
+  uint16_t bottom;
+  uint16_t right;
+} NPRect;
+
+typedef struct _NPSize
+{
+  int32_t width;
+  int32_t height;
+} NPSize;
+
+typedef enum {
+  NPFocusNext = 0,
+  NPFocusPrevious = 1
+} NPFocusDirection;
+
+/* Return values for NPP_HandleEvent */
+#define kNPEventNotHandled 0
+#define kNPEventHandled 1
+/* Exact meaning must be spec'd in event model. */
+#define kNPEventStartIME 2
+
+#if defined(XP_UNIX)
+/*
+ * Unix specific structures and definitions
+ */
+
+/*
+ * Callback Structures.
+ *
+ * These are used to pass additional platform specific information.
+ */
+enum {
+  NP_SETWINDOW = 1,
+  NP_PRINT
+};
+
+typedef struct
+{
+  int32_t type;
+} NPAnyCallbackStruct;
+
+typedef struct
+{
+  int32_t      type;
+#if defined(MOZ_X11)
+  Display*     display;
+  Visual*      visual;
+  Colormap     colormap;
+  unsigned int depth;
+#endif
+} NPSetWindowCallbackStruct;
+
+typedef struct
+{
+  int32_t type;
+  FILE* fp;
+} NPPrintCallbackStruct;
+
+#endif /* XP_UNIX */
+
+typedef enum {
+    NPDrawingModelDUMMY
+#if defined(XP_MACOSX)
+#ifndef NP_NO_QUICKDRAW
+  , NPDrawingModelQuickDraw = 0
+#endif
+  , NPDrawingModelCoreGraphics = 1
+  , NPDrawingModelOpenGL = 2
+  , NPDrawingModelCoreAnimation = 3
+  , NPDrawingModelInvalidatingCoreAnimation = 4
+#endif
+#if defined(XP_WIN)
+  , NPDrawingModelSyncWin = 5
+#endif
+#if defined(MOZ_X11)
+  , NPDrawingModelSyncX = 6
+#endif
+#if 0 /* OBSOLETE */
+  , NPDrawingModelAsyncBitmapSurfaceOBSOLETE = 7
+#if defined(XP_WIN)
+  , NPDrawingModelAsyncWindowsDXGISurfaceOBSOLETE = 8
+#endif
+#endif
+} NPDrawingModel;
+
+#ifdef XP_MACOSX
+typedef enum {
+#ifndef NP_NO_CARBON
+  NPEventModelCarbon = 0,
+#endif
+  NPEventModelCocoa = 1
+} NPEventModel;
+#endif
+
+/*
+ *   The following masks are applied on certain platforms to NPNV and
+ *   NPPV selectors that pass around pointers to COM interfaces. Newer
+ *   compilers on some platforms may generate vtables that are not
+ *   compatible with older compilers. To prevent older plugins from
+ *   not understanding a new browser's ABI, these masks change the
+ *   values of those selectors on those platforms. To remain backwards
+ *   compatible with different versions of the browser, plugins can
+ *   use these masks to dynamically determine and use the correct C++
+ *   ABI that the browser is expecting. This does not apply to Windows
+ *   as Microsoft's COM ABI will likely not change.
+ */
+
+#define NP_ABI_GCC3_MASK  0x10000000
+/*
+ *   gcc 3.x generated vtables on UNIX and OSX are incompatible with
+ *   previous compilers.
+ */
+#if (defined(XP_UNIX) && defined(__GNUC__) && (__GNUC__ >= 3))
+#define _NP_ABI_MIXIN_FOR_GCC3 NP_ABI_GCC3_MASK
+#else
+#define _NP_ABI_MIXIN_FOR_GCC3 0
+#endif
+
+#if defined(XP_MACOSX)
+#define NP_ABI_MACHO_MASK 0x01000000
+#define _NP_ABI_MIXIN_FOR_MACHO NP_ABI_MACHO_MASK
+#else
+#define _NP_ABI_MIXIN_FOR_MACHO 0
+#endif
+
+#define NP_ABI_MASK (_NP_ABI_MIXIN_FOR_GCC3 | _NP_ABI_MIXIN_FOR_MACHO)
+
+/*
+ * List of variable names for which NPP_GetValue shall be implemented
+ */
+typedef enum {
+  NPPVpluginNameString = 1,
+  NPPVpluginDescriptionString,
+  NPPVpluginWindowBool,
+  NPPVpluginTransparentBool,
+  NPPVjavaClass,
+  NPPVpluginWindowSize,
+  NPPVpluginTimerInterval,
+  NPPVpluginScriptableInstance = (10 | NP_ABI_MASK),
+  NPPVpluginScriptableIID = 11,
+  NPPVjavascriptPushCallerBool = 12,
+  NPPVpluginKeepLibraryInMemory = 13,
+  NPPVpluginNeedsXEmbed         = 14,
+
+  /* Get the NPObject for scripting the plugin. Introduced in NPAPI minor version 14.
+   */
+  NPPVpluginScriptableNPObject  = 15,
+
+  /* Get the plugin value (as \0-terminated UTF-8 string data) for
+   * form submission if the plugin is part of a form. Use
+   * NPN_MemAlloc() to allocate memory for the string data. Introduced
+   * in NPAPI minor version 15.
+   */
+  NPPVformValue = 16,
+
+  NPPVpluginUrlRequestsDisplayedBool = 17,
+
+  /* Checks if the plugin is interested in receiving the http body of
+   * all http requests (including failed ones, http status != 200).
+   */
+  NPPVpluginWantsAllNetworkStreams = 18,
+
+  /* Browsers can retrieve a native ATK accessibility plug ID via this variable. */
+  NPPVpluginNativeAccessibleAtkPlugId = 19,
+
+  /* Checks to see if the plug-in would like the browser to load the "src" attribute. */
+  NPPVpluginCancelSrcStream = 20,
+
+  NPPVsupportsAdvancedKeyHandling = 21,
+
+  NPPVpluginUsesDOMForCursorBool = 22,
+
+  /* Used for negotiating drawing models */
+  NPPVpluginDrawingModel = 1000
+#if defined(XP_MACOSX)
+  /* Used for negotiating event models */
+  , NPPVpluginEventModel = 1001
+  /* In the NPDrawingModelCoreAnimation drawing model, the browser asks the plug-in for a Core Animation layer. */
+  , NPPVpluginCoreAnimationLayer = 1003
+#endif
+
+#if defined(MOZ_PLATFORM_MAEMO) && ((MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6))
+  , NPPVpluginWindowlessLocalBool = 2002
+#endif
+} NPPVariable;
+
+/*
+ * List of variable names for which NPN_GetValue should be implemented.
+ */
+typedef enum {
+  NPNVxDisplay = 1,
+  NPNVxtAppContext,
+  NPNVnetscapeWindow,
+  NPNVjavascriptEnabledBool,
+  NPNVasdEnabledBool,
+  NPNVisOfflineBool,
+
+  NPNVserviceManager = (10 | NP_ABI_MASK),
+  NPNVDOMElement     = (11 | NP_ABI_MASK),
+  NPNVDOMWindow      = (12 | NP_ABI_MASK),
+  NPNVToolkit        = (13 | NP_ABI_MASK),
+  NPNVSupportsXEmbedBool = 14,
+
+  /* Get the NPObject wrapper for the browser window. */
+  NPNVWindowNPObject = 15,
+
+  /* Get the NPObject wrapper for the plugins DOM element. */
+  NPNVPluginElementNPObject = 16,
+
+  NPNVSupportsWindowless = 17,
+
+  NPNVprivateModeBool = 18,
+
+  NPNVsupportsAdvancedKeyHandling = 21,
+
+  NPNVdocumentOrigin = 22,
+
+  NPNVpluginDrawingModel = 1000 /* Get the current drawing model (NPDrawingModel) */
+#if defined(XP_MACOSX)
+  , NPNVcontentsScaleFactor = 1001
+#ifndef NP_NO_QUICKDRAW
+  , NPNVsupportsQuickDrawBool = 2000
+#endif
+  , NPNVsupportsCoreGraphicsBool = 2001
+  , NPNVsupportsOpenGLBool = 2002
+  , NPNVsupportsCoreAnimationBool = 2003
+  , NPNVsupportsInvalidatingCoreAnimationBool = 2004
+#endif
+#if 0 /* OBSOLETE */
+  , NPNVsupportsAsyncBitmapSurfaceBoolOBSOLETE = 2007
+#if defined(XP_WIN)
+  , NPNVsupportsAsyncWindowsDXGISurfaceBoolOBSOLETE = 2008
+#endif
+#endif
+#if defined(XP_MACOSX)
+#ifndef NP_NO_CARBON
+  , NPNVsupportsCarbonBool = 3000 /* TRUE if the browser supports the Carbon event model */
+#endif
+  , NPNVsupportsCocoaBool = 3001 /* TRUE if the browser supports the Cocoa event model */
+  , NPNVsupportsUpdatedCocoaTextInputBool = 3002 /* TRUE if the browser supports the updated
+                                                    Cocoa text input specification. */
+  , NPNVsupportsCompositingCoreAnimationPluginsBool = 74656 /* TRUE if the browser supports
+                                                               CA model compositing */
+#endif
+#if defined(MOZ_PLATFORM_MAEMO) && ((MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6))
+  , NPNVSupportsWindowlessLocal = 2002
+#endif
+} NPNVariable;
+
+typedef enum {
+  NPNURLVCookie = 501,
+  NPNURLVProxy
+} NPNURLVariable;
+
+/*
+ * The type of Toolkit the widgets use
+ */
+typedef enum {
+  NPNVGtk12 = 1,
+  NPNVGtk2
+} NPNToolkitType;
+
+/*
+ * The type of a NPWindow - it specifies the type of the data structure
+ * returned in the window field.
+ */
+typedef enum {
+  NPWindowTypeWindow = 1,
+  NPWindowTypeDrawable
+} NPWindowType;
+
+typedef struct _NPWindow
+{
+  void* window;  /* Platform specific window handle */
+                 /* OS/2: x - Position of bottom left corner */
+                 /* OS/2: y - relative to visible netscape window */
+  int32_t  x;      /* Position of top left corner relative */
+  int32_t  y;      /* to a netscape page. */
+  uint32_t width;  /* Maximum window size */
+  uint32_t height;
+  NPRect   clipRect; /* Clipping rectangle in port coordinates */
+#if (defined(XP_UNIX) || defined(XP_SYMBIAN)) && !defined(XP_MACOSX)
+  void * ws_info; /* Platform-dependent additional data */
+#endif /* XP_UNIX */
+  NPWindowType type; /* Is this a window or a drawable? */
+} NPWindow;
+
+typedef struct _NPImageExpose
+{
+  char*    data;       /* image pointer */
+  int32_t  stride;     /* Stride of data image pointer */
+  int32_t  depth;      /* Depth of image pointer */
+  int32_t  x;          /* Expose x */
+  int32_t  y;          /* Expose y */
+  uint32_t width;      /* Expose width */
+  uint32_t height;     /* Expose height */
+  NPSize   dataSize;   /* Data buffer size */
+  float    translateX; /* translate X matrix value */
+  float    translateY; /* translate Y matrix value */
+  float    scaleX;     /* scale X matrix value */
+  float    scaleY;     /* scale Y matrix value */
+} NPImageExpose;
+
+typedef struct _NPFullPrint
+{
+  NPBool pluginPrinted;/* Set TRUE if plugin handled fullscreen printing */
+  NPBool printOne;     /* TRUE if plugin should print one copy to default
+                          printer */
+  void* platformPrint; /* Platform-specific printing info */
+} NPFullPrint;
+
+typedef struct _NPEmbedPrint
+{
+  NPWindow window;
+  void* platformPrint; /* Platform-specific printing info */
+} NPEmbedPrint;
+
+typedef struct _NPPrint
+{
+  uint16_t mode;               /* NP_FULL or NP_EMBED */
+  union
+  {
+    NPFullPrint fullPrint;   /* if mode is NP_FULL */
+    NPEmbedPrint embedPrint; /* if mode is NP_EMBED */
+  } print;
+} NPPrint;
+
+#if defined(XP_MACOSX)
+#ifndef NP_NO_CARBON
+typedef EventRecord NPEvent;
+#endif
+#elif defined(XP_SYMBIAN)
+typedef QEvent NPEvent;
+#elif defined(XP_WIN)
+typedef struct _NPEvent
+{
+  uint16_t event;
+  uintptr_t wParam;
+  uintptr_t lParam;
+} NPEvent;
+#elif defined(XP_OS2)
+typedef struct _NPEvent
+{
+  uint32_t event;
+  uint32_t wParam;
+  uint32_t lParam;
+} NPEvent;
+#elif defined(XP_UNIX) && defined(MOZ_X11)
+typedef XEvent NPEvent;
+#else
+typedef void*  NPEvent;
+#endif
+
+#if defined(XP_MACOSX)
+typedef void* NPRegion;
+#ifndef NP_NO_QUICKDRAW
+typedef RgnHandle NPQDRegion;
+#endif
+typedef CGPathRef NPCGRegion;
+#elif defined(XP_WIN)
+typedef HRGN NPRegion;
+#elif defined(XP_UNIX) && defined(MOZ_X11)
+typedef Region NPRegion;
+#elif defined(XP_SYMBIAN)
+typedef QRegion* NPRegion;
+#else
+typedef void *NPRegion;
+#endif
+
+typedef struct _NPNSString NPNSString;
+typedef struct _NPNSWindow NPNSWindow;
+typedef struct _NPNSMenu   NPNSMenu;
+
+#if defined(XP_MACOSX)
+typedef NPNSMenu NPMenu;
+#else
+typedef void *NPMenu;
+#endif
+
+typedef enum {
+  NPCoordinateSpacePlugin = 1,
+  NPCoordinateSpaceWindow,
+  NPCoordinateSpaceFlippedWindow,
+  NPCoordinateSpaceScreen,
+  NPCoordinateSpaceFlippedScreen
+} NPCoordinateSpace;
+
+#if defined(XP_MACOSX)
+
+#ifndef NP_NO_QUICKDRAW
+typedef struct NP_Port
+{
+  CGrafPtr port;
+  int32_t portx; /* position inside the topmost window */
+  int32_t porty;
+} NP_Port;
+#endif /* NP_NO_QUICKDRAW */
+
+/*
+ * NP_CGContext is the type of the NPWindow's 'window' when the plugin specifies NPDrawingModelCoreGraphics
+ * as its drawing model.
+ */
+
+typedef struct NP_CGContext
+{
+  CGContextRef context;
+  void *window; /* A WindowRef under the Carbon event model. */
+} NP_CGContext;
+
+/*
+ * NP_GLContext is the type of the NPWindow's 'window' when the plugin specifies NPDrawingModelOpenGL as its
+ * drawing model.
+ */
+
+#if !NP_NO_OPENGL
+typedef struct NP_GLContext
+{
+  CGLContextObj context;
+#ifdef NP_NO_CARBON
+  NPNSWindow *window;
+#else
+  void *window; /* Can be either an NSWindow or a WindowRef depending on the event model */
+#endif
+} NP_GLContext;
+#endif /* !NP_NO_OPENGL */
+
+typedef enum {
+  NPCocoaEventDrawRect = 1,
+  NPCocoaEventMouseDown,
+  NPCocoaEventMouseUp,
+  NPCocoaEventMouseMoved,
+  NPCocoaEventMouseEntered,
+  NPCocoaEventMouseExited,
+  NPCocoaEventMouseDragged,
+  NPCocoaEventKeyDown,
+  NPCocoaEventKeyUp,
+  NPCocoaEventFlagsChanged,
+  NPCocoaEventFocusChanged,
+  NPCocoaEventWindowFocusChanged,
+  NPCocoaEventScrollWheel,
+  NPCocoaEventTextInput
+} NPCocoaEventType;
+
+typedef struct _NPCocoaEvent {
+  NPCocoaEventType type;
+  uint32_t version;
+  union {
+    struct {
+      uint32_t modifierFlags;
+      double   pluginX;
+      double   pluginY;
+      int32_t  buttonNumber;
+      int32_t  clickCount;
+      double   deltaX;
+      double   deltaY;
+      double   deltaZ;
+    } mouse;
+    struct {
+      uint32_t    modifierFlags;
+      NPNSString *characters;
+      NPNSString *charactersIgnoringModifiers;
+      NPBool      isARepeat;
+      uint16_t    keyCode;
+    } key;
+    struct {
+      CGContextRef context;
+      double x;
+      double y;
+      double width;
+      double height;
+    } draw;
+    struct {
+      NPBool hasFocus;
+    } focus;
+    struct {
+      NPNSString *text;
+    } text;
+  } data;
+} NPCocoaEvent;
+
+#ifndef NP_NO_CARBON
+/* Non-standard event types that can be passed to HandleEvent */
+enum NPEventType {
+  NPEventType_GetFocusEvent = (osEvt + 16),
+  NPEventType_LoseFocusEvent,
+  NPEventType_AdjustCursorEvent,
+  NPEventType_MenuCommandEvent,
+  NPEventType_ClippingChangedEvent,
+  NPEventType_ScrollingBeginsEvent = 1000,
+  NPEventType_ScrollingEndsEvent
+};
+#endif /* NP_NO_CARBON */
+
+#endif /* XP_MACOSX */
+
+/*
+ * Values for mode passed to NPP_New:
+ */
+#define NP_EMBED 1
+#define NP_FULL  2
+
+/*
+ * Values for stream type passed to NPP_NewStream:
+ */
+#define NP_NORMAL     1
+#define NP_SEEK       2
+#define NP_ASFILE     3
+#define NP_ASFILEONLY 4
+
+#define NP_MAXREADY (((unsigned)(~0)<<1)>>1)
+
+/*
+ * Flags for NPP_ClearSiteData.
+ */
+#define NP_CLEAR_ALL   0
+#define NP_CLEAR_CACHE (1 << 0)
+
+#if !defined(__LP64__)
+#if defined(XP_MACOSX)
+#pragma options align=reset
+#endif
+#endif /* __LP64__ */
+
+/*----------------------------------------------------------------------*/
+/*       Error and Reason Code definitions                              */
+/*----------------------------------------------------------------------*/
+
+/*
+ * Values of type NPError:
+ */
+#define NPERR_BASE                         0
+#define NPERR_NO_ERROR                    (NPERR_BASE + 0)
+#define NPERR_GENERIC_ERROR               (NPERR_BASE + 1)
+#define NPERR_INVALID_INSTANCE_ERROR      (NPERR_BASE + 2)
+#define NPERR_INVALID_FUNCTABLE_ERROR     (NPERR_BASE + 3)
+#define NPERR_MODULE_LOAD_FAILED_ERROR    (NPERR_BASE + 4)
+#define NPERR_OUT_OF_MEMORY_ERROR         (NPERR_BASE + 5)
+#define NPERR_INVALID_PLUGIN_ERROR        (NPERR_BASE + 6)
+#define NPERR_INVALID_PLUGIN_DIR_ERROR    (NPERR_BASE + 7)
+#define NPERR_INCOMPATIBLE_VERSION_ERROR  (NPERR_BASE + 8)
+#define NPERR_INVALID_PARAM               (NPERR_BASE + 9)
+#define NPERR_INVALID_URL                 (NPERR_BASE + 10)
+#define NPERR_FILE_NOT_FOUND              (NPERR_BASE + 11)
+#define NPERR_NO_DATA                     (NPERR_BASE + 12)
+#define NPERR_STREAM_NOT_SEEKABLE         (NPERR_BASE + 13)
+#define NPERR_TIME_RANGE_NOT_SUPPORTED    (NPERR_BASE + 14)
+#define NPERR_MALFORMED_SITE              (NPERR_BASE + 15)
+
+/*
+ * Values of type NPReason:
+ */
+#define NPRES_BASE          0
+#define NPRES_DONE         (NPRES_BASE + 0)
+#define NPRES_NETWORK_ERR  (NPRES_BASE + 1)
+#define NPRES_USER_BREAK   (NPRES_BASE + 2)
+
+/*
+ * Don't use these obsolete error codes any more.
+ */
+#define NP_NOERR  NP_NOERR_is_obsolete_use_NPERR_NO_ERROR
+#define NP_EINVAL NP_EINVAL_is_obsolete_use_NPERR_GENERIC_ERROR
+#define NP_EABORT NP_EABORT_is_obsolete_use_NPRES_USER_BREAK
+
+/*
+ * Version feature information
+ */
+#define NPVERS_HAS_STREAMOUTPUT             8
+#define NPVERS_HAS_NOTIFICATION             9
+#define NPVERS_HAS_LIVECONNECT              9
+#define NPVERS_68K_HAS_LIVECONNECT          11
+#define NPVERS_HAS_WINDOWLESS               11
+#define NPVERS_HAS_XPCONNECT_SCRIPTING      13
+#define NPVERS_HAS_NPRUNTIME_SCRIPTING      14
+#define NPVERS_HAS_FORM_VALUES              15
+#define NPVERS_HAS_POPUPS_ENABLED_STATE     16
+#define NPVERS_HAS_RESPONSE_HEADERS         17
+#define NPVERS_HAS_NPOBJECT_ENUM            18
+#define NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL 19
+#define NPVERS_HAS_ALL_NETWORK_STREAMS      20
+#define NPVERS_HAS_URL_AND_AUTH_INFO        21
+#define NPVERS_HAS_PRIVATE_MODE             22
+#define NPVERS_MACOSX_HAS_COCOA_EVENTS      23
+#define NPVERS_HAS_ADVANCED_KEY_HANDLING    25
+#define NPVERS_HAS_URL_REDIRECT_HANDLING    26
+#define NPVERS_HAS_CLEAR_SITE_DATA          27
+
+/*----------------------------------------------------------------------*/
+/*                        Function Prototypes                           */
+/*----------------------------------------------------------------------*/
+
+#if defined(__OS2__)
+#define NP_LOADDS _System
+#else
+#define NP_LOADDS
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* NPP_* functions are provided by the plugin and called by the navigator. */
+
+#if defined(XP_UNIX)
+const char* NPP_GetMIMEDescription(void);
+#endif
+
+NPError NP_LOADDS NPP_New(NPMIMEType pluginType, NPP instance,
+                          uint16_t mode, int16_t argc, char* argn[],
+                          char* argv[], NPSavedData* saved);
+NPError NP_LOADDS NPP_Destroy(NPP instance, NPSavedData** save);
+NPError NP_LOADDS NPP_SetWindow(NPP instance, NPWindow* window);
+NPError NP_LOADDS NPP_NewStream(NPP instance, NPMIMEType type,
+                                NPStream* stream, NPBool seekable,
+                                uint16_t* stype);
+NPError NP_LOADDS NPP_DestroyStream(NPP instance, NPStream* stream,
+                                    NPReason reason);
+int32_t NP_LOADDS NPP_WriteReady(NPP instance, NPStream* stream);
+int32_t NP_LOADDS NPP_Write(NPP instance, NPStream* stream, int32_t offset,
+                            int32_t len, void* buffer);
+void    NP_LOADDS NPP_StreamAsFile(NPP instance, NPStream* stream,
+                                   const char* fname);
+void    NP_LOADDS NPP_Print(NPP instance, NPPrint* platformPrint);
+int16_t NP_LOADDS NPP_HandleEvent(NPP instance, void* event);
+void    NP_LOADDS NPP_URLNotify(NPP instance, const char* url,
+                                NPReason reason, void* notifyData);
+NPError NP_LOADDS NPP_GetValue(NPP instance, NPPVariable variable, void *value);
+NPError NP_LOADDS NPP_SetValue(NPP instance, NPNVariable variable, void *value);
+NPBool  NP_LOADDS NPP_GotFocus(NPP instance, NPFocusDirection direction);
+void    NP_LOADDS NPP_LostFocus(NPP instance);
+void    NP_LOADDS NPP_URLRedirectNotify(NPP instance, const char* url, int32_t status, void* notifyData);
+NPError NP_LOADDS NPP_ClearSiteData(const char* site, uint64_t flags, uint64_t maxAge);
+char**  NP_LOADDS NPP_GetSitesWithData(void);
+void    NP_LOADDS NPP_DidComposite(NPP instance);
+
+/* NPN_* functions are provided by the navigator and called by the plugin. */
+void        NP_LOADDS NPN_Version(int* plugin_major, int* plugin_minor,
+                                  int* netscape_major, int* netscape_minor);
+NPError     NP_LOADDS NPN_GetURLNotify(NPP instance, const char* url,
+                                       const char* target, void* notifyData);
+NPError     NP_LOADDS NPN_GetURL(NPP instance, const char* url,
+                                 const char* target);
+NPError     NP_LOADDS NPN_PostURLNotify(NPP instance, const char* url,
+                                        const char* target, uint32_t len,
+                                        const char* buf, NPBool file,
+                                        void* notifyData);
+NPError     NP_LOADDS NPN_PostURL(NPP instance, const char* url,
+                                  const char* target, uint32_t len,
+                                  const char* buf, NPBool file);
+NPError     NP_LOADDS NPN_RequestRead(NPStream* stream, NPByteRange* rangeList);
+NPError     NP_LOADDS NPN_NewStream(NPP instance, NPMIMEType type,
+                                    const char* target, NPStream** stream);
+int32_t     NP_LOADDS NPN_Write(NPP instance, NPStream* stream, int32_t len,
+                                void* buffer);
+NPError     NP_LOADDS NPN_DestroyStream(NPP instance, NPStream* stream,
+                                        NPReason reason);
+void        NP_LOADDS NPN_Status(NPP instance, const char* message);
+const char* NP_LOADDS NPN_UserAgent(NPP instance);
+void*       NP_LOADDS NPN_MemAlloc(uint32_t size);
+void        NP_LOADDS NPN_MemFree(void* ptr);
+uint32_t    NP_LOADDS NPN_MemFlush(uint32_t size);
+void        NP_LOADDS NPN_ReloadPlugins(NPBool reloadPages);
+NPError     NP_LOADDS NPN_GetValue(NPP instance, NPNVariable variable,
+                                   void *value);
+NPError     NP_LOADDS NPN_SetValue(NPP instance, NPPVariable variable,
+                                   void *value);
+void        NP_LOADDS NPN_InvalidateRect(NPP instance, NPRect *invalidRect);
+void        NP_LOADDS NPN_InvalidateRegion(NPP instance,
+                                           NPRegion invalidRegion);
+void        NP_LOADDS NPN_ForceRedraw(NPP instance);
+void        NP_LOADDS NPN_PushPopupsEnabledState(NPP instance, NPBool enabled);
+void        NP_LOADDS NPN_PopPopupsEnabledState(NPP instance);
+void        NP_LOADDS NPN_PluginThreadAsyncCall(NPP instance,
+                                                void (*func) (void *),
+                                                void *userData);
+NPError     NP_LOADDS NPN_GetValueForURL(NPP instance, NPNURLVariable variable,
+                                         const char *url, char **value,
+                                         uint32_t *len);
+NPError     NP_LOADDS NPN_SetValueForURL(NPP instance, NPNURLVariable variable,
+                                         const char *url, const char *value,
+                                         uint32_t len);
+NPError     NP_LOADDS NPN_GetAuthenticationInfo(NPP instance,
+                                                const char *protocol,
+                                                const char *host, int32_t port,
+                                                const char *scheme,
+                                                const char *realm,
+                                                char **username, uint32_t *ulen,
+                                                char **password,
+                                                uint32_t *plen);
+uint32_t    NP_LOADDS NPN_ScheduleTimer(NPP instance, uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID));
+void        NP_LOADDS NPN_UnscheduleTimer(NPP instance, uint32_t timerID);
+NPError     NP_LOADDS NPN_PopUpContextMenu(NPP instance, NPMenu* menu);
+NPBool      NP_LOADDS NPN_ConvertPoint(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace);
+NPBool      NP_LOADDS NPN_HandleEvent(NPP instance, void *event, NPBool handled);
+NPBool      NP_LOADDS NPN_UnfocusInstance(NPP instance, NPFocusDirection direction);
+void        NP_LOADDS NPN_URLRedirectResponse(NPP instance, void* notifyData, NPBool allow);
+
+#ifdef __cplusplus
+}  /* end extern "C" */
+#endif
+
+#endif /* RC_INVOKED */
+#if defined(__OS2__)
+#pragma pack()
+#endif
+
+#endif /* npapi_h_ */

+ 329 - 0
direct/src/plugin_npapi/npfunctions.h

@@ -0,0 +1,329 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef npfunctions_h_
+#define npfunctions_h_
+
+#ifdef __OS2__
+#pragma pack(1)
+#define NP_LOADDS _System
+#else
+#define NP_LOADDS
+#endif
+
+#include "npapi.h"
+#include "npruntime.h"
+
+typedef NPError      (* NP_LOADDS NPP_NewProcPtr)(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* saved);
+typedef NPError      (* NP_LOADDS NPP_DestroyProcPtr)(NPP instance, NPSavedData** save);
+typedef NPError      (* NP_LOADDS NPP_SetWindowProcPtr)(NPP instance, NPWindow* window);
+typedef NPError      (* NP_LOADDS NPP_NewStreamProcPtr)(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype);
+typedef NPError      (* NP_LOADDS NPP_DestroyStreamProcPtr)(NPP instance, NPStream* stream, NPReason reason);
+typedef int32_t      (* NP_LOADDS NPP_WriteReadyProcPtr)(NPP instance, NPStream* stream);
+typedef int32_t      (* NP_LOADDS NPP_WriteProcPtr)(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer);
+typedef void         (* NP_LOADDS NPP_StreamAsFileProcPtr)(NPP instance, NPStream* stream, const char* fname);
+typedef void         (* NP_LOADDS NPP_PrintProcPtr)(NPP instance, NPPrint* platformPrint);
+typedef int16_t      (* NP_LOADDS NPP_HandleEventProcPtr)(NPP instance, void* event);
+typedef void         (* NP_LOADDS NPP_URLNotifyProcPtr)(NPP instance, const char* url, NPReason reason, void* notifyData);
+/* Any NPObjects returned to the browser via NPP_GetValue should be retained
+   by the plugin on the way out. The browser is responsible for releasing. */
+typedef NPError      (* NP_LOADDS NPP_GetValueProcPtr)(NPP instance, NPPVariable variable, void *ret_value);
+typedef NPError      (* NP_LOADDS NPP_SetValueProcPtr)(NPP instance, NPNVariable variable, void *value);
+typedef NPBool       (* NP_LOADDS NPP_GotFocusPtr)(NPP instance, NPFocusDirection direction);
+typedef void         (* NP_LOADDS NPP_LostFocusPtr)(NPP instance);
+typedef void         (* NP_LOADDS NPP_URLRedirectNotifyPtr)(NPP instance, const char* url, int32_t status, void* notifyData);
+typedef NPError      (* NP_LOADDS NPP_ClearSiteDataPtr)(const char* site, uint64_t flags, uint64_t maxAge);
+typedef char**       (* NP_LOADDS NPP_GetSitesWithDataPtr)(void);
+typedef void         (* NP_LOADDS NPP_DidCompositePtr)(NPP instance);
+
+typedef NPError      (* NP_LOADDS NPN_GetValueProcPtr)(NPP instance, NPNVariable variable, void *ret_value);
+typedef NPError      (* NP_LOADDS NPN_SetValueProcPtr)(NPP instance, NPPVariable variable, void *value);
+typedef NPError      (* NP_LOADDS NPN_GetURLNotifyProcPtr)(NPP instance, const char* url, const char* window, void* notifyData);
+typedef NPError      (* NP_LOADDS NPN_PostURLNotifyProcPtr)(NPP instance, const char* url, const char* window, uint32_t len, const char* buf, NPBool file, void* notifyData);
+typedef NPError      (* NP_LOADDS NPN_GetURLProcPtr)(NPP instance, const char* url, const char* window);
+typedef NPError      (* NP_LOADDS NPN_PostURLProcPtr)(NPP instance, const char* url, const char* window, uint32_t len, const char* buf, NPBool file);
+typedef NPError      (* NP_LOADDS NPN_RequestReadProcPtr)(NPStream* stream, NPByteRange* rangeList);
+typedef NPError      (* NP_LOADDS NPN_NewStreamProcPtr)(NPP instance, NPMIMEType type, const char* window, NPStream** stream);
+typedef int32_t      (* NP_LOADDS NPN_WriteProcPtr)(NPP instance, NPStream* stream, int32_t len, void* buffer);
+typedef NPError      (* NP_LOADDS NPN_DestroyStreamProcPtr)(NPP instance, NPStream* stream, NPReason reason);
+typedef void         (* NP_LOADDS NPN_StatusProcPtr)(NPP instance, const char* message);
+/* Browser manages the lifetime of the buffer returned by NPN_UserAgent, don't
+   depend on it sticking around and don't free it. */
+typedef const char*  (* NP_LOADDS NPN_UserAgentProcPtr)(NPP instance);
+typedef void*        (* NP_LOADDS NPN_MemAllocProcPtr)(uint32_t size);
+typedef void         (* NP_LOADDS NPN_MemFreeProcPtr)(void* ptr);
+typedef uint32_t     (* NP_LOADDS NPN_MemFlushProcPtr)(uint32_t size);
+typedef void         (* NP_LOADDS NPN_ReloadPluginsProcPtr)(NPBool reloadPages);
+typedef void*        (* NP_LOADDS NPN_GetJavaEnvProcPtr)(void);
+typedef void*        (* NP_LOADDS NPN_GetJavaPeerProcPtr)(NPP instance);
+typedef void         (* NP_LOADDS NPN_InvalidateRectProcPtr)(NPP instance, NPRect *rect);
+typedef void         (* NP_LOADDS NPN_InvalidateRegionProcPtr)(NPP instance, NPRegion region);
+typedef void         (* NP_LOADDS NPN_ForceRedrawProcPtr)(NPP instance);
+typedef NPIdentifier (* NP_LOADDS NPN_GetStringIdentifierProcPtr)(const NPUTF8* name);
+typedef void         (* NP_LOADDS NPN_GetStringIdentifiersProcPtr)(const NPUTF8** names, int32_t nameCount, NPIdentifier* identifiers);
+typedef NPIdentifier (* NP_LOADDS NPN_GetIntIdentifierProcPtr)(int32_t intid);
+typedef bool         (* NP_LOADDS NPN_IdentifierIsStringProcPtr)(NPIdentifier identifier);
+typedef NPUTF8*      (* NP_LOADDS NPN_UTF8FromIdentifierProcPtr)(NPIdentifier identifier);
+typedef int32_t      (* NP_LOADDS NPN_IntFromIdentifierProcPtr)(NPIdentifier identifier);
+typedef NPObject*    (* NP_LOADDS NPN_CreateObjectProcPtr)(NPP npp, NPClass *aClass);
+typedef NPObject*    (* NP_LOADDS NPN_RetainObjectProcPtr)(NPObject *obj);
+typedef void         (* NP_LOADDS NPN_ReleaseObjectProcPtr)(NPObject *obj);
+typedef bool         (* NP_LOADDS NPN_InvokeProcPtr)(NPP npp, NPObject* obj, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result);
+typedef bool         (* NP_LOADDS NPN_InvokeDefaultProcPtr)(NPP npp, NPObject* obj, const NPVariant *args, uint32_t argCount, NPVariant *result);
+typedef bool         (* NP_LOADDS NPN_EvaluateProcPtr)(NPP npp, NPObject *obj, NPString *script, NPVariant *result);
+typedef bool         (* NP_LOADDS NPN_GetPropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName, NPVariant *result);
+typedef bool         (* NP_LOADDS NPN_SetPropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName, const NPVariant *value);
+typedef bool         (* NP_LOADDS NPN_RemovePropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName);
+typedef bool         (* NP_LOADDS NPN_HasPropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName);
+typedef bool         (* NP_LOADDS NPN_HasMethodProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName);
+typedef void         (* NP_LOADDS NPN_ReleaseVariantValueProcPtr)(NPVariant *variant);
+typedef void         (* NP_LOADDS NPN_SetExceptionProcPtr)(NPObject *obj, const NPUTF8 *message);
+typedef void         (* NP_LOADDS NPN_PushPopupsEnabledStateProcPtr)(NPP npp, NPBool enabled);
+typedef void         (* NP_LOADDS NPN_PopPopupsEnabledStateProcPtr)(NPP npp);
+typedef bool         (* NP_LOADDS NPN_EnumerateProcPtr)(NPP npp, NPObject *obj, NPIdentifier **identifier, uint32_t *count);
+typedef void         (* NP_LOADDS NPN_PluginThreadAsyncCallProcPtr)(NPP instance, void (*func)(void *), void *userData);
+typedef bool         (* NP_LOADDS NPN_ConstructProcPtr)(NPP npp, NPObject* obj, const NPVariant *args, uint32_t argCount, NPVariant *result);
+typedef NPError      (* NP_LOADDS NPN_GetValueForURLPtr)(NPP npp, NPNURLVariable variable, const char *url, char **value, uint32_t *len);
+typedef NPError      (* NP_LOADDS NPN_SetValueForURLPtr)(NPP npp, NPNURLVariable variable, const char *url, const char *value, uint32_t len);
+typedef NPError      (* NP_LOADDS NPN_GetAuthenticationInfoPtr)(NPP npp, const char *protocol, const char *host, int32_t port, const char *scheme, const char *realm, char **username, uint32_t *ulen, char **password, uint32_t *plen);
+typedef uint32_t     (* NP_LOADDS NPN_ScheduleTimerPtr)(NPP instance, uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID));
+typedef void         (* NP_LOADDS NPN_UnscheduleTimerPtr)(NPP instance, uint32_t timerID);
+typedef NPError      (* NP_LOADDS NPN_PopUpContextMenuPtr)(NPP instance, NPMenu* menu);
+typedef NPBool       (* NP_LOADDS NPN_ConvertPointPtr)(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace);
+typedef NPBool       (* NP_LOADDS NPN_HandleEventPtr)(NPP instance, void *event, NPBool handled);
+typedef NPBool       (* NP_LOADDS NPN_UnfocusInstancePtr)(NPP instance, NPFocusDirection direction);
+typedef void         (* NP_LOADDS NPN_URLRedirectResponsePtr)(NPP instance, void* notifyData, NPBool allow);
+
+typedef void         (* NP_LOADDS NPN_DummyPtr)(void);
+
+typedef struct _NPPluginFuncs {
+  uint16_t size;
+  uint16_t version;
+  NPP_NewProcPtr newp;
+  NPP_DestroyProcPtr destroy;
+  NPP_SetWindowProcPtr setwindow;
+  NPP_NewStreamProcPtr newstream;
+  NPP_DestroyStreamProcPtr destroystream;
+  NPP_StreamAsFileProcPtr asfile;
+  NPP_WriteReadyProcPtr writeready;
+  NPP_WriteProcPtr write;
+  NPP_PrintProcPtr print;
+  NPP_HandleEventProcPtr event;
+  NPP_URLNotifyProcPtr urlnotify;
+  void* javaClass;
+  NPP_GetValueProcPtr getvalue;
+  NPP_SetValueProcPtr setvalue;
+  NPP_GotFocusPtr gotfocus;
+  NPP_LostFocusPtr lostfocus;
+  NPP_URLRedirectNotifyPtr urlredirectnotify;
+  NPP_ClearSiteDataPtr clearsitedata;
+  NPP_GetSitesWithDataPtr getsiteswithdata;
+  NPP_DidCompositePtr didComposite;
+} NPPluginFuncs;
+
+typedef struct _NPNetscapeFuncs {
+  uint16_t size;
+  uint16_t version;
+  NPN_GetURLProcPtr geturl;
+  NPN_PostURLProcPtr posturl;
+  NPN_RequestReadProcPtr requestread;
+  NPN_NewStreamProcPtr newstream;
+  NPN_WriteProcPtr write;
+  NPN_DestroyStreamProcPtr destroystream;
+  NPN_StatusProcPtr status;
+  NPN_UserAgentProcPtr uagent;
+  NPN_MemAllocProcPtr memalloc;
+  NPN_MemFreeProcPtr memfree;
+  NPN_MemFlushProcPtr memflush;
+  NPN_ReloadPluginsProcPtr reloadplugins;
+  NPN_GetJavaEnvProcPtr getJavaEnv;
+  NPN_GetJavaPeerProcPtr getJavaPeer;
+  NPN_GetURLNotifyProcPtr geturlnotify;
+  NPN_PostURLNotifyProcPtr posturlnotify;
+  NPN_GetValueProcPtr getvalue;
+  NPN_SetValueProcPtr setvalue;
+  NPN_InvalidateRectProcPtr invalidaterect;
+  NPN_InvalidateRegionProcPtr invalidateregion;
+  NPN_ForceRedrawProcPtr forceredraw;
+  NPN_GetStringIdentifierProcPtr getstringidentifier;
+  NPN_GetStringIdentifiersProcPtr getstringidentifiers;
+  NPN_GetIntIdentifierProcPtr getintidentifier;
+  NPN_IdentifierIsStringProcPtr identifierisstring;
+  NPN_UTF8FromIdentifierProcPtr utf8fromidentifier;
+  NPN_IntFromIdentifierProcPtr intfromidentifier;
+  NPN_CreateObjectProcPtr createobject;
+  NPN_RetainObjectProcPtr retainobject;
+  NPN_ReleaseObjectProcPtr releaseobject;
+  NPN_InvokeProcPtr invoke;
+  NPN_InvokeDefaultProcPtr invokeDefault;
+  NPN_EvaluateProcPtr evaluate;
+  NPN_GetPropertyProcPtr getproperty;
+  NPN_SetPropertyProcPtr setproperty;
+  NPN_RemovePropertyProcPtr removeproperty;
+  NPN_HasPropertyProcPtr hasproperty;
+  NPN_HasMethodProcPtr hasmethod;
+  NPN_ReleaseVariantValueProcPtr releasevariantvalue;
+  NPN_SetExceptionProcPtr setexception;
+  NPN_PushPopupsEnabledStateProcPtr pushpopupsenabledstate;
+  NPN_PopPopupsEnabledStateProcPtr poppopupsenabledstate;
+  NPN_EnumerateProcPtr enumerate;
+  NPN_PluginThreadAsyncCallProcPtr pluginthreadasynccall;
+  NPN_ConstructProcPtr construct;
+  NPN_GetValueForURLPtr getvalueforurl;
+  NPN_SetValueForURLPtr setvalueforurl;
+  NPN_GetAuthenticationInfoPtr getauthenticationinfo;
+  NPN_ScheduleTimerPtr scheduletimer;
+  NPN_UnscheduleTimerPtr unscheduletimer;
+  NPN_PopUpContextMenuPtr popupcontextmenu;
+  NPN_ConvertPointPtr convertpoint;
+  NPN_HandleEventPtr handleevent;
+  NPN_UnfocusInstancePtr unfocusinstance;
+  NPN_URLRedirectResponsePtr urlredirectresponse;
+  NPN_DummyPtr initasyncsurfaceOBSOLETE;
+  NPN_DummyPtr finalizeasyncsurfaceOBSOLETE;
+  NPN_DummyPtr setcurrentasyncsurfaceOBSOLETE;
+} NPNetscapeFuncs;
+
+#ifdef XP_MACOSX
+/*
+ * Mac OS X version(s) of NP_GetMIMEDescription(const char *)
+ * These can be called to retreive MIME information from the plugin dynamically
+ *
+ * Note: For compatibility with Quicktime, BPSupportedMIMEtypes is another way
+ *       to get mime info from the plugin only on OSX and may not be supported
+ *       in furture version -- use NP_GetMIMEDescription instead
+ */
+enum
+{
+ kBPSupportedMIMETypesStructVers_1    = 1
+};
+typedef struct _BPSupportedMIMETypes
+{
+ SInt32    structVersion;      /* struct version */
+ Handle    typeStrings;        /* STR# formated handle, allocated by plug-in */
+ Handle    infoStrings;        /* STR# formated handle, allocated by plug-in */
+} BPSupportedMIMETypes;
+OSErr BP_GetSupportedMIMETypes(BPSupportedMIMETypes *mimeInfo, UInt32 flags);
+#define NP_GETMIMEDESCRIPTION_NAME "NP_GetMIMEDescription"
+typedef const char* (*NP_GetMIMEDescriptionProcPtr)(void);
+typedef OSErr (*BP_GetSupportedMIMETypesProcPtr)(BPSupportedMIMETypes*, UInt32);
+#endif
+
+#if defined(_WIN32)
+#define OSCALL WINAPI
+#else
+#if defined(__OS2__)
+#define OSCALL _System
+#else
+#define OSCALL
+#endif
+#endif
+
+#if defined(XP_UNIX)
+/* GCC 3.3 and later support the visibility attribute. */
+#if defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))
+#define NP_VISIBILITY_DEFAULT __attribute__((visibility("default")))
+#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+#define NP_VISIBILITY_DEFAULT __global
+#else
+#define NP_VISIBILITY_DEFAULT
+#endif
+#define NP_EXPORT(__type) NP_VISIBILITY_DEFAULT __type
+#endif
+
+#if defined(_WIN32) || defined (__OS2__)
+#ifdef __cplusplus
+extern "C" {
+#endif
+/* plugin meta member functions */
+#if defined(__OS2__)
+typedef struct _NPPluginData {   /* Alternate OS2 Plugin interface */
+  char *pMimeTypes;
+  char *pFileExtents;
+  char *pFileOpenTemplate;
+  char *pProductName;
+  char *pProductDescription;
+  unsigned long dwProductVersionMS;
+  unsigned long dwProductVersionLS;
+} NPPluginData;
+typedef NPError     (OSCALL *NP_GetPluginDataFunc)(NPPluginData*);
+NPError OSCALL      NP_GetPluginData(NPPluginData * pPluginData);
+#endif
+typedef NPError     (OSCALL *NP_GetEntryPointsFunc)(NPPluginFuncs*);
+NPError OSCALL      NP_GetEntryPoints(NPPluginFuncs* pFuncs);
+typedef NPError     (OSCALL *NP_InitializeFunc)(NPNetscapeFuncs*);
+NPError OSCALL      NP_Initialize(NPNetscapeFuncs* bFuncs);
+typedef NPError     (OSCALL *NP_ShutdownFunc)(void);
+NPError OSCALL      NP_Shutdown(void);
+typedef const char* (*NP_GetMIMEDescriptionFunc)(void);
+const char*         NP_GetMIMEDescription(void);
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+#if defined(__OS2__)
+#pragma pack()
+#endif
+
+#ifdef XP_UNIX
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef char*          (*NP_GetPluginVersionFunc)(void);
+NP_EXPORT(char*)       NP_GetPluginVersion(void);
+typedef const char*    (*NP_GetMIMEDescriptionFunc)(void);
+NP_EXPORT(const char*) NP_GetMIMEDescription(void);
+#ifdef XP_MACOSX
+typedef NPError        (*NP_InitializeFunc)(NPNetscapeFuncs*);
+NP_EXPORT(NPError)     NP_Initialize(NPNetscapeFuncs* bFuncs);
+typedef NPError        (*NP_GetEntryPointsFunc)(NPPluginFuncs*);
+NP_EXPORT(NPError)     NP_GetEntryPoints(NPPluginFuncs* pFuncs);
+#else
+typedef NPError        (*NP_InitializeFunc)(NPNetscapeFuncs*, NPPluginFuncs*);
+NP_EXPORT(NPError)     NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs);
+#endif
+typedef NPError        (*NP_ShutdownFunc)(void);
+NP_EXPORT(NPError)     NP_Shutdown(void);
+typedef NPError        (*NP_GetValueFunc)(void *, NPPVariable, void *);
+NP_EXPORT(NPError)     NP_GetValue(void *future, NPPVariable aVariable, void *aValue);
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+#endif /* npfunctions_h_ */

+ 393 - 0
direct/src/plugin_npapi/npruntime.h

@@ -0,0 +1,393 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright (c) 2004, Apple Computer, Inc. and The Mozilla Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of Apple Computer, Inc. ("Apple") or The Mozilla
+ * Foundation ("Mozilla") nor the names of their contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE, MOZILLA AND THEIR CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE, MOZILLA OR
+ * THEIR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef _NP_RUNTIME_H_
+#define _NP_RUNTIME_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "nptypes.h"
+
+/*
+    This API is used to facilitate binding code written in C to script
+    objects.  The API in this header does not assume the presence of a
+    user agent.  That is, it can be used to bind C code to scripting
+    environments outside of the context of a user agent.
+
+    However, the normal use of the this API is in the context of a
+    scripting environment running in a browser or other user agent.
+    In particular it is used to support the extended Netscape
+    script-ability API for plugins (NP-SAP).  NP-SAP is an extension
+    of the Netscape plugin API.  As such we have adopted the use of
+    the "NP" prefix for this API.
+
+    The following NP{N|P}Variables were added to the Netscape plugin
+    API (in npapi.h):
+
+    NPNVWindowNPObject
+    NPNVPluginElementNPObject
+    NPPVpluginScriptableNPObject
+
+    These variables are exposed through NPN_GetValue() and
+    NPP_GetValue() (respectively) and are used to establish the
+    initial binding between the user agent and native code.  The DOM
+    objects in the user agent can be examined and manipulated using
+    the NPN_ functions that operate on NPObjects described in this
+    header.
+
+    To the extent possible the assumptions about the scripting
+    language used by the scripting environment have been minimized.
+*/
+
+#define NP_BEGIN_MACRO  do {
+#define NP_END_MACRO    } while (0)
+
+/*
+    Objects (non-primitive data) passed between 'C' and script is
+    always wrapped in an NPObject.  The 'interface' of an NPObject is
+    described by an NPClass.
+*/
+typedef struct NPObject NPObject;
+typedef struct NPClass NPClass;
+
+typedef char NPUTF8;
+typedef struct _NPString {
+    const NPUTF8 *UTF8Characters;
+    uint32_t UTF8Length;
+} NPString;
+
+typedef enum {
+    NPVariantType_Void,
+    NPVariantType_Null,
+    NPVariantType_Bool,
+    NPVariantType_Int32,
+    NPVariantType_Double,
+    NPVariantType_String,
+    NPVariantType_Object
+} NPVariantType;
+
+typedef struct _NPVariant {
+    NPVariantType type;
+    union {
+        bool boolValue;
+        int32_t intValue;
+        double doubleValue;
+        NPString stringValue;
+        NPObject *objectValue;
+    } value;
+} NPVariant;
+
+/*
+    NPN_ReleaseVariantValue is called on all 'out' parameters
+    references.  Specifically it is to be called on variants that own
+    their value, as is the case with all non-const NPVariant*
+    arguments after a successful call to any methods (except this one)
+    in this API.
+
+    After calling NPN_ReleaseVariantValue, the type of the variant
+    will be NPVariantType_Void.
+*/
+void NPN_ReleaseVariantValue(NPVariant *variant);
+
+#define NPVARIANT_IS_VOID(_v)    ((_v).type == NPVariantType_Void)
+#define NPVARIANT_IS_NULL(_v)    ((_v).type == NPVariantType_Null)
+#define NPVARIANT_IS_BOOLEAN(_v) ((_v).type == NPVariantType_Bool)
+#define NPVARIANT_IS_INT32(_v)   ((_v).type == NPVariantType_Int32)
+#define NPVARIANT_IS_DOUBLE(_v)  ((_v).type == NPVariantType_Double)
+#define NPVARIANT_IS_STRING(_v)  ((_v).type == NPVariantType_String)
+#define NPVARIANT_IS_OBJECT(_v)  ((_v).type == NPVariantType_Object)
+
+#define NPVARIANT_TO_BOOLEAN(_v) ((_v).value.boolValue)
+#define NPVARIANT_TO_INT32(_v)   ((_v).value.intValue)
+#define NPVARIANT_TO_DOUBLE(_v)  ((_v).value.doubleValue)
+#define NPVARIANT_TO_STRING(_v)  ((_v).value.stringValue)
+#define NPVARIANT_TO_OBJECT(_v)  ((_v).value.objectValue)
+
+#define VOID_TO_NPVARIANT(_v)                                                 \
+NP_BEGIN_MACRO                                                                \
+    (_v).type = NPVariantType_Void;                                           \
+    (_v).value.objectValue = NULL;                                            \
+NP_END_MACRO
+
+#define NULL_TO_NPVARIANT(_v)                                                 \
+NP_BEGIN_MACRO                                                                \
+    (_v).type = NPVariantType_Null;                                           \
+    (_v).value.objectValue = NULL;                                            \
+NP_END_MACRO
+
+#define BOOLEAN_TO_NPVARIANT(_val, _v)                                        \
+NP_BEGIN_MACRO                                                                \
+    (_v).type = NPVariantType_Bool;                                           \
+    (_v).value.boolValue = !!(_val);                                          \
+NP_END_MACRO
+
+#define INT32_TO_NPVARIANT(_val, _v)                                          \
+NP_BEGIN_MACRO                                                                \
+    (_v).type = NPVariantType_Int32;                                          \
+    (_v).value.intValue = _val;                                               \
+NP_END_MACRO
+
+#define DOUBLE_TO_NPVARIANT(_val, _v)                                         \
+NP_BEGIN_MACRO                                                                \
+    (_v).type = NPVariantType_Double;                                         \
+    (_v).value.doubleValue = _val;                                            \
+NP_END_MACRO
+
+#define STRINGZ_TO_NPVARIANT(_val, _v)                                        \
+NP_BEGIN_MACRO                                                                \
+    (_v).type = NPVariantType_String;                                         \
+    NPString str = { _val, (uint32_t)(strlen(_val)) };                        \
+    (_v).value.stringValue = str;                                             \
+NP_END_MACRO
+
+#define STRINGN_TO_NPVARIANT(_val, _len, _v)                                  \
+NP_BEGIN_MACRO                                                                \
+    (_v).type = NPVariantType_String;                                         \
+    NPString str = { _val, (uint32_t)(_len) };                                \
+    (_v).value.stringValue = str;                                             \
+NP_END_MACRO
+
+#define OBJECT_TO_NPVARIANT(_val, _v)                                         \
+NP_BEGIN_MACRO                                                                \
+    (_v).type = NPVariantType_Object;                                         \
+    (_v).value.objectValue = _val;                                            \
+NP_END_MACRO
+
+
+/*
+  Type mappings (JavaScript types have been used for illustration
+    purposes):
+
+  JavaScript       to             C (NPVariant with type:)
+  undefined                       NPVariantType_Void
+  null                            NPVariantType_Null
+  Boolean                         NPVariantType_Bool
+  Number                          NPVariantType_Double or NPVariantType_Int32
+  String                          NPVariantType_String
+  Object                          NPVariantType_Object
+
+  C (NPVariant with type:)   to   JavaScript
+  NPVariantType_Void              undefined
+  NPVariantType_Null              null
+  NPVariantType_Bool              Boolean
+  NPVariantType_Int32             Number
+  NPVariantType_Double            Number
+  NPVariantType_String            String
+  NPVariantType_Object            Object
+*/
+
+typedef void *NPIdentifier;
+
+/*
+    NPObjects have methods and properties.  Methods and properties are
+    identified with NPIdentifiers.  These identifiers may be reflected
+    in script.  NPIdentifiers can be either strings or integers, IOW,
+    methods and properties can be identified by either strings or
+    integers (i.e. foo["bar"] vs foo[1]). NPIdentifiers can be
+    compared using ==.  In case of any errors, the requested
+    NPIdentifier(s) will be NULL. NPIdentifier lifetime is controlled
+    by the browser. Plugins do not need to worry about memory management
+    with regards to NPIdentifiers.
+*/
+NPIdentifier NPN_GetStringIdentifier(const NPUTF8 *name);
+void NPN_GetStringIdentifiers(const NPUTF8 **names, int32_t nameCount,
+                              NPIdentifier *identifiers);
+NPIdentifier NPN_GetIntIdentifier(int32_t intid);
+bool NPN_IdentifierIsString(NPIdentifier identifier);
+
+/*
+    The NPUTF8 returned from NPN_UTF8FromIdentifier SHOULD be freed.
+*/
+NPUTF8 *NPN_UTF8FromIdentifier(NPIdentifier identifier);
+
+/*
+    Get the integer represented by identifier. If identifier is not an
+    integer identifier, the behaviour is undefined.
+*/
+int32_t NPN_IntFromIdentifier(NPIdentifier identifier);
+
+/*
+    NPObject behavior is implemented using the following set of
+    callback functions.
+
+    The NPVariant *result argument of these functions (where
+    applicable) should be released using NPN_ReleaseVariantValue().
+*/
+typedef NPObject *(*NPAllocateFunctionPtr)(NPP npp, NPClass *aClass);
+typedef void (*NPDeallocateFunctionPtr)(NPObject *npobj);
+typedef void (*NPInvalidateFunctionPtr)(NPObject *npobj);
+typedef bool (*NPHasMethodFunctionPtr)(NPObject *npobj, NPIdentifier name);
+typedef bool (*NPInvokeFunctionPtr)(NPObject *npobj, NPIdentifier name,
+                                    const NPVariant *args, uint32_t argCount,
+                                    NPVariant *result);
+typedef bool (*NPInvokeDefaultFunctionPtr)(NPObject *npobj,
+                                           const NPVariant *args,
+                                           uint32_t argCount,
+                                           NPVariant *result);
+typedef bool (*NPHasPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name);
+typedef bool (*NPGetPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name,
+                                         NPVariant *result);
+typedef bool (*NPSetPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name,
+                                         const NPVariant *value);
+typedef bool (*NPRemovePropertyFunctionPtr)(NPObject *npobj,
+                                            NPIdentifier name);
+typedef bool (*NPEnumerationFunctionPtr)(NPObject *npobj, NPIdentifier **value,
+                                         uint32_t *count);
+typedef bool (*NPConstructFunctionPtr)(NPObject *npobj,
+                                       const NPVariant *args,
+                                       uint32_t argCount,
+                                       NPVariant *result);
+
+/*
+    NPObjects returned by create, retain, invoke, and getProperty pass
+    a reference count to the caller.  That is, the callee adds a
+    reference count which passes to the caller.  It is the caller's
+    responsibility to release the returned object.
+
+    NPInvokeFunctionPtr function may return 0 to indicate a void
+    result.
+
+    NPInvalidateFunctionPtr is called by the scripting environment
+    when the native code is shutdown.  Any attempt to message a
+    NPObject instance after the invalidate callback has been
+    called will result in undefined behavior, even if the native code
+    is still retaining those NPObject instances.  (The runtime
+    will typically return immediately, with 0 or NULL, from an attempt
+    to dispatch to a NPObject, but this behavior should not be
+    depended upon.)
+
+    The NPEnumerationFunctionPtr function may pass an array of
+    NPIdentifiers back to the caller. The callee allocs the memory of
+    the array using NPN_MemAlloc(), and it's the caller's responsibility
+    to release it using NPN_MemFree().
+*/
+struct NPClass
+{
+    uint32_t structVersion;
+    NPAllocateFunctionPtr allocate;
+    NPDeallocateFunctionPtr deallocate;
+    NPInvalidateFunctionPtr invalidate;
+    NPHasMethodFunctionPtr hasMethod;
+    NPInvokeFunctionPtr invoke;
+    NPInvokeDefaultFunctionPtr invokeDefault;
+    NPHasPropertyFunctionPtr hasProperty;
+    NPGetPropertyFunctionPtr getProperty;
+    NPSetPropertyFunctionPtr setProperty;
+    NPRemovePropertyFunctionPtr removeProperty;
+    NPEnumerationFunctionPtr enumerate;
+    NPConstructFunctionPtr construct;
+};
+
+#define NP_CLASS_STRUCT_VERSION      3
+
+#define NP_CLASS_STRUCT_VERSION_ENUM 2
+#define NP_CLASS_STRUCT_VERSION_CTOR 3
+
+#define NP_CLASS_STRUCT_VERSION_HAS_ENUM(npclass)   \
+        ((npclass)->structVersion >= NP_CLASS_STRUCT_VERSION_ENUM)
+
+#define NP_CLASS_STRUCT_VERSION_HAS_CTOR(npclass)   \
+        ((npclass)->structVersion >= NP_CLASS_STRUCT_VERSION_CTOR)
+
+struct NPObject {
+    NPClass *_class;
+    uint32_t referenceCount;
+    /*
+     * Additional space may be allocated here by types of NPObjects
+     */
+};
+
+/*
+    If the class has an allocate function, NPN_CreateObject invokes
+    that function, otherwise a NPObject is allocated and
+    returned. This method will initialize the referenceCount member of
+    the NPObject to 1.
+*/
+NPObject *NPN_CreateObject(NPP npp, NPClass *aClass);
+
+/*
+    Increment the NPObject's reference count.
+*/
+NPObject *NPN_RetainObject(NPObject *npobj);
+
+/*
+    Decremented the NPObject's reference count.  If the reference
+    count goes to zero, the class's destroy function is invoke if
+    specified, otherwise the object is freed directly.
+*/
+void NPN_ReleaseObject(NPObject *npobj);
+
+/*
+    Functions to access script objects represented by NPObject.
+
+    Calls to script objects are synchronous.  If a function returns a
+    value, it will be supplied via the result NPVariant
+    argument. Successful calls will return true, false will be
+    returned in case of an error.
+
+    Calls made from plugin code to script must be made from the thread
+    on which the plugin was initialized.
+*/
+
+bool NPN_Invoke(NPP npp, NPObject *npobj, NPIdentifier methodName,
+                const NPVariant *args, uint32_t argCount, NPVariant *result);
+bool NPN_InvokeDefault(NPP npp, NPObject *npobj, const NPVariant *args,
+                       uint32_t argCount, NPVariant *result);
+bool NPN_Evaluate(NPP npp, NPObject *npobj, NPString *script,
+                  NPVariant *result);
+bool NPN_GetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName,
+                     NPVariant *result);
+bool NPN_SetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName,
+                     const NPVariant *value);
+bool NPN_RemoveProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName);
+bool NPN_HasProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName);
+bool NPN_HasMethod(NPP npp, NPObject *npobj, NPIdentifier methodName);
+bool NPN_Enumerate(NPP npp, NPObject *npobj, NPIdentifier **identifier,
+                   uint32_t *count);
+bool NPN_Construct(NPP npp, NPObject *npobj, const NPVariant *args,
+                   uint32_t argCount, NPVariant *result);
+
+/*
+    NPN_SetException may be called to trigger a script exception upon
+    return from entry points into NPObjects.  Typical usage:
+
+    NPN_SetException (npobj, message);
+*/
+void NPN_SetException(NPObject *npobj, const NPUTF8 *message);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 121 - 0
direct/src/plugin_npapi/nptypes.h

@@ -0,0 +1,121 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * mozilla.org.
+ * Portions created by the Initial Developer are Copyright (C) 2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Johnny Stenback <[email protected]> (Original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nptypes_h_
+#define nptypes_h_
+
+/*
+ * Header file for ensuring that C99 types ([u]int32_t, [u]int64_t and bool) and
+ * true/false macros are available.
+ */
+
+#if (defined(WIN32) && !defined(__GNUC__)) || defined(OS2)
+  /*
+   * Win32 and OS/2 don't know C99, so define [u]int_16/32/64 here. The bool
+   * is predefined tho, both in C and C++.
+   */
+  typedef short int16_t;
+  typedef unsigned short uint16_t;
+  typedef int int32_t;
+  typedef unsigned int uint32_t;
+  typedef long long int64_t;
+  typedef unsigned long long uint64_t;
+#elif defined(_AIX) || defined(__sun) || defined(__osf__) || defined(IRIX) || defined(HPUX)
+  /*
+   * AIX and SunOS ship a inttypes.h header that defines [u]int32_t,
+   * but not bool for C.
+   */
+  #include <inttypes.h>
+
+  #ifndef __cplusplus
+    typedef int bool;
+    #define true   1
+    #define false  0
+  #endif
+#elif defined(bsdi) || defined(FREEBSD) || defined(OPENBSD)
+  /*
+   * BSD/OS, FreeBSD, and OpenBSD ship sys/types.h that define int32_t and
+   * u_int32_t.
+   */
+  #include <sys/types.h>
+
+  /*
+   * BSD/OS ships no header that defines uint32_t, nor bool (for C)
+   */
+  #if defined(bsdi)
+  typedef u_int32_t uint32_t;
+  typedef u_int64_t uint64_t;
+
+  #if !defined(__cplusplus)
+    typedef int bool;
+    #define true   1
+    #define false  0
+  #endif
+  #else
+  /*
+   * FreeBSD and OpenBSD define uint32_t and bool.
+   */
+    #include <inttypes.h>
+    #include <stdbool.h>
+  #endif
+#elif defined(BEOS)
+  #include <inttypes.h>
+#else
+  /*
+   * For those that ship a standard C99 stdint.h header file, include
+   * it. Can't do the same for stdbool.h tho, since some systems ship
+   * with a stdbool.h file that doesn't compile!
+   */
+  #include <stdint.h>
+
+  #ifndef __cplusplus
+    #if !defined(__GNUC__) || (__GNUC__ > 2 || __GNUC_MINOR__ > 95)
+      #include <stdbool.h>
+    #else
+      /*
+       * GCC 2.91 can't deal with a typedef for bool, but a #define
+       * works.
+       */
+      #define bool int
+      #define true   1
+      #define false  0
+    #endif
+  #endif
+#endif
+
+#endif /* nptypes_h_ */

+ 2 - 2
direct/src/plugin_npapi/ppBrowserObject.cxx

@@ -230,10 +230,10 @@ call(const string &method_name, P3D_object *params[], int num_params) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 P3D_object *PPBrowserObject::
 P3D_object *PPBrowserObject::
 eval(const string &expression) const {
 eval(const string &expression) const {
-  NPString npexpr = { expression.c_str(), expression.length() };
+  NPString npexpr = { expression.c_str(), (uint32_t)expression.length() };
 
 
   NPVariant result;
   NPVariant result;
-  if (!browser->evaluate(_instance->get_npp_instance(), _npobj, 
+  if (!browser->evaluate(_instance->get_npp_instance(), _npobj,
                          &npexpr, &result)) {
                          &npexpr, &result)) {
     // Failed to eval.
     // Failed to eval.
     return NULL;
     return NULL;

+ 7 - 3
direct/src/plugin_npapi/ppInstance.cxx

@@ -1882,8 +1882,10 @@ send_window() {
     assert(!_use_xembed);
     assert(!_use_xembed);
     parent_window._window_handle_type = _window_handle_type;
     parent_window._window_handle_type = _window_handle_type;
     if (_window_handle_type == P3D_WHT_osx_port) {
     if (_window_handle_type == P3D_WHT_osx_port) {
+#if !__LP64__
       NP_Port *port = (NP_Port *)_window.window;
       NP_Port *port = (NP_Port *)_window.window;
       parent_window._handle._osx_port._port = port->port;
       parent_window._handle._osx_port._port = port->port;
+#endif
     } else if (_window_handle_type == P3D_WHT_osx_cgcontext) {
     } else if (_window_handle_type == P3D_WHT_osx_cgcontext) {
       NP_CGContext *context = (NP_CGContext *)_window.window;
       NP_CGContext *context = (NP_CGContext *)_window.window;
       if (context != NULL) {
       if (context != NULL) {
@@ -1929,8 +1931,10 @@ send_window() {
 #elif defined(__APPLE__)
 #elif defined(__APPLE__)
     parent_window._window_handle_type = _window_handle_type;
     parent_window._window_handle_type = _window_handle_type;
     if (_window_handle_type == P3D_WHT_osx_port) {
     if (_window_handle_type == P3D_WHT_osx_port) {
+#if !__LP64__
       NP_Port *port = (NP_Port *)_window.window;
       NP_Port *port = (NP_Port *)_window.window;
       parent_window._handle._osx_port._port = port->port;
       parent_window._handle._osx_port._port = port->port;
+#endif
     } else if (_window_handle_type == P3D_WHT_osx_cgcontext) {
     } else if (_window_handle_type == P3D_WHT_osx_cgcontext) {
       NP_CGContext *context = (NP_CGContext *)_window.window;
       NP_CGContext *context = (NP_CGContext *)_window.window;
       if (context != NULL) {
       if (context != NULL) {
@@ -2173,16 +2177,16 @@ set_failed() {
       NPObject *window_object = NULL;
       NPObject *window_object = NULL;
       if (browser->getvalue(_npp_instance, NPNVWindowNPObject,
       if (browser->getvalue(_npp_instance, NPNVWindowNPObject,
                             &window_object) == NPERR_NO_ERROR) {
                             &window_object) == NPERR_NO_ERROR) {
-        NPString npexpr = { expression.c_str(), expression.length() };
+        NPString npexpr = { expression.c_str(), (uint32_t)expression.length() };
         NPVariant result;
         NPVariant result;
-        if (browser->evaluate(_npp_instance, window_object, 
+        if (browser->evaluate(_npp_instance, window_object,
                               &npexpr, &result)) {
                               &npexpr, &result)) {
           nout << "Eval " << expression << "\n";
           nout << "Eval " << expression << "\n";
           browser->releasevariantvalue(&result);
           browser->releasevariantvalue(&result);
         } else {
         } else {
           nout << "Unable to eval " << expression << "\n";
           nout << "Unable to eval " << expression << "\n";
         }
         }
-        
+
         browser->releaseobject(window_object);
         browser->releaseobject(window_object);
       }
       }
     }
     }

+ 1 - 1
direct/src/plugin_npapi/startup.cxx

@@ -187,7 +187,7 @@ NP_Initialize(NPNetscapeFuncs *browserFuncs,
   }
   }
 #endif
 #endif
 
 
-  int browser_major = (browser->version >> 8) && 0xff;
+  int browser_major = (browser->version >> 8) & 0xff;
   int browser_minor = browser->version & 0xff;
   int browser_minor = browser->version & 0xff;
   nout << "Browser NPAPI version " << browser_major << "." << browser_minor << "\n";
   nout << "Browser NPAPI version " << browser_major << "." << browser_minor << "\n";
 
 

+ 1 - 2
direct/src/plugin_standalone/Sources.pp

@@ -83,7 +83,6 @@
 #end bin_target
 #end bin_target
 
 
 #begin bin_target
 #begin bin_target
-  #define BUILD_TARGET $[and $[HAVE_JPEG],$[HAVE_PNG]]
   #define USE_PACKAGES openssl zlib
   #define USE_PACKAGES openssl zlib
   #define TARGET p3dembed
   #define TARGET p3dembed
   #define LOCAL_LIBS plugin_common p3d_plugin_static
   #define LOCAL_LIBS plugin_common p3d_plugin_static
@@ -115,7 +114,7 @@
   // On Windows, we also need to build p3dembedw.exe, the non-console
   // On Windows, we also need to build p3dembedw.exe, the non-console
   // version of p3dembed.exe.
   // version of p3dembed.exe.
 
 
-  #define BUILD_TARGET $[and $[HAVE_JPEG],$[HAVE_PNG],$[WINDOWS_PLATFORM]]
+  #define BUILD_TARGET $[WINDOWS_PLATFORM]
   #define USE_PACKAGES openssl zlib
   #define USE_PACKAGES openssl zlib
   #define TARGET p3dembedw
   #define TARGET p3dembedw
   #define LOCAL_LIBS plugin_common p3d_plugin_static
   #define LOCAL_LIBS plugin_common p3d_plugin_static

+ 3 - 3
direct/src/plugin_standalone/panda3dBase.cxx

@@ -147,7 +147,7 @@ run_main_loop() {
     }
     }
   }
   }
 
 
-#elif defined(__APPLE__)
+#elif defined(__APPLE__) && !__LP64__
   // OSX really prefers to own the main loop, so we install a timer to
   // OSX really prefers to own the main loop, so we install a timer to
   // call out to our instances and getters, rather than polling within
   // call out to our instances and getters, rather than polling within
   // the event loop as we do in the Windows case, above.
   // the event loop as we do in the Windows case, above.
@@ -699,7 +699,7 @@ report_download_complete(P3D_instance *instance) {
   }
   }
 }
 }
 
 
-#ifdef __APPLE__
+#if defined(__APPLE__) && !__LP64__
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Panda3DBase::st_timer_callback
 //     Function: Panda3DBase::st_timer_callback
 //       Access: Protected, Static
 //       Access: Protected, Static
@@ -712,7 +712,7 @@ st_timer_callback(EventLoopTimerRef timer, void *user_data) {
 }
 }
 #endif  // __APPLE__
 #endif  // __APPLE__
 
 
-#ifdef __APPLE__
+#if defined(__APPLE__) && !__LP64__
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Panda3DBase::timer_callback
 //     Function: Panda3DBase::timer_callback
 //       Access: Protected
 //       Access: Protected

+ 1 - 1
direct/src/plugin_standalone/panda3dMac.cxx

@@ -63,7 +63,7 @@ open_p3d_file(FSRef *ref) {
 
 
 static pascal OSErr
 static pascal OSErr
 open_documents_handler(const AppleEvent *theAppleEvent, AppleEvent *reply, 
 open_documents_handler(const AppleEvent *theAppleEvent, AppleEvent *reply, 
-                       long handlerRefcon) {
+                       SRefCon handlerRefcon) {
   AEDescList docList;
   AEDescList docList;
   FSRef theFSRef;
   FSRef theFSRef;
   long index;
   long index;

+ 5 - 0
direct/src/showbase/EventManager.py

@@ -187,3 +187,8 @@ class EventManager:
 
 
     def shutdown(self):
     def shutdown(self):
         taskMgr.remove('eventManager')
         taskMgr.remove('eventManager')
+
+        # Flush the event queue.  We do this after removing the task
+        # since the task removal itself might also fire off an event.
+        if self.eventQueue is not None:
+            self.eventQueue.clear()

+ 156 - 125
direct/src/showbase/ShowBase.py

@@ -11,15 +11,15 @@ from panda3d.core import *
 from panda3d.direct import get_config_showbase, throw_new_frame, init_app_for_gui
 from panda3d.direct import get_config_showbase, throw_new_frame, init_app_for_gui
 
 
 # This needs to be available early for DirectGUI imports
 # This needs to be available early for DirectGUI imports
-import __builtin__
-__builtin__.config = get_config_showbase()
-
-from direct.directnotify.DirectNotifyGlobal import *
-from MessengerGlobal import *
-from BulletinBoardGlobal import *
-from direct.task.TaskManagerGlobal import *
-from JobManagerGlobal import *
-from EventManagerGlobal import *
+import __builtin__ as builtins
+builtins.config = get_config_showbase()
+
+from direct.directnotify.DirectNotifyGlobal import directNotify, giveNotify
+from MessengerGlobal import messenger
+from BulletinBoardGlobal import bulletinBoard
+from direct.task.TaskManagerGlobal import taskMgr
+from JobManagerGlobal import jobMgr
+from EventManagerGlobal import eventMgr
 from PythonUtil import *
 from PythonUtil import *
 from direct.showbase import PythonUtil
 from direct.showbase import PythonUtil
 #from direct.interval.IntervalManager import ivalMgr
 #from direct.interval.IntervalManager import ivalMgr
@@ -29,11 +29,11 @@ from direct.showbase.BufferViewer import BufferViewer
 from direct.task import Task
 from direct.task import Task
 from direct.directutil import Verify
 from direct.directutil import Verify
 from direct.showbase import GarbageReport
 from direct.showbase import GarbageReport
-import EventManager
 import math,sys,os
 import math,sys,os
 import Loader
 import Loader
 import time
 import time
 import gc
 import gc
+import atexit
 from direct.fsm import ClassicFSM
 from direct.fsm import ClassicFSM
 from direct.fsm import State
 from direct.fsm import State
 from direct.showbase import ExceptionVarDump
 from direct.showbase import ExceptionVarDump
@@ -44,9 +44,17 @@ if __debug__:
 import OnScreenDebug
 import OnScreenDebug
 import AppRunnerGlobal
 import AppRunnerGlobal
 
 
-__builtin__.FADE_SORT_INDEX = 1000
-__builtin__.NO_FADE_SORT_INDEX = 2000
+builtins.FADE_SORT_INDEX = 1000
+builtins.NO_FADE_SORT_INDEX = 2000
 
 
+def legacyRun():
+    builtins.base.notify.warning("run() is deprecated, use base.run() instead")
+    builtins.base.run()
+
[email protected]
+def exitfunc():
+    if getattr(builtins, 'base', None) is not None:
+        builtins.base.destroy()
 
 
 # Now ShowBase is a DirectObject.  We need this so ShowBase can hang
 # Now ShowBase is a DirectObject.  We need this so ShowBase can hang
 # hooks on messages, particularly on window-event.  This doesn't
 # hooks on messages, particularly on window-event.  This doesn't
@@ -57,7 +65,7 @@ class ShowBase(DirectObject.DirectObject):
 
 
     def __init__(self, fStartDirect = True, windowType = None):
     def __init__(self, fStartDirect = True, windowType = None):
         self.__dev__ = config.GetBool('want-dev', __debug__)
         self.__dev__ = config.GetBool('want-dev', __debug__)
-        __builtin__.__dev__ = self.__dev__
+        builtins.__dev__ = self.__dev__
 
 
         logStackDump = (config.GetBool('log-stack-dump', False) or
         logStackDump = (config.GetBool('log-stack-dump', False) or
                         config.GetBool('client-log-stack-dump', False))
                         config.GetBool('client-log-stack-dump', False))
@@ -65,11 +73,12 @@ class ShowBase(DirectObject.DirectObject):
         if logStackDump or uploadStackDump:
         if logStackDump or uploadStackDump:
             ExceptionVarDump.install(logStackDump, uploadStackDump)
             ExceptionVarDump.install(logStackDump, uploadStackDump)
 
 
-        # Locate the directory containing the main program
+        ## The directory containing the main Python file of this application.
         self.mainDir = ExecutionEnvironment.getEnvironmentVariable("MAIN_DIR")
         self.mainDir = ExecutionEnvironment.getEnvironmentVariable("MAIN_DIR")
 
 
-        # The appRunner should have been created by the time ShowBase
-        # has been.
+        ## This contains the global appRunner instance, as imported from
+        ## AppRunnerGlobal.  This will be None if we are not running in the
+        ## runtime environment (ie. from a .p3d file).
         self.appRunner = AppRunnerGlobal.appRunner
         self.appRunner = AppRunnerGlobal.appRunner
 
 
         #debug running multiplier
         #debug running multiplier
@@ -108,13 +117,13 @@ class ShowBase(DirectObject.DirectObject):
         self.wantTk = False
         self.wantTk = False
         self.wantWx = False
         self.wantWx = False
 
 
-        # Fill this in with a function to invoke when the user "exits"
-        # the program by closing the main window.
+        ## Fill this in with a function to invoke when the user "exits"
+        ## the program by closing the main window.
         self.exitFunc = None
         self.exitFunc = None
 
 
-        # Add final-exit callbacks to this list.  These will be called
-        # when sys.exit() is called, after Panda has unloaded, and
-        # just before Python is about to shut down.
+        ## Add final-exit callbacks to this list.  These will be called
+        ## when sys.exit() is called, after Panda has unloaded, and
+        ## just before Python is about to shut down.
         self.finalExitCallbacks = []
         self.finalExitCallbacks = []
 
 
         Task.TaskManager.taskTimerVerbose = self.config.GetBool('task-timer-verbose', 0)
         Task.TaskManager.taskTimerVerbose = self.config.GetBool('task-timer-verbose', 0)
@@ -139,13 +148,15 @@ class ShowBase(DirectObject.DirectObject):
         # we get a window-event.
         # we get a window-event.
         self.__oldAspectRatio = None
         self.__oldAspectRatio = None
 
 
+        ## This is set to the value of the window-type config variable, but may
+        ## optionally be overridden in the Showbase constructor.  Should either be
+        ## 'onscreen' (the default), 'offscreen' or 'none'.
         self.windowType = windowType
         self.windowType = windowType
         if self.windowType is None:
         if self.windowType is None:
             self.windowType = self.config.GetString('window-type', 'onscreen')
             self.windowType = self.config.GetString('window-type', 'onscreen')
         self.requireWindow = self.config.GetBool('require-window', 1)
         self.requireWindow = self.config.GetBool('require-window', 1)
 
 
-        # base.win is the main, or only window; base.winList is a list of
-        # *all* windows.  Similarly with base.camList.
+        ## This is the main, or only window; see winList for a list of *all* windows.
         self.win = None
         self.win = None
         self.frameRateMeter = None
         self.frameRateMeter = None
         self.sceneGraphAnalyzerMeter = None
         self.sceneGraphAnalyzerMeter = None
@@ -165,17 +176,29 @@ class ShowBase(DirectObject.DirectObject):
         self.trackball = None
         self.trackball = None
         self.texmem = None
         self.texmem = None
         self.showVertices = None
         self.showVertices = None
+
+        ## This is a NodePath pointing to the Camera object set up for the 3D scene.
+        ## This is usually a child of self.camera.
         self.cam = None
         self.cam = None
         self.cam2d = None
         self.cam2d = None
         self.cam2dp = None
         self.cam2dp = None
+
+        ## This is the NodePath that should be used to manipulate the camera.  This
+        ## is the node to which the default camera is attached.
         self.camera = None
         self.camera = None
         self.camera2d = None
         self.camera2d = None
         self.camera2dp = None
         self.camera2dp = None
+
+        ## This is a list of all cameras created with makeCamera, including base.cam.
         self.camList = []
         self.camList = []
+        ## Convenience accessor for base.cam.node()
         self.camNode = None
         self.camNode = None
+        ## Convenience accessor for base.camNode.get_lens()
         self.camLens = None
         self.camLens = None
         self.camFrustumVis = None
         self.camFrustumVis = None
         self.direct = None
         self.direct = None
+        ## This is used to store the wx.Application object used when want-wx is
+        ## set or base.startWx() is called.
         self.wxApp = None
         self.wxApp = None
         self.tkRoot = None
         self.tkRoot = None
 
 
@@ -189,6 +212,7 @@ class ShowBase(DirectObject.DirectObject):
 
 
         self.hidden = NodePath('hidden')
         self.hidden = NodePath('hidden')
 
 
+        ## The global graphics engine, ie. GraphicsEngine.getGlobalPtr()
         self.graphicsEngine = GraphicsEngine.getGlobalPtr()
         self.graphicsEngine = GraphicsEngine.getGlobalPtr()
         self.setupRender()
         self.setupRender()
         self.setupRender2d()
         self.setupRender2d()
@@ -198,11 +222,11 @@ class ShowBase(DirectObject.DirectObject):
             self.setupRender2dp()
             self.setupRender2dp()
 
 
 
 
-        # This is a placeholder for a CollisionTraverser.  If someone
-        # stores a CollisionTraverser pointer here, we'll traverse it
-        # in the collisionLoop task.
-        self.shadowTrav = 0
+        ## This is a placeholder for a CollisionTraverser.  If someone
+        ## stores a CollisionTraverser pointer here, we'll traverse it
+        ## in the collisionLoop task.
         self.cTrav = 0
         self.cTrav = 0
+        self.shadowTrav = 0
         self.cTravStack = Stack()
         self.cTravStack = Stack()
         # Ditto for an AppTraverser.
         # Ditto for an AppTraverser.
         self.appTrav = 0
         self.appTrav = 0
@@ -233,10 +257,6 @@ class ShowBase(DirectObject.DirectObject):
             random.seed(seed)
             random.seed(seed)
             #whrandom.seed(seed & 0xff, (seed >> 8) & 0xff, (seed >> 16) & 0xff)
             #whrandom.seed(seed & 0xff, (seed >> 8) & 0xff, (seed >> 16) & 0xff)
 
 
-        # Now that we've set up the window structures, assign an exitfunc.
-        self.oldexitfunc = getattr(sys, 'exitfunc', None)
-        sys.exitfunc = self.exitfunc
-
         # Open the default rendering window.
         # Open the default rendering window.
         if self.windowType != 'none':
         if self.windowType != 'none':
             props = WindowProperties.getDefault()
             props = WindowProperties.getDefault()
@@ -254,17 +274,22 @@ class ShowBase(DirectObject.DirectObject):
         self.loader = Loader.Loader(self)
         self.loader = Loader.Loader(self)
         self.graphicsEngine.setDefaultLoader(self.loader.loader)
         self.graphicsEngine.setDefaultLoader(self.loader.loader)
 
 
+        ## The global event manager, as imported from EventManagerGlobal.
         self.eventMgr = eventMgr
         self.eventMgr = eventMgr
+        ## The global messenger, as imported from MessengerGlobal.
         self.messenger = messenger
         self.messenger = messenger
+        ## The global bulletin board, as imported from BulletinBoardGlobal.
         self.bboard = bulletinBoard
         self.bboard = bulletinBoard
+        ## The global task manager, as imported from TaskManagerGlobal.
         self.taskMgr = taskMgr
         self.taskMgr = taskMgr
+        ## The global job manager, as imported from JobManagerGlobal.
         self.jobMgr = jobMgr
         self.jobMgr = jobMgr
 
 
-        # Particle manager
+        ## Particle manager
         self.particleMgr = None
         self.particleMgr = None
         self.particleMgrEnabled = 0
         self.particleMgrEnabled = 0
 
 
-        # Physics manager
+        ## Physics manager
         self.physicsMgr = None
         self.physicsMgr = None
         self.physicsMgrEnabled = 0
         self.physicsMgrEnabled = 0
         self.physicsMgrAngular = 0
         self.physicsMgrAngular = 0
@@ -302,8 +327,8 @@ class ShowBase(DirectObject.DirectObject):
             # assigned to a single CPU
             # assigned to a single CPU
             autoAffinity = self.config.GetBool('auto-single-cpu-affinity', 0)
             autoAffinity = self.config.GetBool('auto-single-cpu-affinity', 0)
             affinity = None
             affinity = None
-            if autoAffinity and ('clientIndex' in __builtin__.__dict__):
-                affinity = abs(int(__builtin__.clientIndex))
+            if autoAffinity and ('clientIndex' in builtins.__dict__):
+                affinity = abs(int(builtins.clientIndex))
             else:
             else:
                 affinity = self.config.GetInt('client-cpu-affinity', -1)
                 affinity = self.config.GetInt('client-cpu-affinity', -1)
             if (affinity in (None, -1)) and autoAffinity:
             if (affinity in (None, -1)) and autoAffinity:
@@ -313,42 +338,44 @@ class ShowBase(DirectObject.DirectObject):
                 TrueClock.getGlobalPtr().setCpuAffinity(1 << (affinity % 32))
                 TrueClock.getGlobalPtr().setCpuAffinity(1 << (affinity % 32))
 
 
         # Make sure we're not making more than one ShowBase.
         # Make sure we're not making more than one ShowBase.
-        if 'base' in __builtin__.__dict__:
+        if 'base' in builtins.__dict__:
             raise StandardError, "Attempt to spawn multiple ShowBase instances!"
             raise StandardError, "Attempt to spawn multiple ShowBase instances!"
 
 
-        __builtin__.base = self
-        __builtin__.render2d = self.render2d
-        __builtin__.aspect2d = self.aspect2d
-        __builtin__.pixel2d = self.pixel2d
-        __builtin__.render = self.render
-        __builtin__.hidden = self.hidden
-        __builtin__.camera = self.camera
-        __builtin__.loader = self.loader
-        __builtin__.taskMgr = self.taskMgr
-        __builtin__.jobMgr = self.jobMgr
-        __builtin__.eventMgr = self.eventMgr
-        __builtin__.messenger = self.messenger
-        __builtin__.bboard = self.bboard
+        # DO NOT ADD TO THIS LIST.  We're trying to phase out the use of
+        # built-in variables by ShowBase.  Use a Global module if necessary.
+        builtins.base = self
+        builtins.render2d = self.render2d
+        builtins.aspect2d = self.aspect2d
+        builtins.pixel2d = self.pixel2d
+        builtins.render = self.render
+        builtins.hidden = self.hidden
+        builtins.camera = self.camera
+        builtins.loader = self.loader
+        builtins.taskMgr = self.taskMgr
+        builtins.jobMgr = self.jobMgr
+        builtins.eventMgr = self.eventMgr
+        builtins.messenger = self.messenger
+        builtins.bboard = self.bboard
         # Config needs to be defined before ShowBase is constructed
         # Config needs to be defined before ShowBase is constructed
-        #__builtin__.config = self.config
-        __builtin__.run = self.run
-        __builtin__.ostream = Notify.out()
-        __builtin__.directNotify = directNotify
-        __builtin__.giveNotify = giveNotify
-        __builtin__.globalClock = globalClock
-        __builtin__.vfs = vfs
-        __builtin__.cpMgr = ConfigPageManager.getGlobalPtr()
-        __builtin__.cvMgr = ConfigVariableManager.getGlobalPtr()
-        __builtin__.pandaSystem = PandaSystem.getGlobalPtr()
-        __builtin__.wantUberdog = base.config.GetBool('want-uberdog', 1)
+        #builtins.config = self.config
+        builtins.run = legacyRun
+        builtins.ostream = Notify.out()
+        builtins.directNotify = directNotify
+        builtins.giveNotify = giveNotify
+        builtins.globalClock = globalClock
+        builtins.vfs = vfs
+        builtins.cpMgr = ConfigPageManager.getGlobalPtr()
+        builtins.cvMgr = ConfigVariableManager.getGlobalPtr()
+        builtins.pandaSystem = PandaSystem.getGlobalPtr()
+        builtins.wantUberdog = base.config.GetBool('want-uberdog', 1)
         if __debug__:
         if __debug__:
-            __builtin__.deltaProfiler = DeltaProfiler.DeltaProfiler("ShowBase")
-        __builtin__.onScreenDebug = OnScreenDebug.OnScreenDebug()
+            builtins.deltaProfiler = DeltaProfiler.DeltaProfiler("ShowBase")
+        builtins.onScreenDebug = OnScreenDebug.OnScreenDebug()
 
 
         if self.wantRender2dp:
         if self.wantRender2dp:
-            __builtin__.render2dp = self.render2dp
-            __builtin__.aspect2dp = self.aspect2dp
-            __builtin__.pixel2dp = self.pixel2dp
+            builtins.render2dp = self.render2dp
+            builtins.aspect2dp = self.aspect2dp
+            builtins.pixel2dp = self.pixel2dp
 
 
         if __dev__:
         if __dev__:
             ShowBase.notify.debug('__dev__ == %s' % __dev__)
             ShowBase.notify.debug('__dev__ == %s' % __dev__)
@@ -426,7 +453,7 @@ class ShowBase(DirectObject.DirectObject):
         self.cTrav = self.cTravStack.pop()
         self.cTrav = self.cTravStack.pop()
 
 
     def __setupProfile(self):
     def __setupProfile(self):
-        """ Sets up the Python profiler, if avaialable, according to
+        """ Sets up the Python profiler, if available, according to
         some Panda config settings. """
         some Panda config settings. """
 
 
         try:
         try:
@@ -445,8 +472,7 @@ class ShowBase(DirectObject.DirectObject):
         return 0
         return 0
 
 
     def printEnvDebugInfo(self):
     def printEnvDebugInfo(self):
-        """
-        Print some information about the environment that we are running
+        """Print some information about the environment that we are running
         in.  Stuff like the model paths and other paths.  Feel free to
         in.  Stuff like the model paths and other paths.  Feel free to
         add stuff to this.
         add stuff to this.
         """
         """
@@ -470,11 +496,18 @@ class ShowBase(DirectObject.DirectObject):
         for cb in self.finalExitCallbacks[:]:
         for cb in self.finalExitCallbacks[:]:
             cb()
             cb()
 
 
+        # Remove the built-in base reference
+        if getattr(builtins, 'base', None) is self:
+            del builtins.base
+            del builtins.loader
+            del builtins.taskMgr
+
         # [gjeon] restore sticky key settings
         # [gjeon] restore sticky key settings
         if self.config.GetBool('disable-sticky-keys', 0):
         if self.config.GetBool('disable-sticky-keys', 0):
             allowAccessibilityShortcutKeys(True)
             allowAccessibilityShortcutKeys(True)
 
 
-        taskMgr.destroy()
+        self.ignoreAll()
+        self.shutdown()
 
 
         if getattr(self, 'musicManager', None):
         if getattr(self, 'musicManager', None):
             self.musicManager.shutdown()
             self.musicManager.shutdown()
@@ -501,19 +534,6 @@ class ShowBase(DirectObject.DirectObject):
         vfs = VirtualFileSystem.getGlobalPtr()
         vfs = VirtualFileSystem.getGlobalPtr()
         vfs.unmountAll()
         vfs.unmountAll()
 
 
-
-    def exitfunc(self):
-        """
-        This should be assigned to sys.exitfunc to be called just
-        before Python shutdown.  It guarantees that the Panda window
-        is closed cleanly, so that we free system resources, restore
-        the desktop and keyboard functionality, etc.
-        """
-        self.destroy()
-
-        if self.oldexitfunc:
-            self.oldexitfunc()
-
     def makeDefaultPipe(self, printPipeTypes = True):
     def makeDefaultPipe(self, printPipeTypes = True):
         """
         """
         Creates the default GraphicsPipe, which will be used to make
         Creates the default GraphicsPipe, which will be used to make
@@ -1022,6 +1042,7 @@ class ShowBase(DirectObject.DirectObject):
         Creates the render scene graph, the primary scene graph for
         Creates the render scene graph, the primary scene graph for
         rendering 3-d geometry.
         rendering 3-d geometry.
         """
         """
+        ## This is the root of the 3-D scene graph.
         self.render = NodePath('render')
         self.render = NodePath('render')
         self.render.setAttrib(RescaleNormalAttrib.makeDefault())
         self.render.setAttrib(RescaleNormalAttrib.makeDefault())
 
 
@@ -1037,6 +1058,7 @@ class ShowBase(DirectObject.DirectObject):
         2-d objects and gui elements that are superimposed over the
         2-d objects and gui elements that are superimposed over the
         3-d geometry in the window.
         3-d geometry in the window.
         """
         """
+        ## This is the root of the 2-D scene graph.
         self.render2d = NodePath('render2d')
         self.render2d = NodePath('render2d')
 
 
         # Set up some overrides to turn off certain properties which
         # Set up some overrides to turn off certain properties which
@@ -1057,22 +1079,26 @@ class ShowBase(DirectObject.DirectObject):
         self.render2d.setMaterialOff(1)
         self.render2d.setMaterialOff(1)
         self.render2d.setTwoSided(1)
         self.render2d.setTwoSided(1)
 
 
-        # The normal 2-d DisplayRegion has an aspect ratio that
-        # matches the window, but its coordinate system is square.
-        # This means anything we parent to render2d gets stretched.
-        # For things where that makes a difference, we set up
-        # aspect2d, which scales things back to the right aspect
-        # ratio.
-        aspectRatio = self.getAspectRatio()
+        ## The normal 2-d DisplayRegion has an aspect ratio that
+        ## matches the window, but its coordinate system is square.
+        ## This means anything we parent to render2d gets stretched.
+        ## For things where that makes a difference, we set up
+        ## aspect2d, which scales things back to the right aspect
+        ## ratio along the X axis (Z is still from -1 to 1)
         self.aspect2d = self.render2d.attachNewNode(PGTop("aspect2d"))
         self.aspect2d = self.render2d.attachNewNode(PGTop("aspect2d"))
+
+        aspectRatio = self.getAspectRatio()
         self.aspect2d.setScale(1.0 / aspectRatio, 1.0, 1.0)
         self.aspect2d.setScale(1.0 / aspectRatio, 1.0, 1.0)
 
 
         self.a2dBackground = self.aspect2d.attachNewNode("a2dBackground")
         self.a2dBackground = self.aspect2d.attachNewNode("a2dBackground")
 
 
-        # It's important to know the bounds of the aspect2d screen.
+        ## The Z position of the top border of the aspect2d screen.
         self.a2dTop = 1.0
         self.a2dTop = 1.0
+        ## The Z position of the bottom border of the aspect2d screen.
         self.a2dBottom = -1.0
         self.a2dBottom = -1.0
+        ## The X position of the left border of the aspect2d screen.
         self.a2dLeft = -aspectRatio
         self.a2dLeft = -aspectRatio
+        ## The X position of the right border of the aspect2d screen.
         self.a2dRight = aspectRatio
         self.a2dRight = aspectRatio
 
 
         self.a2dTopCenter = self.aspect2d.attachNewNode("a2dTopCenter")
         self.a2dTopCenter = self.aspect2d.attachNewNode("a2dTopCenter")
@@ -1112,12 +1138,12 @@ class ShowBase(DirectObject.DirectObject):
         self.a2dBottomRight.setPos(self.a2dRight, 0, self.a2dBottom)
         self.a2dBottomRight.setPos(self.a2dRight, 0, self.a2dBottom)
         self.a2dBottomRightNs.setPos(self.a2dRight, 0, self.a2dBottom)
         self.a2dBottomRightNs.setPos(self.a2dRight, 0, self.a2dBottom)
 
 
-        # This special root, pixel2d, uses units in pixels that are relative
-        # to the window. The upperleft corner of the window is (0, 0),
-        # the lowerleft corner is (xsize, -ysize), in this coordinate system.
-        xsize, ysize = self.getSize()
+        ## This special root, pixel2d, uses units in pixels that are relative
+        ## to the window. The upperleft corner of the window is (0, 0),
+        ## the lowerleft corner is (xsize, -ysize), in this coordinate system.
         self.pixel2d = self.render2d.attachNewNode(PGTop("pixel2d"))
         self.pixel2d = self.render2d.attachNewNode(PGTop("pixel2d"))
         self.pixel2d.setPos(-1, 0, 1)
         self.pixel2d.setPos(-1, 0, 1)
+        xsize, ysize = self.getSize()
         if xsize > 0 and ysize > 0:
         if xsize > 0 and ysize > 0:
             self.pixel2d.setScale(2.0 / xsize, 1.0, 2.0 / ysize)
             self.pixel2d.setScale(2.0 / xsize, 1.0, 2.0 / ysize)
 
 
@@ -1144,25 +1170,27 @@ class ShowBase(DirectObject.DirectObject):
         self.render2dp.setMaterialOff(1)
         self.render2dp.setMaterialOff(1)
         self.render2dp.setTwoSided(1)
         self.render2dp.setTwoSided(1)
 
 
-        # The normal 2-d DisplayRegion has an aspect ratio that
-        # matches the window, but its coordinate system is square.
-        # This means anything we parent to render2d gets stretched.
-        # For things where that makes a difference, we set up
-        # aspect2d, which scales things back to the right aspect
-        # ratio.
-
-        aspectRatio = self.getAspectRatio()
+        ## The normal 2-d DisplayRegion has an aspect ratio that
+        ## matches the window, but its coordinate system is square.
+        ## This means anything we parent to render2dp gets stretched.
+        ## For things where that makes a difference, we set up
+        ## aspect2dp, which scales things back to the right aspect
+        ## ratio along the X axis (Z is still from -1 to 1)
         self.aspect2dp = self.render2dp.attachNewNode(PGTop("aspect2dp"))
         self.aspect2dp = self.render2dp.attachNewNode(PGTop("aspect2dp"))
         self.aspect2dp.node().setStartSort(16384)
         self.aspect2dp.node().setStartSort(16384)
+
+        aspectRatio = self.getAspectRatio()
         self.aspect2dp.setScale(1.0 / aspectRatio, 1.0, 1.0)
         self.aspect2dp.setScale(1.0 / aspectRatio, 1.0, 1.0)
 
 
-        # It's important to know the bounds of the aspect2d screen.
+        ## The Z position of the top border of the aspect2dp screen.
         self.a2dpTop = 1.0
         self.a2dpTop = 1.0
+        ## The Z position of the bottom border of the aspect2dp screen.
         self.a2dpBottom = -1.0
         self.a2dpBottom = -1.0
+        ## The X position of the left border of the aspect2dp screen.
         self.a2dpLeft = -aspectRatio
         self.a2dpLeft = -aspectRatio
+        ## The X position of the right border of the aspect2dp screen.
         self.a2dpRight = aspectRatio
         self.a2dpRight = aspectRatio
 
 
-
         self.a2dpTopCenter = self.aspect2dp.attachNewNode("a2dpTopCenter")
         self.a2dpTopCenter = self.aspect2dp.attachNewNode("a2dpTopCenter")
         self.a2dpBottomCenter = self.aspect2dp.attachNewNode("a2dpBottomCenter")
         self.a2dpBottomCenter = self.aspect2dp.attachNewNode("a2dpBottomCenter")
         self.a2dpLeftCenter = self.aspect2dp.attachNewNode("a2dpLeftCenter")
         self.a2dpLeftCenter = self.aspect2dp.attachNewNode("a2dpLeftCenter")
@@ -1184,13 +1212,13 @@ class ShowBase(DirectObject.DirectObject):
         self.a2dpBottomLeft.setPos(self.a2dpLeft, 0, self.a2dpBottom)
         self.a2dpBottomLeft.setPos(self.a2dpLeft, 0, self.a2dpBottom)
         self.a2dpBottomRight.setPos(self.a2dpRight, 0, self.a2dpBottom)
         self.a2dpBottomRight.setPos(self.a2dpRight, 0, self.a2dpBottom)
 
 
-        # This special root, pixel2d, uses units in pixels that are relative
-        # to the window. The upperleft corner of the window is (0, 0),
-        # the lowerleft corner is (xsize, -ysize), in this coordinate system.
-        xsize, ysize = self.getSize()
+        ## This special root, pixel2d, uses units in pixels that are relative
+        ## to the window. The upperleft corner of the window is (0, 0),
+        ## the lowerleft corner is (xsize, -ysize), in this coordinate system.
         self.pixel2dp = self.render2dp.attachNewNode(PGTop("pixel2dp"))
         self.pixel2dp = self.render2dp.attachNewNode(PGTop("pixel2dp"))
         self.pixel2dp.node().setStartSort(16384)
         self.pixel2dp.node().setStartSort(16384)
         self.pixel2dp.setPos(-1, 0, 1)
         self.pixel2dp.setPos(-1, 0, 1)
+        xsize, ysize = self.getSize()
         if xsize > 0 and ysize > 0:
         if xsize > 0 and ysize > 0:
             self.pixel2dp.setScale(2.0 / xsize, 1.0, 2.0 / ysize)
             self.pixel2dp.setScale(2.0 / xsize, 1.0, 2.0 / ysize)
 
 
@@ -1280,7 +1308,7 @@ class ShowBase(DirectObject.DirectObject):
             # camera.
             # camera.
             self.camera = self.render.attachNewNode(ModelNode('camera'))
             self.camera = self.render.attachNewNode(ModelNode('camera'))
             self.camera.node().setPreserveTransform(ModelNode.PTLocal)
             self.camera.node().setPreserveTransform(ModelNode.PTLocal)
-            __builtin__.camera = self.camera
+            builtins.camera = self.camera
 
 
             self.mouse2cam.node().setNode(self.camera.node())
             self.mouse2cam.node().setNode(self.camera.node())
 
 
@@ -1502,12 +1530,14 @@ class ShowBase(DirectObject.DirectObject):
             np = mw.getParent().attachNewNode(mouseRecorder)
             np = mw.getParent().attachNewNode(mouseRecorder)
             mw.reparentTo(np)
             mw.reparentTo(np)
 
 
-        # A special ButtonThrower to generate keyboard events and
-        # include the time from the OS.  This is separate only to
-        # support legacy code that did not expect a time parameter; it
-        # will eventually be folded into the normal ButtonThrower,
-        # above.
+
         mw = self.buttonThrowers[0].getParent()
         mw = self.buttonThrowers[0].getParent()
+
+        ## A special ButtonThrower to generate keyboard events and
+        ## include the time from the OS.  This is separate only to
+        ## support legacy code that did not expect a time parameter; it
+        ## will eventually be folded into the normal ButtonThrower,
+        ## above.
         self.timeButtonThrower = mw.attachNewNode(ButtonThrower('timeButtons'))
         self.timeButtonThrower = mw.attachNewNode(ButtonThrower('timeButtons'))
         self.timeButtonThrower.node().setPrefix('time-')
         self.timeButtonThrower.node().setPrefix('time-')
         self.timeButtonThrower.node().setTimeFlag(1)
         self.timeButtonThrower.node().setTimeFlag(1)
@@ -1931,7 +1961,7 @@ class ShowBase(DirectObject.DirectObject):
         throw_new_frame()
         throw_new_frame()
         return Task.cont
         return Task.cont
 
 
-    def restart(self,clusterSync=False,cluster=None):
+    def restart(self, clusterSync=False, cluster=None):
         self.shutdown()
         self.shutdown()
         # __resetPrevTransform goes at the very beginning of the frame.
         # __resetPrevTransform goes at the very beginning of the frame.
         self.taskMgr.add(
         self.taskMgr.add(
@@ -1970,7 +2000,7 @@ class ShowBase(DirectObject.DirectObject):
         self.taskMgr.remove('dataLoop')
         self.taskMgr.remove('dataLoop')
         self.taskMgr.remove('resetPrevTransform')
         self.taskMgr.remove('resetPrevTransform')
         self.taskMgr.remove('ivalLoop')
         self.taskMgr.remove('ivalLoop')
-        self.taskMgr.remove('garbage_collect')
+        self.taskMgr.remove('garbageCollectStates')
         self.eventMgr.shutdown()
         self.eventMgr.shutdown()
 
 
     def getBackgroundColor(self, win = None):
     def getBackgroundColor(self, win = None):
@@ -2784,7 +2814,7 @@ class ShowBase(DirectObject.DirectObject):
             # wx is now the main loop, not us any more.
             # wx is now the main loop, not us any more.
             self.run = self.wxRun
             self.run = self.wxRun
             self.taskMgr.run = self.wxRun
             self.taskMgr.run = self.wxRun
-            __builtin__.run = self.wxRun
+            builtins.run = self.wxRun
             if self.appRunner:
             if self.appRunner:
                 self.appRunner.run = self.wxRun
                 self.appRunner.run = self.wxRun
 
 
@@ -2846,7 +2876,7 @@ class ShowBase(DirectObject.DirectObject):
 
 
         # Create a new Tk root.
         # Create a new Tk root.
         self.tkRoot = Pmw.initialise()
         self.tkRoot = Pmw.initialise()
-        __builtin__.tkroot = self.tkRoot
+        builtins.tkroot = self.tkRoot
 
 
         init_app_for_gui()
         init_app_for_gui()
 
 
@@ -2863,7 +2893,7 @@ class ShowBase(DirectObject.DirectObject):
             # wx is now the main loop, not us any more.
             # wx is now the main loop, not us any more.
             self.run = self.tkRun
             self.run = self.tkRun
             self.taskMgr.run = self.tkRun
             self.taskMgr.run = self.tkRun
-            __builtin__.run = self.tkRun
+            builtins.run = self.tkRun
             if self.appRunner:
             if self.appRunner:
                 self.appRunner.run = self.tkRun
                 self.appRunner.run = self.tkRun
 
 
@@ -2908,7 +2938,7 @@ class ShowBase(DirectObject.DirectObject):
             from direct.directtools import DirectSession
             from direct.directtools import DirectSession
             base.direct.enable()
             base.direct.enable()
         else:
         else:
-            __builtin__.direct = self.direct = None
+            builtins.direct = self.direct = None
 
 
     def getRepository(self):
     def getRepository(self):
         return None
         return None
@@ -2931,11 +2961,12 @@ class ShowBase(DirectObject.DirectObject):
         self.startDirect(fWantDirect = fDirect, fWantTk = fTk, fWantWx = fWx)
         self.startDirect(fWantDirect = fDirect, fWantTk = fTk, fWantWx = fWx)
 
 
     def run(self):
     def run(self):
-        # This method runs the TaskManager when self.appRunner is
-        # None, which is to say, when we are not running from within a
-        # p3d file.  When we *are* within a p3d file, the Panda
-        # runtime has to be responsible for running the main loop, so
-        # we can't allow the application to do it.
+        """ This method runs the TaskManager when self.appRunner is
+        None, which is to say, when we are not running from within a
+        p3d file.  When we *are* within a p3d file, the Panda
+        runtime has to be responsible for running the main loop, so
+        we can't allow the application to do it. """
+
         if self.appRunner is None or self.appRunner.dummy or \
         if self.appRunner is None or self.appRunner.dummy or \
            (self.appRunner.interactiveConsole and not self.appRunner.initialAppImport):
            (self.appRunner.interactiveConsole and not self.appRunner.initialAppImport):
             self.taskMgr.run()
             self.taskMgr.run()

+ 1 - 1
direct/src/showbase/VFSImporter.py

@@ -408,7 +408,7 @@ class VFSSharedImporter:
             path = sys.path
             path = sys.path
 
 
         for dir in path:
         for dir in path:
-            pdir = Filename.fromOsSpecific(dir).cStr()
+            pdir = str(Filename.fromOsSpecific(dir))
             if pdir + '/' + basename == dirname:
             if pdir + '/' + basename == dirname:
                 # We found it!
                 # We found it!
                 return dir
                 return dir

+ 1 - 1
direct/src/showutil/FreezeTool.py

@@ -1174,7 +1174,7 @@ class Freezer:
                 source = open(sourceFilename.toOsSpecific(), 'r').read()
                 source = open(sourceFilename.toOsSpecific(), 'r').read()
                 if source and source[-1] != '\n':
                 if source and source[-1] != '\n':
                     source = source + '\n'
                     source = source + '\n'
-                code = compile(source, sourceFilename.cStr(), 'exec')
+                code = compile(source, str(sourceFilename), 'exec')
 
 
         self.__addPyc(multifile, filename, code, compressionLevel)
         self.__addPyc(multifile, filename, code, compressionLevel)
 
 

+ 104 - 45
doc/INSTALL-MK

@@ -20,33 +20,35 @@ the next section.
 Alternately, it is possible to download the source in pieces. There
 Alternately, it is possible to download the source in pieces. There
 are three pieces:
 are three pieces:
 
 
-    1. Source code from Sourceforge.
+    1. Source code from Github.
     2. Third-party tools (not strictly necessary for Unix)
     2. Third-party tools (not strictly necessary for Unix)
-    3. Sample programs.
 
 
-You will need all three to use makepanda.  You can download all three
-pieces from the panda website.  Look for the files labeled "Panda3D
-source, piecewise, X of 3".  You can also obtain the first piece
-directly from the sourceforge CVS server:
-
-    CVSROOT=:pserver:[email protected]:/cvsroot/panda3d
-
-Make sure you have all three pieces.  If you do, then your panda
+You will need both to use makepanda.  You can find the
+pieces on the panda website.  Look for the files labeled "Panda3D
+source".  You can also obtain the first piece
+directly from the github:
+
+Over https:
+   https://github.com/panda3d/panda3d.git
+Over SSH:
+   [email protected]:panda3d/panda3d.git
+   
+Make sure you have both pieces.  If you do, then your panda
 directory will contain the following subdirectories:
 directory will contain the following subdirectories:
 
 
-    direct	- piece 1, source code from sourceforge
-    dmodels	- piece 1, source code from sourceforge
-    doc         - piece 1, source code from sourceforge
-    dtool	- piece 1, source code from sourceforge
-    Makefile	- piece 1, source code from sourceforge
-    makepanda	- piece 1, source code from sourceforge
-    models	- piece 1, source code from sourceforge
-    panda	- piece 1, source code from sourceforge
-    pandatool	- piece 1, source code from sourceforge
-    ppremake	- piece 1, source code from sourceforge
-    contrib     - piece 1, source code from sourceforge
+    direct	- piece 1, source code from github
+    dmodels	- piece 1, source code from github
+    doc         - piece 1, source code from github
+    dtool	- piece 1, source code from github
+    makepanda	- piece 1, source code from github
+    models	- piece 1, source code from github
+    panda	- piece 1, source code from github
+    pandatool	- piece 1, source code from github
+    ppremake	- piece 1, source code from github
+    contrib     - piece 1, source code from github
+    samples	- piece 1, sample programs
     thirdparty  - piece 2, third party tools
     thirdparty  - piece 2, third party tools
-    samples	- piece 3, sample programs
+
 
 
 If you have all of these, you're ready to go.  If not, then you
 If you have all of these, you're ready to go.  If not, then you
 must have missed a piece.
 must have missed a piece.
@@ -119,14 +121,49 @@ it will show you the available command-line options:
 
 
   --help            (print the help message you're reading now)
   --help            (print the help message you're reading now)
   --verbose         (print out more information)
   --verbose         (print out more information)
+  --runtime         (build a runtime build instead of an SDK build)
   --installer       (build an installer)
   --installer       (build an installer)
   --optimize X      (optimization level can be 1,2,3,4)
   --optimize X      (optimization level can be 1,2,3,4)
-  --version         (set the panda version number)
-  --lzma            (use lzma compression when building installer)
+  --version X       (set the panda version number)
+  --lzma            (use lzma compression when building Windows installer)
+  --distributor X   (short string identifying the distributor of the build)
+  --outputdir X     (use the specified directory instead of 'built')
+  --host URL        (set the host url (runtime build only))
   --threads N       (use the multithreaded build system. see manual)
   --threads N       (use the multithreaded build system. see manual)
   --osxtarget N     (the OSX version number to build for (OSX only))
   --osxtarget N     (the OSX version number to build for (OSX only))
+  --universal       (build universal binaries (OSX only))
   --override "O=V"  (override dtool_config/prc option value)
   --override "O=V"  (override dtool_config/prc option value)
+  --static          (builds libraries for static linking)
+  --target X        (experimental cross-compilation (android only))
+  --arch X          (target architecture for cross-compilation)
 
 
+  --use-python      --no-python    (enable/disable use of PYTHON)
+  --use-direct      --no-direct    (enable/disable use of DIRECT)
+  --use-gl          --no-gl        (enable/disable use of GL)
+  --use-gles        --no-gles      (enable/disable use of GLES)
+  --use-gles2       --no-gles2     (enable/disable use of GLES2)
+  --use-dx9         --no-dx9       (enable/disable use of DX9)
+  --use-tinydisplay   --no-tinydisplay (enable/disable use of TINYDISPLAY)
+  --use-nvidiacg    --no-nvidiacg  (enable/disable use of NVIDIACG)
+  --use-egl         --no-egl       (enable/disable use of EGL)
+  --use-eigen       --no-eigen     (enable/disable use of EIGEN)
+  --use-openal      --no-openal    (enable/disable use of OPENAL)
+  --use-fmodex      --no-fmodex    (enable/disable use of FMODEX)
+  --use-vorbis      --no-vorbis    (enable/disable use of VORBIS)
+  --use-ffmpeg      --no-ffmpeg    (enable/disable use of FFMPEG)
+  --use-swscale     --no-swscale   (enable/disable use of SWSCALE)
+  --use-swresample   --no-swresample (enable/disable use of SWRESAMPLE)
+  --use-ode         --no-ode       (enable/disable use of ODE)
+  --use-physx       --no-physx     (enable/disable use of PHYSX)
+  --use-bullet      --no-bullet    (enable/disable use of BULLET)
+  --use-pandaphysics   --no-pandaphysics (enable/disable use of PANDAPHYSICS)
+  --use-speedtree   --no-speedtree (enable/disable use of SPEEDTREE)
+  --use-zlib        --no-zlib      (enable/disable use of ZLIB)
+  --use-png         --no-png       (enable/disable use of PNG)
+  --use-jpeg        --no-jpeg      (enable/disable use of JPEG)
+  --use-tiff        --no-tiff      (enable/disable use of TIFF)
+  --use-squish      --no-squish    (enable/disable use of SQUISH)
+  --use-freetype    --no-freetype  (enable/disable use of FREETYPE)
   --use-maya6       --no-maya6     (enable/disable use of MAYA6)
   --use-maya6       --no-maya6     (enable/disable use of MAYA6)
   --use-maya65      --no-maya65    (enable/disable use of MAYA65)
   --use-maya65      --no-maya65    (enable/disable use of MAYA65)
   --use-maya7       --no-maya7     (enable/disable use of MAYA7)
   --use-maya7       --no-maya7     (enable/disable use of MAYA7)
@@ -135,41 +172,63 @@ it will show you the available command-line options:
   --use-maya2008    --no-maya2008  (enable/disable use of MAYA2008)
   --use-maya2008    --no-maya2008  (enable/disable use of MAYA2008)
   --use-maya2009    --no-maya2009  (enable/disable use of MAYA2009)
   --use-maya2009    --no-maya2009  (enable/disable use of MAYA2009)
   --use-maya2010    --no-maya2010  (enable/disable use of MAYA2010)
   --use-maya2010    --no-maya2010  (enable/disable use of MAYA2010)
+  --use-maya2011    --no-maya2011  (enable/disable use of MAYA2011)
+  --use-maya2012    --no-maya2012  (enable/disable use of MAYA2012)
+  --use-maya2013    --no-maya2013  (enable/disable use of MAYA2013)
+  --use-maya20135   --no-maya20135 (enable/disable use of MAYA20135)
+  --use-maya2014    --no-maya2014  (enable/disable use of MAYA2014)
+  --use-maya2015    --no-maya2015  (enable/disable use of MAYA2015)
   --use-max6        --no-max6      (enable/disable use of MAX6)
   --use-max6        --no-max6      (enable/disable use of MAX6)
   --use-max7        --no-max7      (enable/disable use of MAX7)
   --use-max7        --no-max7      (enable/disable use of MAX7)
   --use-max8        --no-max8      (enable/disable use of MAX8)
   --use-max8        --no-max8      (enable/disable use of MAX8)
   --use-max9        --no-max9      (enable/disable use of MAX9)
   --use-max9        --no-max9      (enable/disable use of MAX9)
   --use-max2009     --no-max2009   (enable/disable use of MAX2009)
   --use-max2009     --no-max2009   (enable/disable use of MAX2009)
   --use-max2010     --no-max2010   (enable/disable use of MAX2010)
   --use-max2010     --no-max2010   (enable/disable use of MAX2010)
-  --use-dx9         --no-dx9       (enable/disable use of DX9)
-  --use-python      --no-python    (enable/disable use of PYTHON)
-  --use-zlib        --no-zlib      (enable/disable use of ZLIB)
-  --use-png         --no-png       (enable/disable use of PNG)
-  --use-jpeg        --no-jpeg      (enable/disable use of JPEG)
-  --use-tiff        --no-tiff      (enable/disable use of TIFF)
+  --use-max2011     --no-max2011   (enable/disable use of MAX2011)
+  --use-max2012     --no-max2012   (enable/disable use of MAX2012)
+  --use-max2013     --no-max2013   (enable/disable use of MAX2013)
+  --use-max2014     --no-max2014   (enable/disable use of MAX2014)
+  --use-fcollada    --no-fcollada  (enable/disable use of FCOLLADA)
   --use-vrpn        --no-vrpn      (enable/disable use of VRPN)
   --use-vrpn        --no-vrpn      (enable/disable use of VRPN)
-  --use-tinyxml     --no-tinyxml   (enable/disable use of TINYXML)
-  --use-fmodex      --no-fmodex    (enable/disable use of FMODEX)
-  --use-openal      --no-openal    (enable/disable use of OPENAL)
-  --use-nvidiacg    --no-nvidiacg  (enable/disable use of NVIDIACG)
   --use-openssl     --no-openssl   (enable/disable use of OPENSSL)
   --use-openssl     --no-openssl   (enable/disable use of OPENSSL)
-  --use-freetype    --no-freetype  (enable/disable use of FREETYPE)
-  --use-wx          --no-wx        (enable/disable use of WX)
   --use-fftw        --no-fftw      (enable/disable use of FFTW)
   --use-fftw        --no-fftw      (enable/disable use of FFTW)
   --use-artoolkit   --no-artoolkit (enable/disable use of ARTOOLKIT)
   --use-artoolkit   --no-artoolkit (enable/disable use of ARTOOLKIT)
-  --use-squish      --no-squish    (enable/disable use of SQUISH)
-  --use-ode         --no-ode       (enable/disable use of ODE)
-  --use-directcam   --no-directcam (enable/disable use of DIRECTCAM)
-  --use-npapi       --no-npapi     (enable/disable use of NPAPI)
   --use-opencv      --no-opencv    (enable/disable use of OPENCV)
   --use-opencv      --no-opencv    (enable/disable use of OPENCV)
-  --use-ffmpeg      --no-ffmpeg    (enable/disable use of FFMPEG)
-  --use-swscale     --no-swscale   (enable/disable use of SWSCALE)
-  --use-fcollada    --no-fcollada  (enable/disable use of FCOLLADA)
+  --use-directcam   --no-directcam (enable/disable use of DIRECTCAM)
+  --use-vision      --no-vision    (enable/disable use of VISION)
   --use-gtk2        --no-gtk2      (enable/disable use of GTK2)
   --use-gtk2        --no-gtk2      (enable/disable use of GTK2)
+  --use-npapi       --no-npapi     (enable/disable use of NPAPI)
+  --use-mfc         --no-mfc       (enable/disable use of MFC)
+  --use-wx          --no-wx        (enable/disable use of WX)
+  --use-fltk        --no-fltk      (enable/disable use of FLTK)
+  --use-rocket      --no-rocket    (enable/disable use of ROCKET)
+  --use-awesomium   --no-awesomium (enable/disable use of AWESOMIUM)
+  --use-carbon      --no-carbon    (enable/disable use of CARBON)
+  --use-cocoa       --no-cocoa     (enable/disable use of COCOA)
+  --use-x11         --no-x11       (enable/disable use of X11)
+  --use-xf86dga     --no-xf86dga   (enable/disable use of XF86DGA)
+  --use-xrandr      --no-xrandr    (enable/disable use of XRANDR)
+  --use-xcursor     --no-xcursor   (enable/disable use of XCURSOR)
   --use-pandatool   --no-pandatool (enable/disable use of PANDATOOL)
   --use-pandatool   --no-pandatool (enable/disable use of PANDATOOL)
+  --use-pview       --no-pview     (enable/disable use of PVIEW)
+  --use-deploytools   --no-deploytools (enable/disable use of DEPLOYTOOLS)
+  --use-skel        --no-skel      (enable/disable use of SKEL)
+  --use-pandafx     --no-pandafx   (enable/disable use of PANDAFX)
+  --use-pandaparticlesystem   --no-pandaparticlesystem (enable/disable use of PA
+NDAPARTICLESYSTEM)
+  --use-contrib     --no-contrib   (enable/disable use of CONTRIB)
+  --use-sse2        --no-sse2      (enable/disable use of SSE2)
+  --use-neon        --no-neon      (enable/disable use of NEON)
+  --use-touchinput   --no-touchinput (enable/disable use of TOUCHINPUT)
 
 
   --nothing         (disable every third-party lib)
   --nothing         (disable every third-party lib)
   --everything      (enable every third-party lib)
   --everything      (enable every third-party lib)
+  --directx-sdk=X   (specify version of DX9 SDK to use: jun2010, aug2009, mar200
+9, aug2006)
+  --platform-sdk=X  (specify MSPlatSdk to use: win71, win61, win60A, winserver20
+03r2)
+  --use-icl         (experimental setting to use an intel compiler instead of MS
+VC on Windows)
 
 
 Makepanda shows you all the available options, not all of which may be
 Makepanda shows you all the available options, not all of which may be
 relevant to your operating system.  For example, makepanda can build a
 relevant to your operating system.  For example, makepanda can build a
@@ -247,11 +306,11 @@ It is all too easy to accidentally invoke 'makepanda' with the wrong
 options, thereby triggering an hour-long recompilation.  To avoid this
 options, thereby triggering an hour-long recompilation.  To avoid this
 situation, we recommend that you write a short script containing the
 situation, we recommend that you write a short script containing the
 options you intend to use regularly.  For example, I regularly compile
 options you intend to use regularly.  For example, I regularly compile
-panda without helix.  I have a very short Windows BAT file called
+panda without eigen.  I have a very short Windows BAT file called
 "mkp.bat" that looks like this:
 "mkp.bat" that looks like this:
 
 
 	@echo off
 	@echo off
-	makepanda --everything --no-helix
+	makepanda --everything --no-eigen
 
 
 This helps me avoid accidentally typing makepanda with the wrong
 This helps me avoid accidentally typing makepanda with the wrong
 options.
 options.

+ 102 - 58
dtool/src/cppparser/cppBison.yxx

@@ -21,7 +21,7 @@
 #include "cppClassTemplateParameter.h"
 #include "cppClassTemplateParameter.h"
 #include "cppTemplateParameterList.h"
 #include "cppTemplateParameterList.h"
 #include "cppInstanceIdentifier.h"
 #include "cppInstanceIdentifier.h"
-#include "cppTypedef.h"
+#include "cppTypedefType.h"
 #include "cppTypeDeclaration.h"
 #include "cppTypeDeclaration.h"
 #include "cppVisibility.h"
 #include "cppVisibility.h"
 #include "cppIdentifier.h"
 #include "cppIdentifier.h"
@@ -241,7 +241,8 @@ pop_struct() {
 %token KW_BOOL
 %token KW_BOOL
 %token KW_CATCH
 %token KW_CATCH
 %token KW_CHAR
 %token KW_CHAR
-%token KW_WCHAR_T
+%token KW_CHAR16_T
+%token KW_CHAR32_T
 %token KW_CLASS
 %token KW_CLASS
 %token KW_CONST
 %token KW_CONST
 %token KW_DELETE
 %token KW_DELETE
@@ -294,6 +295,7 @@ pop_struct() {
 %token KW_VIRTUAL
 %token KW_VIRTUAL
 %token KW_VOID
 %token KW_VOID
 %token KW_VOLATILE
 %token KW_VOLATILE
+%token KW_WCHAR_T
 %token KW_WHILE
 %token KW_WHILE
 
 
 /* These special tokens are used to set the starting state of the
 /* These special tokens are used to set the starting state of the
@@ -325,8 +327,7 @@ pop_struct() {
 %type <u.type> full_type
 %type <u.type> full_type
 %type <u.struct_type> anonymous_struct
 %type <u.struct_type> anonymous_struct
 %type <u.struct_type> named_struct
 %type <u.struct_type> named_struct
-%type <u.enum_type> anonymous_enum
-%type <u.enum_type> named_enum
+%type <u.enum_type> enum
 %type <u.extension_enum> enum_keyword
 %type <u.extension_enum> enum_keyword
 %type <u.extension_enum> struct_keyword
 %type <u.extension_enum> struct_keyword
 %type <u.simple_type> simple_type
 %type <u.simple_type> simple_type
@@ -334,6 +335,7 @@ pop_struct() {
 %type <u.simple_type> simple_float_type
 %type <u.simple_type> simple_float_type
 %type <u.simple_type> simple_void_type
 %type <u.simple_type> simple_void_type
 %type <u.type> class_derivation_name
 %type <u.type> class_derivation_name
+%type <u.type> enum_element_type
 /*%type <u.type> typedefname*/
 /*%type <u.type> typedefname*/
 %type <u.identifier> name
 %type <u.identifier> name
 %type <str> string
 %type <str> string
@@ -353,7 +355,7 @@ pop_struct() {
 
 
 /* Precedence rules. */
 /* Precedence rules. */
 
 
-%left IDENTIFIER TYPENAME_IDENTIFIER TYPEDEFNAME KW_ENUM ELLIPSIS KW_OPERATOR KW_TYPENAME KW_INT KW_SHORT KW_UNSIGNED KW_SIGNED KW_LONG KW_FLOAT KW_DOUBLE KW_CHAR KW_WCHAR_T KW_BOOL
+%left IDENTIFIER TYPENAME_IDENTIFIER TYPEDEFNAME KW_ENUM ELLIPSIS KW_OPERATOR KW_TYPENAME KW_INT KW_SHORT KW_UNSIGNED KW_SIGNED KW_LONG KW_FLOAT KW_DOUBLE KW_CHAR KW_WCHAR_T KW_CHAR16_T KW_CHAR32_T KW_BOOL
 
 
 %left '{' ',' ';'
 %left '{' ',' ';'
 
 
@@ -493,17 +495,21 @@ declaration:
   CPPDeclaration *getter = $5->find_symbol(current_scope, global_scope, current_lexer);
   CPPDeclaration *getter = $5->find_symbol(current_scope, global_scope, current_lexer);
   if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) {
   if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) {
     yyerror("Reference to non-existent or invalid getter: " + $5->get_fully_scoped_name(), @1);
     yyerror("Reference to non-existent or invalid getter: " + $5->get_fully_scoped_name(), @1);
-  }
 
 
-  CPPDeclaration *setter = $7->find_symbol(current_scope, global_scope, current_lexer);
-  if (setter == (CPPDeclaration *)NULL || setter->get_subtype() != CPPDeclaration::ST_function_group) {
-    yyerror("Reference to non-existent or invalid setter: " + $7->get_fully_scoped_name(), @1);
-  }
+  } else {
+    CPPDeclaration *setter = $7->find_symbol(current_scope, global_scope, current_lexer);
+    CPPFunctionGroup *setter_func = NULL;
 
 
-  CPPMakeProperty *make_property = new CPPMakeProperty($3, getter->as_function_group(),
-                                                           setter->as_function_group(),
-                                                           current_scope, @1.file);
-  current_scope->add_declaration(make_property, global_scope, current_lexer, @1);
+    if (setter == (CPPDeclaration *)NULL || setter->get_subtype() != CPPDeclaration::ST_function_group) {
+      yyerror("Reference to non-existent or invalid setter: " + $7->get_fully_scoped_name(), @1);
+    } else {
+      setter_func = setter->as_function_group();
+    }
+
+    CPPMakeProperty *make_property = new CPPMakeProperty($3, getter->as_function_group(),
+                                                         setter_func, current_scope, @1.file);
+    current_scope->add_declaration(make_property, global_scope, current_lexer, @1);
+  }
 }
 }
          | KW_MAKE_SEQ '(' name ',' name ',' name ')' ';'
          | KW_MAKE_SEQ '(' name ',' name ',' name ')' ';'
 {
 {
@@ -717,7 +723,8 @@ typedef_declaration:
     if (inst != (CPPInstance *)NULL) {
     if (inst != (CPPInstance *)NULL) {
       inst->_storage_class |= (current_storage_class | $1);
       inst->_storage_class |= (current_storage_class | $1);
       current_scope->add_declaration(inst, global_scope, current_lexer, @2);
       current_scope->add_declaration(inst, global_scope, current_lexer, @2);
-      current_scope->add_declaration(new CPPTypedef(inst, current_scope == global_scope), global_scope, current_lexer, @2);
+      CPPTypedefType *typedef_type = new CPPTypedefType(inst->_type, inst->_ident, current_scope);
+      current_scope->add_declaration(typedef_type, global_scope, current_lexer, @2);
     }
     }
   }
   }
 }
 }
@@ -726,19 +733,15 @@ typedef_declaration:
 typedef_instance_identifiers:
 typedef_instance_identifiers:
         instance_identifier maybe_initialize_or_function_body
         instance_identifier maybe_initialize_or_function_body
 {
 {
-  CPPInstance *inst = new CPPInstance(current_type, $1,
-                                      current_storage_class,
-                                      @1.file);
-  inst->set_initializer($2);
-  current_scope->add_declaration(new CPPTypedef(inst, current_scope == global_scope), global_scope, current_lexer, @1);
+  CPPType *target_type = current_type;
+  CPPTypedefType *typedef_type = new CPPTypedefType(target_type, $1, current_scope, @1.file);
+  current_scope->add_declaration(typedef_type, global_scope, current_lexer, @1);
 }
 }
         | instance_identifier maybe_initialize ',' typedef_instance_identifiers
         | instance_identifier maybe_initialize ',' typedef_instance_identifiers
 {
 {
-  CPPInstance *inst = new CPPInstance(current_type, $1,
-                                      current_storage_class,
-                                      @1.file);
-  inst->set_initializer($2);
-  current_scope->add_declaration(new CPPTypedef(inst, current_scope == global_scope), global_scope, current_lexer, @1);
+  CPPType *target_type = current_type;
+  CPPTypedefType *typedef_type = new CPPTypedefType(target_type, $1, current_scope, @1.file);
+  current_scope->add_declaration(typedef_type, global_scope, current_lexer, @1);
 }
 }
         ;
         ;
 
 
@@ -746,20 +749,16 @@ typedef_const_instance_identifiers:
         instance_identifier maybe_initialize_or_function_body
         instance_identifier maybe_initialize_or_function_body
 {
 {
   $1->add_modifier(IIT_const);
   $1->add_modifier(IIT_const);
-  CPPInstance *inst = new CPPInstance(current_type, $1,
-                                      current_storage_class,
-                                      @1.file);
-  inst->set_initializer($2);
-  current_scope->add_declaration(new CPPTypedef(inst, current_scope == global_scope), global_scope, current_lexer, @1);
+  CPPType *target_type = current_type;
+  CPPTypedefType *typedef_type = new CPPTypedefType(target_type, $1, current_scope, @1.file);
+  current_scope->add_declaration(typedef_type, global_scope, current_lexer, @1);
 }
 }
         | instance_identifier maybe_initialize ',' typedef_const_instance_identifiers
         | instance_identifier maybe_initialize ',' typedef_const_instance_identifiers
 {
 {
   $1->add_modifier(IIT_const);
   $1->add_modifier(IIT_const);
-  CPPInstance *inst = new CPPInstance(current_type, $1,
-                                      current_storage_class,
-                                      @1.file);
-  inst->set_initializer($2);
-  current_scope->add_declaration(new CPPTypedef(inst, current_scope == global_scope), global_scope, current_lexer, @1);
+  CPPType *target_type = current_type;
+  CPPTypedefType *typedef_type = new CPPTypedefType(target_type, $1, current_scope, @1.file);
+  current_scope->add_declaration(typedef_type, global_scope, current_lexer, @1);
 }
 }
         ;
         ;
 
 
@@ -1585,11 +1584,7 @@ type:
 {
 {
   $$ = CPPType::new_type($1);
   $$ = CPPType::new_type($1);
 }
 }
-        | anonymous_enum
-{
-  $$ = CPPType::new_type($1);
-}
-        | named_enum
+        | enum
 {
 {
   $$ = CPPType::new_type($1);
   $$ = CPPType::new_type($1);
 }
 }
@@ -1609,7 +1604,7 @@ type:
     $$ = et;
     $$ = et;
   }
   }
 }
 }
-        | enum_keyword name
+        | enum_keyword name ':' enum_element_type
 {
 {
   CPPType *type = $2->find_type(current_scope, global_scope, false, current_lexer);
   CPPType *type = $2->find_type(current_scope, global_scope, false, current_lexer);
   if (type != NULL) {
   if (type != NULL) {
@@ -1649,11 +1644,7 @@ type_decl:
 {
 {
   $$ = new CPPTypeDeclaration(CPPType::new_type($1));
   $$ = new CPPTypeDeclaration(CPPType::new_type($1));
 }
 }
-        | anonymous_enum
-{
-  $$ = CPPType::new_type($1);
-}
-        | named_enum
+        | enum
 {
 {
   $$ = new CPPTypeDeclaration(CPPType::new_type($1));
   $$ = new CPPTypeDeclaration(CPPType::new_type($1));
 }
 }
@@ -1672,9 +1663,27 @@ type_decl:
     }
     }
     $$ = et;
     $$ = et;
   }
   }
+}
+        | enum_keyword name ':' enum_element_type
+{
+  CPPType *type = $2->find_type(current_scope, global_scope, false, current_lexer);
+  if (type != NULL) {
+    $$ = type;
+  } else {
+    CPPExtensionType *et =
+      CPPType::new_type(new CPPExtensionType($1, $2, current_scope, @1.file))
+      ->as_extension_type();
+    CPPScope *scope = $2->get_scope(current_scope, global_scope);
+    if (scope != NULL) {
+      scope->define_extension_type(et);
+    }
+    $$ = et;
+  }
 }
 }
         | enum_keyword name
         | enum_keyword name
 {
 {
+  yywarning(string("C++ does not permit forward declaration of untyped enum ") + $2->get_fully_scoped_name(), @1);
+
   CPPType *type = $2->find_type(current_scope, global_scope, false, current_lexer);
   CPPType *type = $2->find_type(current_scope, global_scope, false, current_lexer);
   if (type != NULL) {
   if (type != NULL) {
     $$ = type;
     $$ = type;
@@ -1858,27 +1867,41 @@ base_specification:
 }
 }
         ;
         ;
 
 
-anonymous_enum:
-        enum_keyword '{'
-{
-  current_enum = new CPPEnumType(NULL, current_scope, @1.file);
-}
-        enum_body '}'
+enum:
+        enum_decl '{' enum_body '}'
 {
 {
   $$ = current_enum;
   $$ = current_enum;
   current_enum = NULL;
   current_enum = NULL;
 }
 }
         ;
         ;
 
 
-named_enum:
-        enum_keyword name '{'
+enum_decl:
+        enum_keyword name ':' enum_element_type
+{
+  current_enum = new CPPEnumType($2, $4, current_scope, @1.file);
+}
+        | enum_keyword name
 {
 {
   current_enum = new CPPEnumType($2, current_scope, @1.file);
   current_enum = new CPPEnumType($2, current_scope, @1.file);
 }
 }
-        enum_body '}'
+        | enum_keyword ':' enum_element_type
 {
 {
-  $$ = current_enum;
-  current_enum = NULL;
+  current_enum = new CPPEnumType(NULL, $3, current_scope, @1.file);
+}
+        | enum_keyword
+{
+  current_enum = new CPPEnumType(NULL, current_scope, @1.file);
+}
+        ;
+
+enum_element_type:
+        simple_int_type
+{
+  $$ = CPPType::new_type($1);
+}
+        | TYPENAME_IDENTIFIER
+{
+  $$ = $1->find_type(current_scope, global_scope, false, current_lexer);
 }
 }
         ;
         ;
 
 
@@ -1994,6 +2017,14 @@ simple_int_type:
         | KW_WCHAR_T
         | KW_WCHAR_T
 {
 {
   $$ = new CPPSimpleType(CPPSimpleType::T_wchar_t);
   $$ = new CPPSimpleType(CPPSimpleType::T_wchar_t);
+}
+        | KW_CHAR16_T
+{
+  $$ = new CPPSimpleType(CPPSimpleType::T_char16_t);
+}
+        | KW_CHAR32_T
+{
+  $$ = new CPPSimpleType(CPPSimpleType::T_char32_t);
 }
 }
         | KW_SHORT
         | KW_SHORT
 {
 {
@@ -2132,7 +2163,8 @@ element:
         | SCOPE | PLUSPLUS | MINUSMINUS
         | SCOPE | PLUSPLUS | MINUSMINUS
         | TIMESEQUAL | DIVIDEEQUAL | MODEQUAL | PLUSEQUAL | MINUSEQUAL
         | TIMESEQUAL | DIVIDEEQUAL | MODEQUAL | PLUSEQUAL | MINUSEQUAL
         | OREQUAL | ANDEQUAL | XOREQUAL | LSHIFTEQUAL | RSHIFTEQUAL
         | OREQUAL | ANDEQUAL | XOREQUAL | LSHIFTEQUAL | RSHIFTEQUAL
-        | KW_BOOL | KW_CATCH | KW_CHAR | KW_WCHAR_T | KW_CLASS | KW_CONST
+        | KW_BOOL | KW_CATCH | KW_CHAR | KW_CHAR16_T | KW_CHAR32_T
+        | KW_WCHAR_T | KW_CLASS | KW_CONST
         | KW_DELETE | KW_DOUBLE | KW_DYNAMIC_CAST | KW_ELSE | KW_ENUM
         | KW_DELETE | KW_DOUBLE | KW_DYNAMIC_CAST | KW_ELSE | KW_ENUM
         | KW_EXTERN | KW_EXPLICIT | KW_FALSE
         | KW_EXTERN | KW_EXPLICIT | KW_FALSE
         | KW_FLOAT | KW_FRIEND | KW_FOR | KW_GOTO
         | KW_FLOAT | KW_FRIEND | KW_FOR | KW_GOTO
@@ -2369,6 +2401,18 @@ const_expr:
   CPPType *type =
   CPPType *type =
     CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_wchar_t));
     CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_wchar_t));
   $$ = new CPPExpression(CPPExpression::construct_op(type, $3));
   $$ = new CPPExpression(CPPExpression::construct_op(type, $3));
+}
+        | KW_CHAR16_T '(' optional_const_expr_comma ')'
+{
+  CPPType *type =
+    CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char16_t));
+  $$ = new CPPExpression(CPPExpression::construct_op(type, $3));
+}
+        | KW_CHAR32_T '(' optional_const_expr_comma ')'
+{
+  CPPType *type =
+    CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char32_t));
+  $$ = new CPPExpression(CPPExpression::construct_op(type, $3));
 }
 }
         | KW_BOOL '(' optional_const_expr_comma ')'
         | KW_BOOL '(' optional_const_expr_comma ')'
 {
 {

+ 25 - 4
dtool/src/cppparser/cppDeclaration.cxx

@@ -177,13 +177,13 @@ as_class_template_parameter() {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CPPDeclaration::as_typedef
+//     Function: CPPDeclaration::as_typedef_type
 //       Access: Public, Virtual
 //       Access: Public, Virtual
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-CPPTypedef *CPPDeclaration::
-as_typedef() {
-  return (CPPTypedef *)NULL;
+CPPTypedefType *CPPDeclaration::
+as_typedef_type() {
+  return (CPPTypedefType *)NULL;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -399,3 +399,24 @@ is_less(const CPPDeclaration *other) const {
   return this < other;
   return this < other;
 }
 }
 
 
+
+ostream &
+operator << (ostream &out, const CPPDeclaration::SubstDecl &subst) {
+  CPPDeclaration::SubstDecl::const_iterator it;
+  for (it = subst.begin(); it != subst.end(); ++it) {
+    out << "  ";
+    if (it->first == NULL) {
+      out << "(null)";
+    } else {
+      out << *(it->first);
+    }
+    out << " -> ";
+    if (it->second == NULL) {
+      out << "(null)";
+    } else {
+      out << *(it->second);
+    }
+    out << "\n";
+  }
+  return out;
+}

+ 6 - 3
dtool/src/cppparser/cppDeclaration.h

@@ -30,7 +30,7 @@ using namespace std;
 
 
 class CPPInstance;
 class CPPInstance;
 class CPPTemplateParameterList;
 class CPPTemplateParameterList;
-class CPPTypedef;
+class CPPTypedefType;
 class CPPTypeDeclaration;
 class CPPTypeDeclaration;
 class CPPExpression;
 class CPPExpression;
 class CPPType;
 class CPPType;
@@ -64,7 +64,6 @@ public:
   enum SubType {
   enum SubType {
     // Subtypes of CPPDeclaration
     // Subtypes of CPPDeclaration
     ST_instance,
     ST_instance,
-    ST_typedef,
     ST_type_declaration,
     ST_type_declaration,
     ST_expression,
     ST_expression,
     ST_type,
     ST_type,
@@ -87,6 +86,7 @@ public:
     ST_class_template_parameter,
     ST_class_template_parameter,
     ST_tbd,
     ST_tbd,
     ST_type_proxy,
     ST_type_proxy,
+    ST_typedef,
   };
   };
 
 
   CPPDeclaration(const CPPFile &file);
   CPPDeclaration(const CPPFile &file);
@@ -120,7 +120,7 @@ public:
 
 
   virtual CPPInstance *as_instance();
   virtual CPPInstance *as_instance();
   virtual CPPClassTemplateParameter *as_class_template_parameter();
   virtual CPPClassTemplateParameter *as_class_template_parameter();
-  virtual CPPTypedef *as_typedef();
+  virtual CPPTypedefType *as_typedef_type();
   virtual CPPTypeDeclaration *as_type_declaration();
   virtual CPPTypeDeclaration *as_type_declaration();
   virtual CPPExpression *as_expression();
   virtual CPPExpression *as_expression();
   virtual CPPType *as_type();
   virtual CPPType *as_type();
@@ -157,4 +157,7 @@ operator << (ostream &out, const CPPDeclaration &decl) {
   return out;
   return out;
 }
 }
 
 
+ostream &
+operator << (ostream &out, const CPPDeclaration::SubstDecl &decl);
+
 #endif
 #endif

+ 100 - 12
dtool/src/cppparser/cppEnumType.cxx

@@ -13,7 +13,7 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 #include "cppEnumType.h"
 #include "cppEnumType.h"
-#include "cppTypedef.h"
+#include "cppTypedefType.h"
 #include "cppExpression.h"
 #include "cppExpression.h"
 #include "cppSimpleType.h"
 #include "cppSimpleType.h"
 #include "cppConstType.h"
 #include "cppConstType.h"
@@ -24,14 +24,37 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPEnumType::Constructor
 //     Function: CPPEnumType::Constructor
 //       Access: Public
 //       Access: Public
-//  Description:
+//  Description: Creates an untyped, unscoped enum.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPPEnumType::
 CPPEnumType::
 CPPEnumType(CPPIdentifier *ident, CPPScope *current_scope,
 CPPEnumType(CPPIdentifier *ident, CPPScope *current_scope,
             const CPPFile &file) :
             const CPPFile &file) :
   CPPExtensionType(T_enum, ident, current_scope, file),
   CPPExtensionType(T_enum, ident, current_scope, file),
+  _parent_scope(current_scope),
+  _element_type(NULL),
   _last_value(NULL)
   _last_value(NULL)
 {
 {
+  if (ident != NULL) {
+    ident->_native_scope = current_scope;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPEnumType::Constructor
+//       Access: Public
+//  Description: Creates a typed but unscoped enum.
+////////////////////////////////////////////////////////////////////
+CPPEnumType::
+CPPEnumType(CPPIdentifier *ident, CPPType *element_type,
+            CPPScope *current_scope, const CPPFile &file) :
+  CPPExtensionType(T_enum, ident, current_scope, file),
+  _parent_scope(current_scope),
+  _element_type(element_type),
+  _last_value(NULL)
+{
+  if (ident != NULL) {
+    ident->_native_scope = current_scope;
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -41,12 +64,24 @@ CPPEnumType(CPPIdentifier *ident, CPPScope *current_scope,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPPInstance *CPPEnumType::
 CPPInstance *CPPEnumType::
 add_element(const string &name, CPPExpression *value) {
 add_element(const string &name, CPPExpression *value) {
-  CPPType *type =
-    CPPType::new_type(new CPPConstType(new CPPSimpleType(
-      CPPSimpleType::T_int, CPPSimpleType::F_unsigned)));
-
   CPPIdentifier *ident = new CPPIdentifier(name);
   CPPIdentifier *ident = new CPPIdentifier(name);
-  CPPInstance *inst = new CPPInstance(type, ident);
+  ident->_native_scope = _parent_scope;
+  CPPInstance *inst;
+
+  static CPPType *default_element_type = NULL;
+  if (_element_type == NULL) {
+    // This enum is untyped.  Use a suitable default, ie. 'int'.
+    if (default_element_type == NULL) {
+      default_element_type =
+        CPPType::new_type(new CPPConstType(new CPPSimpleType(CPPSimpleType::T_int, 0)));
+    }
+
+    inst = new CPPInstance(default_element_type, ident);
+  } else {
+    // This enum has an explicit type, so use that.
+    inst = new CPPInstance(CPPType::new_type(new CPPConstType(_element_type)), ident);
+  }
+
   _elements.push_back(inst);
   _elements.push_back(inst);
 
 
   if (value == (CPPExpression *)NULL) {
   if (value == (CPPExpression *)NULL) {
@@ -81,6 +116,38 @@ is_incomplete() const {
   return false;
   return false;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPEnumType::is_fully_specified
+//       Access: Public, Virtual
+//  Description: Returns true if this declaration is an actual,
+//               factual declaration, or false if some part of the
+//               declaration depends on a template parameter which has
+//               not yet been instantiated.
+////////////////////////////////////////////////////////////////////
+bool CPPEnumType::
+is_fully_specified() const {
+  if (!CPPDeclaration::is_fully_specified()) {
+    return false;
+  }
+
+  if (_ident != NULL && !_ident->is_fully_specified()) {
+    return false;
+  }
+
+  if (_element_type != NULL && !_element_type->is_fully_specified()) {
+    return false;
+  }
+
+  Elements::const_iterator ei;
+  for (ei = _elements.begin(); ei != _elements.end(); ++ei) {
+    if (!(*ei)->is_fully_specified()) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPEnumType::substitute_decl
 //     Function: CPPEnumType::substitute_decl
 //       Access: Public, Virtual
 //       Access: Public, Virtual
@@ -95,12 +162,34 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
   }
   }
 
 
   CPPEnumType *rep = new CPPEnumType(*this);
   CPPEnumType *rep = new CPPEnumType(*this);
+
   if (_ident != NULL) {
   if (_ident != NULL) {
     rep->_ident =
     rep->_ident =
       _ident->substitute_decl(subst, current_scope, global_scope);
       _ident->substitute_decl(subst, current_scope, global_scope);
   }
   }
 
 
-  if (rep->_ident == _ident) {
+  if (_element_type != NULL) {
+    rep->_element_type =
+      _element_type->substitute_decl(subst, current_scope, global_scope)
+      ->as_type();
+  }
+
+  bool any_changed = false;
+
+  for (int i = 0; i < _elements.size(); ++i) {
+    CPPInstance *elem_rep =
+      _elements[i]->substitute_decl(subst, current_scope, global_scope)
+      ->as_instance();
+
+    if (elem_rep != _elements[i]) {
+      rep->_elements[i] = elem_rep;
+      any_changed = true;
+    }
+  }
+
+  if (rep->_ident == _ident &&
+      rep->_element_type == _element_type &&
+      !any_changed) {
     delete rep;
     delete rep;
     rep = this;
     rep = this;
   }
   }
@@ -124,15 +213,14 @@ output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
     }
     }
     out << _ident->get_local_name(scope);
     out << _ident->get_local_name(scope);
 
 
-  } else if (!complete && !_typedefs.empty()) {
-    // If we have a typedef name, use it.
-    out << _typedefs.front()->get_local_name(scope);
-
   } else {
   } else {
     out << _type;
     out << _type;
     if (_ident != NULL) {
     if (_ident != NULL) {
       out << " " << _ident->get_local_name(scope);
       out << " " << _ident->get_local_name(scope);
     }
     }
+    if (_element_type != NULL) {
+      out << " : " << _element_type->get_local_name(scope);
+    }
 
 
     out << " {\n";
     out << " {\n";
     Elements::const_iterator ei;
     Elements::const_iterator ei;

+ 6 - 0
dtool/src/cppparser/cppEnumType.h

@@ -34,12 +34,15 @@ class CPPEnumType : public CPPExtensionType {
 public:
 public:
   CPPEnumType(CPPIdentifier *ident, CPPScope *current_scope,
   CPPEnumType(CPPIdentifier *ident, CPPScope *current_scope,
               const CPPFile &file);
               const CPPFile &file);
+  CPPEnumType(CPPIdentifier *ident, CPPType *element_type,
+              CPPScope *current_scope, const CPPFile &file);
 
 
   CPPInstance *add_element(const string &name,
   CPPInstance *add_element(const string &name,
                            CPPExpression *value = (CPPExpression *)NULL);
                            CPPExpression *value = (CPPExpression *)NULL);
 
 
   virtual bool is_incomplete() const;
   virtual bool is_incomplete() const;
 
 
+  virtual bool is_fully_specified() const;
   virtual CPPDeclaration *substitute_decl(SubstDecl &subst,
   virtual CPPDeclaration *substitute_decl(SubstDecl &subst,
                                           CPPScope *current_scope,
                                           CPPScope *current_scope,
                                           CPPScope *global_scope);
                                           CPPScope *global_scope);
@@ -50,6 +53,9 @@ public:
 
 
   virtual CPPEnumType *as_enum_type();
   virtual CPPEnumType *as_enum_type();
 
 
+  CPPScope *_parent_scope;
+  CPPType *_element_type;
+
   typedef vector<CPPInstance *> Elements;
   typedef vector<CPPInstance *> Elements;
   Elements _elements;
   Elements _elements;
   CPPExpression *_last_value;
   CPPExpression *_last_value;

+ 132 - 3
dtool/src/cppparser/cppExpression.cxx

@@ -147,6 +147,30 @@ as_pointer() const {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPExpression::Result::as_boolean
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+bool CPPExpression::Result::
+as_boolean() const {
+  switch (_type) {
+  case RT_integer:
+    return (_u._integer != 0);
+
+  case RT_real:
+    return (_u._real != 0.0);
+
+  case RT_pointer:
+    return (_u._pointer != NULL);
+
+  default:
+    cerr << "Invalid type\n";
+    assert(false);
+    return false;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPExpression::Result::output
 //     Function: CPPExpression::Result::output
 //       Access: Public
 //       Access: Public
@@ -226,7 +250,7 @@ CPPExpression(CPPIdentifier *ident, CPPScope *current_scope,
   CPPDeclaration(CPPFile())
   CPPDeclaration(CPPFile())
 {
 {
   CPPDeclaration *decl =
   CPPDeclaration *decl =
-    ident->find_symbol(current_scope, global_scope, error_sink);
+    ident->find_symbol(current_scope, global_scope);
 
 
   if (decl != NULL) {
   if (decl != NULL) {
     CPPInstance *inst = decl->as_instance();
     CPPInstance *inst = decl->as_instance();
@@ -245,6 +269,7 @@ CPPExpression(CPPIdentifier *ident, CPPScope *current_scope,
 
 
   _type = T_unknown_ident;
   _type = T_unknown_ident;
   _u._ident = ident;
   _u._ident = ident;
+  _u._ident->_native_scope = current_scope;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -801,6 +826,66 @@ determine_type() const {
   return NULL;  // Compiler kludge; can't get here.
   return NULL;  // Compiler kludge; can't get here.
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPExpression::is_fully_specified
+//       Access: Public, Virtual
+//  Description: Returns true if this declaration is an actual,
+//               factual declaration, or false if some part of the
+//               declaration depends on a template parameter which has
+//               not yet been instantiated.
+////////////////////////////////////////////////////////////////////
+bool CPPExpression::
+is_fully_specified() const {
+  if (!CPPDeclaration::is_fully_specified()) {
+    return false;
+  }
+
+  switch (_type) {
+  case T_integer:
+  case T_real:
+  case T_string:
+    return false;
+
+  case T_variable:
+    return _u._variable->is_fully_specified();
+
+  case T_function:
+    return _u._fgroup->is_fully_specified();
+
+  case T_unknown_ident:
+    return _u._ident->is_fully_specified();
+
+  case T_typecast:
+  case T_construct:
+  case T_new:
+    return (_u._typecast._to->is_fully_specified() &&
+            _u._typecast._op1->is_fully_specified());
+
+  case T_default_construct:
+  case T_default_new:
+  case T_sizeof:
+    return _u._typecast._to->is_fully_specified();
+
+  case T_trinary_operation:
+    if (!_u._op._op3->is_fully_specified()) {
+      return false;
+    }
+    // Fall through
+
+  case T_binary_operation:
+    if (!_u._op._op2->is_fully_specified()) {
+      return false;
+    }
+    // Fall through
+
+  case T_unary_operation:
+    return _u._op._op1->is_fully_specified();
+
+  default:
+    return true;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPExpression::substitute_decl
 //     Function: CPPExpression::substitute_decl
 //       Access: Public, Virtual
 //       Access: Public, Virtual
@@ -827,6 +912,7 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
         // Replacing the variable reference with another variable reference.
         // Replacing the variable reference with another variable reference.
         rep->_u._variable = decl->as_instance();
         rep->_u._variable = decl->as_instance();
         any_changed = true;
         any_changed = true;
+
       } else if (decl->as_expression()) {
       } else if (decl->as_expression()) {
         // Replacing the variable reference with an expression.
         // Replacing the variable reference with an expression.
         delete rep;
         delete rep;
@@ -836,6 +922,43 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
     }
     }
     break;
     break;
 
 
+  case T_unknown_ident:
+    rep->_u._ident = _u._ident->substitute_decl(subst, current_scope, global_scope);
+    any_changed = any_changed || (rep->_u._ident != _u._ident);
+
+    // See if we can define it now.
+    decl = rep->_u._ident->find_symbol(current_scope, global_scope, subst);
+    if (decl != NULL) {
+      CPPInstance *inst = decl->as_instance();
+      if (inst != NULL) {
+        rep->_type = T_variable;
+        rep->_u._variable = inst;
+        any_changed = true;
+
+        decl = inst->substitute_decl(subst, current_scope, global_scope);
+        if (decl != inst) {
+          if (decl->as_instance()) {
+            // Replacing the variable reference with another variable reference.
+            rep->_u._variable = decl->as_instance();
+
+          } else if (decl->as_expression()) {
+            // Replacing the variable reference with an expression.
+            delete rep;
+            rep = decl->as_expression();
+          }
+        }
+        break;
+      }
+      CPPFunctionGroup *fgroup = decl->as_function_group();
+      if (fgroup != NULL) {
+        rep->_type = T_function;
+        rep->_u._fgroup = fgroup;
+        any_changed = true;
+      }
+    }
+
+    break;
+
   case T_typecast:
   case T_typecast:
   case T_construct:
   case T_construct:
   case T_new:
   case T_new:
@@ -909,6 +1032,9 @@ is_tbd() const {
 
 
     return true;
     return true;
 
 
+  case T_unknown_ident:
+    return true;
+
   case T_typecast:
   case T_typecast:
   case T_construct:
   case T_construct:
   case T_new:
   case T_new:
@@ -996,8 +1122,12 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
     break;
     break;
 
 
   case T_variable:
   case T_variable:
+    // We can just refer to the variable by name, except if it's a
+    // private constant, in which case we have to compute the value,
+    // since we may have to use it in generated code.
     if (_u._variable->_type != NULL &&
     if (_u._variable->_type != NULL &&
-        _u._variable->_initializer != NULL) {
+        _u._variable->_initializer != NULL &&
+        _u._variable->_vis > V_public) {
       // A const variable.  Fetch its assigned value.
       // A const variable.  Fetch its assigned value.
       CPPConstType *const_type = _u._variable->_type->as_const_type();
       CPPConstType *const_type = _u._variable->_type->as_const_type();
       if (const_type != NULL) {
       if (const_type != NULL) {
@@ -1434,4 +1564,3 @@ is_less(const CPPDeclaration *other) const {
 
 
   return false;
   return false;
 }
 }
-

+ 2 - 0
dtool/src/cppparser/cppExpression.h

@@ -63,6 +63,7 @@ public:
     int as_integer() const;
     int as_integer() const;
     double as_real() const;
     double as_real() const;
     void *as_pointer() const;
     void *as_pointer() const;
+    bool as_boolean() const;
     void output(ostream &out) const;
     void output(ostream &out) const;
 
 
     ResultType _type;
     ResultType _type;
@@ -78,6 +79,7 @@ public:
   CPPType *determine_type() const;
   CPPType *determine_type() const;
   bool is_tbd() const;
   bool is_tbd() const;
 
 
+  virtual bool is_fully_specified() const;
   virtual CPPDeclaration *substitute_decl(SubstDecl &subst,
   virtual CPPDeclaration *substitute_decl(SubstDecl &subst,
                                           CPPScope *current_scope,
                                           CPPScope *current_scope,
                                           CPPScope *global_scope);
                                           CPPScope *global_scope);

+ 24 - 1
dtool/src/cppparser/cppExtensionType.cxx

@@ -14,7 +14,7 @@
 
 
 
 
 #include "cppExtensionType.h"
 #include "cppExtensionType.h"
-#include "cppTypedef.h"
+#include "cppTypedefType.h"
 #include "cppIdentifier.h"
 #include "cppIdentifier.h"
 #include "cppParser.h"
 #include "cppParser.h"
 #include "indent.h"
 #include "indent.h"
@@ -130,6 +130,29 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
   return rep;
   return rep;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPExtensionType::resolve_type
+//       Access: Public, Virtual
+//  Description: If this CPPType object is a forward reference or
+//               other nonspecified reference to a type that might now
+//               be known a real type, returns the real type.
+//               Otherwise returns the type itself.
+////////////////////////////////////////////////////////////////////
+CPPType *CPPExtensionType::
+resolve_type(CPPScope *current_scope, CPPScope *global_scope) {
+  if (_ident == NULL) {
+    // We can't resolve anonymous types.  But that's OK, since they
+    // can't be forward declared anyway.
+    return this;
+  }
+
+  // Maybe it has been defined by now.
+  CPPType *type = _ident->find_type(current_scope, global_scope);
+  if (type != NULL) {
+    return type;
+  }
+  return this;
+}
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPExtensionType::is_equivalent_type
 //     Function: CPPExtensionType::is_equivalent_type

+ 6 - 1
dtool/src/cppparser/cppExtensionType.h

@@ -25,7 +25,9 @@ class CPPIdentifier;
 
 
 ///////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////
 //       Class : CPPExtensionType
 //       Class : CPPExtensionType
-// Description :
+// Description : Base class of enum, class, struct, and union types.
+//               An instance of the base class (instead of one of
+//               the specializations) is used for forward references.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class CPPExtensionType : public CPPType {
 class CPPExtensionType : public CPPType {
 public:
 public:
@@ -50,6 +52,9 @@ public:
                                           CPPScope *current_scope,
                                           CPPScope *current_scope,
                                           CPPScope *global_scope);
                                           CPPScope *global_scope);
 
 
+  virtual CPPType *resolve_type(CPPScope *current_scope,
+                                CPPScope *global_scope);
+
   virtual bool is_equivalent(const CPPType &other) const;
   virtual bool is_equivalent(const CPPType &other) const;
 
 
 
 

+ 42 - 2
dtool/src/cppparser/cppIdentifier.cxx

@@ -39,7 +39,7 @@ CPPIdentifier(const string &name, const CPPFile &file) : _file(file) {
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPPIdentifier::
 CPPIdentifier::
-CPPIdentifier(const CPPNameComponent &name) {
+CPPIdentifier(const CPPNameComponent &name, const CPPFile &file) : _file(file) {
   _names.push_back(name);
   _names.push_back(name);
   _native_scope = (CPPScope *)NULL;
   _native_scope = (CPPScope *)NULL;
 }
 }
@@ -146,8 +146,10 @@ get_local_name(CPPScope *scope) const {
 
 
   if (scope == NULL || (_native_scope == NULL && _names.size() == 1)) {
   if (scope == NULL || (_native_scope == NULL && _names.size() == 1)) {
     result = _names.back().get_name_with_templ(scope);
     result = _names.back().get_name_with_templ(scope);
+
   } else if (_names.front().empty()) {
   } else if (_names.front().empty()) {
     result = get_fully_scoped_name();
     result = get_fully_scoped_name();
+
   } else {
   } else {
     // Determine the scope of everything up until but not including the
     // Determine the scope of everything up until but not including the
     // last name.
     // last name.
@@ -382,6 +384,7 @@ find_type(CPPScope *current_scope, CPPScope *global_scope,
   if (scope == NULL) {
   if (scope == NULL) {
     return NULL;
     return NULL;
   }
   }
+
   CPPType *type = scope->find_type(get_simple_name(), subst, global_scope);
   CPPType *type = scope->find_type(get_simple_name(), subst, global_scope);
   if (type != NULL && _names.back().has_templ()) {
   if (type != NULL && _names.back().has_templ()) {
     // This is a template type.
     // This is a template type.
@@ -398,7 +401,6 @@ find_type(CPPScope *current_scope, CPPScope *global_scope,
       assert(new_type != NULL);
       assert(new_type != NULL);
       if (new_type == type) {
       if (new_type == type) {
         type = CPPType::new_type(new CPPTBDType((CPPIdentifier *)this));
         type = CPPType::new_type(new CPPTBDType((CPPIdentifier *)this));
-        //      type = new_type;
       } else {
       } else {
         type = new_type;
         type = new_type;
       }
       }
@@ -424,12 +426,50 @@ find_symbol(CPPScope *current_scope, CPPScope *global_scope,
   if (scope == NULL) {
   if (scope == NULL) {
     return NULL;
     return NULL;
   }
   }
+
+  CPPDeclaration *sym;
+  if (!_names.back().has_templ()) {
+    sym = scope->find_symbol(get_simple_name());
+
+  } else {
+    sym = scope->find_template(get_simple_name());
+    if (sym != NULL) {
+      CPPType *type = sym->as_type();
+      if (type != NULL && type->is_incomplete()) {
+        // We can't instantiate an incomplete type.
+        sym = CPPType::new_type(new CPPTBDType((CPPIdentifier *)this));
+      } else {
+        // Instantiate the symbol.
+        sym = sym->instantiate(_names.back().get_templ(), current_scope,
+                               global_scope, error_sink);
+      }
+    }
+  }
+
+  return sym;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPIdentifier::find_symbol
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+CPPDeclaration *CPPIdentifier::
+find_symbol(CPPScope *current_scope, CPPScope *global_scope,
+            CPPDeclaration::SubstDecl &subst,
+            CPPPreprocessor *error_sink) const {
+  CPPScope *scope = get_scope(current_scope, global_scope, subst, error_sink);
+  if (scope == NULL) {
+    return NULL;
+  }
+
   CPPDeclaration *sym;
   CPPDeclaration *sym;
   if (!_names.back().has_templ()) {
   if (!_names.back().has_templ()) {
     sym = scope->find_symbol(get_simple_name());
     sym = scope->find_symbol(get_simple_name());
 
 
   } else {
   } else {
     sym = scope->find_template(get_simple_name());
     sym = scope->find_template(get_simple_name());
+
     if (sym != NULL) {
     if (sym != NULL) {
       CPPType *type = sym->as_type();
       CPPType *type = sym->as_type();
       if (type != NULL && type->is_incomplete()) {
       if (type != NULL && type->is_incomplete()) {

+ 5 - 1
dtool/src/cppparser/cppIdentifier.h

@@ -36,7 +36,7 @@ class CPPTemplateParameterList;
 class CPPIdentifier {
 class CPPIdentifier {
 public:
 public:
   CPPIdentifier(const string &name, const CPPFile &file = CPPFile());
   CPPIdentifier(const string &name, const CPPFile &file = CPPFile());
-  CPPIdentifier(const CPPNameComponent &name);
+  CPPIdentifier(const CPPNameComponent &name, const CPPFile &file = CPPFile());
   void add_name(const string &name);
   void add_name(const string &name);
   void add_name(const CPPNameComponent &name);
   void add_name(const CPPNameComponent &name);
 
 
@@ -69,6 +69,10 @@ public:
   CPPDeclaration *find_symbol(CPPScope *current_scope,
   CPPDeclaration *find_symbol(CPPScope *current_scope,
                               CPPScope *global_scope,
                               CPPScope *global_scope,
                               CPPPreprocessor *error_sink = NULL) const;
                               CPPPreprocessor *error_sink = NULL) const;
+  CPPDeclaration *find_symbol(CPPScope *current_scope,
+                              CPPScope *global_scope,
+                              CPPDeclaration::SubstDecl &subst,
+                              CPPPreprocessor *error_sink = NULL) const;
   CPPDeclaration *find_template(CPPScope *current_scope,
   CPPDeclaration *find_template(CPPScope *current_scope,
                                 CPPScope *global_scope,
                                 CPPScope *global_scope,
                                 CPPPreprocessor *error_sink = NULL) const;
                                 CPPPreprocessor *error_sink = NULL) const;

+ 1 - 1
dtool/src/cppparser/cppInstance.cxx

@@ -372,6 +372,7 @@ CPPDeclaration *CPPInstance::
 instantiate(const CPPTemplateParameterList *actual_params,
 instantiate(const CPPTemplateParameterList *actual_params,
             CPPScope *current_scope, CPPScope *global_scope,
             CPPScope *current_scope, CPPScope *global_scope,
             CPPPreprocessor *error_sink) const {
             CPPPreprocessor *error_sink) const {
+
   if (!is_template()) {
   if (!is_template()) {
     if (error_sink != NULL) {
     if (error_sink != NULL) {
       error_sink->warning("Ignoring template parameters for instance " +
       error_sink->warning("Ignoring template parameters for instance " +
@@ -457,7 +458,6 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
   rep->_type = new_type->as_type();
   rep->_type = new_type->as_type();
 
 
   if (rep->_type == NULL) {
   if (rep->_type == NULL) {
-    cerr << "Type " << *_type << " became " << *new_type << " which isn't a type\n";
     rep->_type = _type;
     rep->_type = _type;
   }
   }
 
 

+ 2 - 2
dtool/src/cppparser/cppManifest.cxx

@@ -47,8 +47,8 @@ ExpansionNode(const string &str, bool paste) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPPManifest::
 CPPManifest::
 CPPManifest(const string &args, const CPPFile &file) :
 CPPManifest(const string &args, const CPPFile &file) :
-  _file(file),
   _variadic_param(-1),
   _variadic_param(-1),
+  _file(file),
   _expr((CPPExpression *)NULL)
   _expr((CPPExpression *)NULL)
 {
 {
   assert(!args.empty());
   assert(!args.empty());
@@ -184,7 +184,7 @@ expand(const vector_string &args) const {
         // to a comma and no arguments are passed, the comma
         // to a comma and no arguments are passed, the comma
         // is removed.  MSVC does this automatically.  Not sure
         // is removed.  MSVC does this automatically.  Not sure
         // if we should allow MSVC behavior as well.
         // if we should allow MSVC behavior as well.
-        if (*result.rbegin() == ',') {
+        if (!result.empty() && *result.rbegin() == ',') {
           result.resize(result.size() - 1);
           result.resize(result.size() - 1);
         }
         }
       }
       }

+ 24 - 10
dtool/src/cppparser/cppPreprocessor.cxx

@@ -200,6 +200,7 @@ CPPPreprocessor() {
 
 
   _warning_count = 0;
   _warning_count = 0;
   _error_count = 0;
   _error_count = 0;
+  _error_abort = false;
 #ifdef CPP_VERBOSE_LEX
 #ifdef CPP_VERBOSE_LEX
   _token_index = 0;
   _token_index = 0;
 #endif
 #endif
@@ -404,8 +405,7 @@ get_next_token0() {
 
 
     int token_type = IDENTIFIER;
     int token_type = IDENTIFIER;
     CPPDeclaration *decl = ident->find_symbol(current_scope, global_scope);
     CPPDeclaration *decl = ident->find_symbol(current_scope, global_scope);
-    if (decl != NULL &&
-        (decl->as_typedef() != NULL || decl->as_type() != NULL)) {
+    if (decl != NULL && decl->as_type() != NULL) {
       token_type = TYPENAME_IDENTIFIER;
       token_type = TYPENAME_IDENTIFIER;
     }
     }
 
 
@@ -432,10 +432,14 @@ warning(const string &message, int line, int col, CPPFile file) {
     if (file.empty()) {
     if (file.empty()) {
       file = get_file();
       file = get_file();
     }
     }
-    indent(cerr, _files.size() * 2)
+    int indent_level = 0;
+    if (_verbose >= 3) {
+      indent_level = _files.size() * 2;
+    }
+    indent(cerr, indent_level)
       << "*** Warning in " << file
       << "*** Warning in " << file
       << " near line " << line << ", column " << col << ":\n";
       << " near line " << line << ", column " << col << ":\n";
-    indent(cerr, _files.size() * 2)
+    indent(cerr, indent_level)
       << message << "\n";
       << message << "\n";
   }
   }
   _warning_count++;
   _warning_count++;
@@ -452,7 +456,7 @@ error(const string &message, int line, int col, CPPFile file) {
     // Don't report or log errors in the nested state.  These will be
     // Don't report or log errors in the nested state.  These will be
     // reported when the nesting level collapses.
     // reported when the nesting level collapses.
     return;
     return;
-  };
+  }
 
 
   if (_verbose >= 1) {
   if (_verbose >= 1) {
     if (line == 0) {
     if (line == 0) {
@@ -462,11 +466,20 @@ error(const string &message, int line, int col, CPPFile file) {
     if (file.empty()) {
     if (file.empty()) {
       file = get_file();
       file = get_file();
     }
     }
-    indent(cerr, _files.size() * 2)
+    int indent_level = 0;
+    if (_verbose >= 3) {
+      indent_level = _files.size() * 2;
+    }
+    indent(cerr, indent_level)
       << "*** Error in " << file
       << "*** Error in " << file
       << " near line " << line << ", column " << col << ":\n";
       << " near line " << line << ", column " << col << ":\n";
-    indent(cerr, _files.size() * 2)
+    indent(cerr, indent_level)
       << message << "\n";
       << message << "\n";
+
+    if (_error_abort) {
+      cerr << "Aborting.\n";
+      abort();
+    }
   }
   }
   _error_count++;
   _error_count++;
 }
 }
@@ -603,7 +616,7 @@ init_type(const string &type) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool CPPPreprocessor::
 bool CPPPreprocessor::
 push_file(const CPPFile &file) {
 push_file(const CPPFile &file) {
-  if (_verbose >= 2) {
+  if (_verbose >= 3) {
     indent(cerr, _files.size() * 2)
     indent(cerr, _files.size() * 2)
       << "Reading " << file << "\n";
       << "Reading " << file << "\n";
   }
   }
@@ -2009,7 +2022,8 @@ check_keyword(const string &name) {
   if (name == "bool") return KW_BOOL;
   if (name == "bool") return KW_BOOL;
   if (name == "catch") return KW_CATCH;
   if (name == "catch") return KW_CATCH;
   if (name == "char") return KW_CHAR;
   if (name == "char") return KW_CHAR;
-  if (name == "wchar_t") return KW_WCHAR_T;
+  if (name == "char16_t") return KW_CHAR16_T;
+  if (name == "char32_t") return KW_CHAR32_T;
   if (name == "class") return KW_CLASS;
   if (name == "class") return KW_CLASS;
   if (name == "const") return KW_CONST;
   if (name == "const") return KW_CONST;
   if (name == "delete") return KW_DELETE;
   if (name == "delete") return KW_DELETE;
@@ -2061,6 +2075,7 @@ check_keyword(const string &name) {
   if (name == "virtual") return KW_VIRTUAL;
   if (name == "virtual") return KW_VIRTUAL;
   if (name == "void") return KW_VOID;
   if (name == "void") return KW_VOID;
   if (name == "volatile") return KW_VOLATILE;
   if (name == "volatile") return KW_VOLATILE;
+  if (name == "wchar_t") return KW_WCHAR_T;
   if (name == "while") return KW_WHILE;
   if (name == "while") return KW_WHILE;
 
 
   // These are alternative ways to refer to built-in operators.
   // These are alternative ways to refer to built-in operators.
@@ -2287,7 +2302,6 @@ unget(int c) {
   _unget = c;
   _unget = c;
 }
 }
 
 
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPPreprocessor::nested_parse_template_instantiation
 //     Function: CPPPreprocessor::nested_parse_template_instantiation
 //       Access: Private
 //       Access: Private

+ 1 - 0
dtool/src/cppparser/cppPreprocessor.h

@@ -209,6 +209,7 @@ private:
 
 
   int _warning_count;
   int _warning_count;
   int _error_count;
   int _error_count;
+  bool _error_abort;
 };
 };
 
 
 #endif
 #endif

+ 146 - 65
dtool/src/cppparser/cppScope.cxx

@@ -16,7 +16,7 @@
 #include "cppScope.h"
 #include "cppScope.h"
 #include "cppDeclaration.h"
 #include "cppDeclaration.h"
 #include "cppNamespace.h"
 #include "cppNamespace.h"
-#include "cppTypedef.h"
+#include "cppTypedefType.h"
 #include "cppTypeDeclaration.h"
 #include "cppTypeDeclaration.h"
 #include "cppExtensionType.h"
 #include "cppExtensionType.h"
 #include "cppInstance.h"
 #include "cppInstance.h"
@@ -136,7 +136,7 @@ add_declaration(CPPDeclaration *decl, CPPScope *global_scope,
 
 
   _declarations.push_back(decl);
   _declarations.push_back(decl);
 
 
-  handle_declaration(decl, global_scope);
+  handle_declaration(decl, global_scope, preprocessor);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -185,9 +185,12 @@ add_enum_value(CPPInstance *inst, CPPPreprocessor *preprocessor,
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CPPScope::
 void CPPScope::
-define_extension_type(CPPExtensionType *type) {
+define_extension_type(CPPExtensionType *type, CPPPreprocessor *error_sink) {
   assert(type != NULL);
   assert(type != NULL);
-  string name = type->get_simple_name();
+  string name = type->get_local_name(this);
+  if (name.empty()) {
+    return;
+  }
 
 
   switch (type->_type) {
   switch (type->_type) {
   case CPPExtensionType::T_class:
   case CPPExtensionType::T_class:
@@ -200,34 +203,59 @@ define_extension_type(CPPExtensionType *type) {
 
 
   case CPPExtensionType::T_union:
   case CPPExtensionType::T_union:
     _unions[name] = type;
     _unions[name] = type;
+    break;
 
 
   case CPPExtensionType::T_enum:
   case CPPExtensionType::T_enum:
     _enums[name] = type;
     _enums[name] = type;
+    break;
   }
   }
 
 
   // Create an implicit typedef for the extension.
   // Create an implicit typedef for the extension.
-  CPPIdentifier *ident = new CPPIdentifier(name);
-  CPPTypedef *td = new CPPTypedef(new CPPInstance(type, ident), false);
-  pair<Typedefs::iterator, bool> result =
-    _typedefs.insert(Typedefs::value_type(name, td));
+  //CPPTypedefType *td = new CPPTypedefType(type, name);
+  pair<Types::iterator, bool> result =
+    _types.insert(Types::value_type(name, type));
 
 
   if (!result.second) {
   if (!result.second) {
     // There's already a typedef for this extension.  This one
     // There's already a typedef for this extension.  This one
-    // overrides if it has template parameters and the other one
-    // doesn't.
-    CPPType *other_type = (*result.first).second->_type;
-    if (type->is_template() && !other_type->is_template()) {
-      (*result.first).second = td;
-
-      // Or if the other one is a forward reference.
-    } else if (other_type->get_subtype() == CPPDeclaration::ST_extension) {
-      (*result.first).second = td;
+    // overrides it only if the other is a forward declaration.
+    CPPType *other_type = (*result.first).second;
+
+    if (other_type->get_subtype() == CPPDeclaration::ST_extension) {
+      CPPExtensionType *other_ext = other_type->as_extension_type();
+
+      if (other_ext->_type != type->_type) {
+        if (error_sink != NULL) {
+          ostringstream errstr;
+          errstr << other_ext->_type << " " << type->get_fully_scoped_name()
+                 << " was previously declared as " << other_ext->_type << "\n";
+          error_sink->error(errstr.str());
+        }
+      }
+      (*result.first).second = type;
+
+    } else {
+      CPPTypedefType *other_td = other_type->as_typedef_type();
+
+      // Error out if the declaration is different than the previous one.
+      if (other_type != type &&
+          (other_td == NULL || other_td->_type != type)) {
+
+        if (error_sink != NULL) {
+          ostringstream errstr;
+          type->output(errstr, 0, NULL, false);
+          errstr << " has conflicting declaration as ";
+          other_type->output(errstr, 0, NULL, true);
+          error_sink->error(errstr.str());
+        }
+      }
     }
     }
   }
   }
 
 
   if (type->is_template()) {
   if (type->is_template()) {
+    string simple_name = type->get_simple_name();
+
     pair<Templates::iterator, bool> result =
     pair<Templates::iterator, bool> result =
-      _templates.insert(Templates::value_type(name, type));
+      _templates.insert(Templates::value_type(simple_name, type));
 
 
     if (!result.second) {
     if (!result.second) {
       // The template was not inserted because we already had a
       // The template was not inserted because we already had a
@@ -277,7 +305,7 @@ add_using(CPPUsing *using_decl, CPPScope *global_scope,
   } else {
   } else {
     CPPDeclaration *decl = using_decl->_ident->find_symbol(this, global_scope);
     CPPDeclaration *decl = using_decl->_ident->find_symbol(this, global_scope);
     if (decl != NULL) {
     if (decl != NULL) {
-      handle_declaration(decl, global_scope);
+      handle_declaration(decl, global_scope, error_sink);
     } else {
     } else {
       if (error_sink != NULL) {
       if (error_sink != NULL) {
         error_sink->warning("Attempt to use unknown symbol: " + using_decl->_ident->get_fully_scoped_name());
         error_sink->warning("Attempt to use unknown symbol: " + using_decl->_ident->get_fully_scoped_name());
@@ -391,11 +419,13 @@ instantiate(const CPPTemplateParameterList *actual_params,
       CPPDeclaration *decl = (*pi);
       CPPDeclaration *decl = (*pi);
       CPPClassTemplateParameter *ctp = decl->as_class_template_parameter();
       CPPClassTemplateParameter *ctp = decl->as_class_template_parameter();
       if (ctp != NULL) {
       if (ctp != NULL) {
-        CPPInstance *inst = new CPPInstance(ctp, ctp->_ident);
-        CPPTypedef *td = new CPPTypedef(inst, true);
-        scope->_typedefs.insert(Typedefs::value_type
-                                (ctp->_ident->get_local_name(),
-                                 td));
+        //CPPTypedefType *td = new CPPTypedefType(ctp, ctp->_ident);
+        //scope->_typedefs.insert(Typedefs::value_type
+        //                        (ctp->_ident->get_local_name(),
+        //                         td));
+        scope->_types.insert(Types::value_type
+                             (ctp->_ident->get_local_name(),
+                              ctp));
       }
       }
     }
     }
   }
   }
@@ -465,10 +495,10 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPPType *CPPScope::
 CPPType *CPPScope::
 find_type(const string &name, bool recurse) const {
 find_type(const string &name, bool recurse) const {
-  Typedefs::const_iterator ti;
-  ti = _typedefs.find(name);
-  if (ti != _typedefs.end()) {
-    return (*ti).second->_type;
+  Types::const_iterator ti;
+  ti = _types.find(name);
+  if (ti != _types.end()) {
+    return ti->second;
   }
   }
 
 
   Using::const_iterator ui;
   Using::const_iterator ui;
@@ -509,11 +539,11 @@ find_type(const string &name, bool recurse) const {
 CPPType *CPPScope::
 CPPType *CPPScope::
 find_type(const string &name, CPPDeclaration::SubstDecl &subst,
 find_type(const string &name, CPPDeclaration::SubstDecl &subst,
           CPPScope *global_scope, bool recurse) const {
           CPPScope *global_scope, bool recurse) const {
-  Typedefs::const_iterator ti;
-  ti = _typedefs.find(name);
-  if (ti != _typedefs.end()) {
+  Types::const_iterator ti;
+  ti = _types.find(name);
+  if (ti != _types.end()) {
     CPPScope *current_scope = (CPPScope *)this;
     CPPScope *current_scope = (CPPScope *)this;
-    return (*ti).second->_type->substitute_decl
+    return (*ti).second->substitute_decl
       (subst, current_scope, global_scope)->as_type();
       (subst, current_scope, global_scope)->as_type();
   }
   }
 
 
@@ -562,10 +592,14 @@ find_scope(const string &name, bool recurse) const {
 
 
   CPPType *type = (CPPType *)NULL;
   CPPType *type = (CPPType *)NULL;
 
 
-  Typedefs::const_iterator ti;
-  ti = _typedefs.find(name);
-  if (ti != _typedefs.end()) {
-    type = (*ti).second->_type;
+  Types::const_iterator ti;
+  ti = _types.find(name);
+  if (ti != _types.end()) {
+    type = (*ti).second;
+    // Resolve if this is a typedef.
+    while (type->as_typedef_type() != (CPPTypedefType *)NULL) {
+      type = type->as_typedef_type()->_type;
+    }
 
 
   } else if (_struct_type != NULL) {
   } else if (_struct_type != NULL) {
     CPPStructType::Derivation::const_iterator di;
     CPPStructType::Derivation::const_iterator di;
@@ -613,10 +647,17 @@ find_scope(const string &name, CPPDeclaration::SubstDecl &subst,
   if (type == NULL) {
   if (type == NULL) {
     return NULL;
     return NULL;
   }
   }
+
+  // Resolve this if it is a typedef.
+  while (type->get_subtype() == CPPDeclaration::ST_typedef) {
+    type = type->as_typedef_type()->_type;
+  }
+
   CPPStructType *st = type->as_struct_type();
   CPPStructType *st = type->as_struct_type();
   if (st == NULL) {
   if (st == NULL) {
     return NULL;
     return NULL;
   }
   }
+
   return st->_scope;
   return st->_scope;
 }
 }
 
 
@@ -631,10 +672,10 @@ find_symbol(const string &name, bool recurse) const {
     return _struct_type;
     return _struct_type;
   }
   }
 
 
-  Typedefs::const_iterator ti;
-  ti = _typedefs.find(name);
-  if (ti != _typedefs.end()) {
-    return (*ti).second->_type;
+  Types::const_iterator ti;
+  ti = _types.find(name);
+  if (ti != _types.end()) {
+    return (*ti).second;
   }
   }
 
 
   Variables::const_iterator vi;
   Variables::const_iterator vi;
@@ -755,9 +796,14 @@ get_local_name(CPPScope *scope) const {
   }
   }
   */
   */
 
 
-  if (scope != NULL && _parent_scope != NULL && _parent_scope != scope) {
-    return _parent_scope->get_local_name(scope) + "::" +
-      _name.get_name_with_templ();
+  if (scope != NULL && _parent_scope != NULL/* && _parent_scope != scope*/) {
+    string parent_scope_name = _parent_scope->get_local_name(scope);
+    if (parent_scope_name.empty()) {
+      return _name.get_name_with_templ();
+    } else {
+      return parent_scope_name + "::" +
+        _name.get_name_with_templ();
+    }
   } else {
   } else {
     return _name.get_name_with_templ();
     return _name.get_name_with_templ();
   }
   }
@@ -816,8 +862,7 @@ write(ostream &out, int indent_level, CPPScope *scope) const {
     }
     }
     bool complete = false;
     bool complete = false;
 
 
-    if (cd->as_typedef() != NULL || cd->as_type() != NULL ||
-        cd->as_namespace() != NULL) {
+    if (cd->as_type() != NULL || cd->as_namespace() != NULL) {
       complete = true;
       complete = true;
     }
     }
 
 
@@ -880,7 +925,7 @@ copy_substitute_decl(CPPScope *to_scope, CPPDeclaration::SubstDecl &subst,
     }
     }
     to_scope->_struct_type =
     to_scope->_struct_type =
       new CPPStructType(_struct_type->_type,
       new CPPStructType(_struct_type->_type,
-                        new CPPIdentifier(to_scope->_name),
+                        new CPPIdentifier(to_scope->_name, _struct_type->_file),
                         native_scope, to_scope, _struct_type->_file);
                         native_scope, to_scope, _struct_type->_file);
     to_scope->_struct_type->_incomplete = false;
     to_scope->_struct_type->_incomplete = false;
 
 
@@ -985,11 +1030,11 @@ copy_substitute_decl(CPPScope *to_scope, CPPDeclaration::SubstDecl &subst,
     }
     }
   }
   }
 
 
-  Typedefs::const_iterator ti;
-  for (ti = _typedefs.begin(); ti != _typedefs.end(); ++ti) {
-    CPPTypedef *td =
-      (*ti).second->substitute_decl(subst, to_scope, global_scope)->as_typedef();
-    to_scope->_typedefs.insert(Typedefs::value_type((*ti).first, td));
+  Types::const_iterator ti;
+  for (ti = _types.begin(); ti != _types.end(); ++ti) {
+    CPPType *td =
+      (*ti).second->substitute_decl(subst, to_scope, global_scope)->as_type();
+    to_scope->_types.insert(Types::value_type((*ti).first, td));
     if (td != (*ti).second) {
     if (td != (*ti).second) {
       anything_changed = true;
       anything_changed = true;
     }
     }
@@ -999,6 +1044,19 @@ copy_substitute_decl(CPPScope *to_scope, CPPDeclaration::SubstDecl &subst,
     CPPInstance *inst =
     CPPInstance *inst =
       (*vi).second->substitute_decl(subst, to_scope, global_scope)->as_instance();
       (*vi).second->substitute_decl(subst, to_scope, global_scope)->as_instance();
     to_scope->_variables.insert(Variables::value_type((*vi).first, inst));
     to_scope->_variables.insert(Variables::value_type((*vi).first, inst));
+    if (inst != (*vi).second) {
+      // I don't know if this _native_scope assignment is right, but it
+      // fixes some issues with variables in instantiated template scopes
+      // being printed out with an uninstantiated template scope prefix. ~rdb
+      inst->_ident->_native_scope = to_scope;
+      anything_changed = true;
+    }
+  }
+
+  for (vi = _enum_values.begin(); vi != _enum_values.end(); ++vi) {
+    CPPInstance *inst =
+      (*vi).second->substitute_decl(subst, to_scope, global_scope)->as_instance();
+    to_scope->_enum_values.insert(Variables::value_type((*vi).first, inst));
     if (inst != (*vi).second) {
     if (inst != (*vi).second) {
       anything_changed = true;
       anything_changed = true;
     }
     }
@@ -1026,25 +1084,41 @@ copy_substitute_decl(CPPScope *to_scope, CPPDeclaration::SubstDecl &subst,
 //               functions, or whatever.
 //               functions, or whatever.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CPPScope::
 void CPPScope::
-handle_declaration(CPPDeclaration *decl, CPPScope *global_scope) {
-  CPPTypedef *def = decl->as_typedef();
+handle_declaration(CPPDeclaration *decl, CPPScope *global_scope,
+                   CPPPreprocessor *error_sink) {
+  CPPTypedefType *def = decl->as_typedef_type();
   if (def != NULL) {
   if (def != NULL) {
     string name = def->get_simple_name();
     string name = def->get_simple_name();
-    _typedefs[name] = def;
+
+    pair<Types::iterator, bool> result =
+      _types.insert(Types::value_type(name, def));
+
+    if (!result.second) {
+      CPPType *other_type = result.first->second;
+      CPPTypedefType *other_td = other_type->as_typedef_type();
+
+      // We don't do redefinitions of typedefs.  But we don't complain
+      // as long as this is actually a typedef to the previous definition.
+      if (other_type != def->_type &&
+          (other_td == NULL || other_td->_type != def->_type)) {
+
+        if (error_sink != NULL) {
+          ostringstream errstr;
+          def->output(errstr, 0, NULL, false);
+          errstr << " has conflicting declaration as ";
+          other_type->output(errstr, 0, NULL, true);
+          error_sink->error(errstr.str());
+        }
+      }
+    } else {
+      _types[name] = def;
+    }
 
 
     CPPExtensionType *et = def->_type->as_extension_type();
     CPPExtensionType *et = def->_type->as_extension_type();
     if (et != NULL) {
     if (et != NULL) {
-      define_extension_type(et);
+      define_extension_type(et, error_sink);
     }
     }
 
 
-    if (!name.empty() && def->get_scope(this, global_scope) == this) {
-      // Don't add a new template definition if we already had one
-      // by the same name in another scope.
-
-      if (find_template(name) == NULL) {
-        _templates.insert(Templates::value_type(name, def));
-      }
-    }
     return;
     return;
   }
   }
 
 
@@ -1052,7 +1126,7 @@ handle_declaration(CPPDeclaration *decl, CPPScope *global_scope) {
   if (typedecl != (CPPTypeDeclaration *)NULL) {
   if (typedecl != (CPPTypeDeclaration *)NULL) {
     CPPExtensionType *et = typedecl->_type->as_extension_type();
     CPPExtensionType *et = typedecl->_type->as_extension_type();
     if (et != NULL) {
     if (et != NULL) {
-      define_extension_type(et);
+      define_extension_type(et, error_sink);
     }
     }
     return;
     return;
   }
   }
@@ -1061,6 +1135,13 @@ handle_declaration(CPPDeclaration *decl, CPPScope *global_scope) {
   if (inst != NULL) {
   if (inst != NULL) {
     inst->check_for_constructor(this, global_scope);
     inst->check_for_constructor(this, global_scope);
 
 
+    if (inst->_ident != NULL) {
+      // Not sure if this is the best place to assign this.  However,
+      // this fixes a bug with variables in expressions not having
+      // the proper scoping prefix. ~rdb
+      inst->_ident->_native_scope = this;
+    }
+
     string name = inst->get_simple_name();
     string name = inst->get_simple_name();
     if (!name.empty() && inst->get_scope(this, global_scope) == this) {
     if (!name.empty() && inst->get_scope(this, global_scope) == this) {
       if (inst->_type->as_function_type()) {
       if (inst->_type->as_function_type()) {
@@ -1107,6 +1188,6 @@ handle_declaration(CPPDeclaration *decl, CPPScope *global_scope) {
 
 
   CPPExtensionType *et = decl->as_extension_type();
   CPPExtensionType *et = decl->as_extension_type();
   if (et != NULL) {
   if (et != NULL) {
-    define_extension_type(et);
+    define_extension_type(et, error_sink);
   }
   }
 }
 }

+ 7 - 5
dtool/src/cppparser/cppScope.h

@@ -34,7 +34,7 @@ class CPPExtensionType;
 class CPPStructType;
 class CPPStructType;
 class CPPNamespace;
 class CPPNamespace;
 class CPPUsing;
 class CPPUsing;
-class CPPTypedef;
+class CPPTypedefType;
 class CPPInstance;
 class CPPInstance;
 class CPPFunctionGroup;
 class CPPFunctionGroup;
 class CPPTemplateScope;
 class CPPTemplateScope;
@@ -66,7 +66,8 @@ public:
   virtual void add_enum_value(CPPInstance *inst,
   virtual void add_enum_value(CPPInstance *inst,
                               CPPPreprocessor *preprocessor,
                               CPPPreprocessor *preprocessor,
                               const cppyyltype &pos);
                               const cppyyltype &pos);
-  virtual void define_extension_type(CPPExtensionType *type);
+  virtual void define_extension_type(CPPExtensionType *type,
+                                     CPPPreprocessor *error_sink = NULL);
   virtual void define_namespace(CPPNamespace *scope);
   virtual void define_namespace(CPPNamespace *scope);
   virtual void add_using(CPPUsing *using_decl, CPPScope *global_scope,
   virtual void add_using(CPPUsing *using_decl, CPPScope *global_scope,
                          CPPPreprocessor *error_sink = NULL);
                          CPPPreprocessor *error_sink = NULL);
@@ -113,7 +114,8 @@ private:
   copy_substitute_decl(CPPScope *to_scope, CPPDeclaration::SubstDecl &subst,
   copy_substitute_decl(CPPScope *to_scope, CPPDeclaration::SubstDecl &subst,
                        CPPScope *global_scope) const;
                        CPPScope *global_scope) const;
 
 
-  void handle_declaration(CPPDeclaration *decl, CPPScope *global_scope);
+  void handle_declaration(CPPDeclaration *decl, CPPScope *global_scope,
+                          CPPPreprocessor *error_sink = NULL);
 
 
 public:
 public:
   typedef vector<CPPDeclaration *> Declarations;
   typedef vector<CPPDeclaration *> Declarations;
@@ -128,8 +130,8 @@ public:
   typedef map<string, CPPNamespace *> Namespaces;
   typedef map<string, CPPNamespace *> Namespaces;
   Namespaces _namespaces;
   Namespaces _namespaces;
 
 
-  typedef map<string, CPPTypedef *> Typedefs;
-  Typedefs _typedefs;
+  typedef map<string, CPPType *> Types;
+  Types _types;
   typedef map<string, CPPInstance *> Variables;
   typedef map<string, CPPInstance *> Variables;
   Variables _variables;
   Variables _variables;
   Variables _enum_values;
   Variables _enum_values;

+ 12 - 4
dtool/src/cppparser/cppSimpleType.cxx

@@ -99,6 +99,10 @@ output(ostream &out, int, CPPScope *, bool) const {
   }
   }
 
 
   switch (_type) {
   switch (_type) {
+  case T_unknown:
+    out << "unknown";
+    break;
+
   case T_bool:
   case T_bool:
     out << "bool";
     out << "bool";
     break;
     break;
@@ -111,6 +115,14 @@ output(ostream &out, int, CPPScope *, bool) const {
     out << "wchar_t";
     out << "wchar_t";
     break;
     break;
 
 
+  case T_char16_t:
+    out << "char16_t";
+    break;
+
+  case T_char32_t:
+    out << "char32_t";
+    break;
+
   case T_int:
   case T_int:
     out << "int";
     out << "int";
     break;
     break;
@@ -127,10 +139,6 @@ output(ostream &out, int, CPPScope *, bool) const {
     out << "void";
     out << "void";
     break;
     break;
 
 
-  case T_unknown:
-    out << "unknown";
-    break;
-
   case T_parameter:
   case T_parameter:
     out << "parameter";
     out << "parameter";
     break;
     break;

+ 4 - 2
dtool/src/cppparser/cppSimpleType.h

@@ -26,14 +26,16 @@
 class CPPSimpleType : public CPPType {
 class CPPSimpleType : public CPPType {
 public:
 public:
   enum Type {
   enum Type {
+    T_unknown,
     T_bool,
     T_bool,
     T_char,
     T_char,
-    T_wchar_t,  // Not strictly a builtin type, but we pretend.
+    T_wchar_t,
+    T_char16_t,
+    T_char32_t,
     T_int,
     T_int,
     T_float,
     T_float,
     T_double,
     T_double,
     T_void,
     T_void,
-    T_unknown,
 
 
     // T_parameter is a special type which is assigned to expressions
     // T_parameter is a special type which is assigned to expressions
     // that are discovered where a formal parameter was expected.
     // that are discovered where a formal parameter was expected.

+ 10 - 11
dtool/src/cppparser/cppStructType.cxx

@@ -14,7 +14,7 @@
 
 
 
 
 #include "cppStructType.h"
 #include "cppStructType.h"
-#include "cppTypedef.h"
+#include "cppTypedefType.h"
 #include "cppScope.h"
 #include "cppScope.h"
 #include "cppTypeProxy.h"
 #include "cppTypeProxy.h"
 #include "cppTemplateScope.h"
 #include "cppTemplateScope.h"
@@ -91,6 +91,13 @@ operator = (const CPPStructType &copy) {
 void CPPStructType::
 void CPPStructType::
 append_derivation(CPPType *base, CPPVisibility vis, bool is_virtual) {
 append_derivation(CPPType *base, CPPVisibility vis, bool is_virtual) {
   if (base != NULL) {
   if (base != NULL) {
+    // Unwrap any typedefs, since we can't inherit from a typedef.
+    CPPTypedefType *def = base->as_typedef_type();
+    while (def != NULL) {
+      base = def->_type;
+      def = base->as_typedef_type();
+    }
+
     Base b;
     Base b;
     b._base = base;
     b._base = base;
     b._vis = vis;
     b._vis = vis;
@@ -110,7 +117,6 @@ get_scope() const {
   return _scope;
   return _scope;
 }
 }
 
 
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPStructType::is_abstract
 //     Function: CPPStructType::is_abstract
 //       Access: Public
 //       Access: Public
@@ -246,7 +252,7 @@ instantiate(const CPPTemplateParameterList *actual_params,
     // don't yet know what its associated struct type will be.
     // don't yet know what its associated struct type will be.
 
 
     // Postpone the evaluation of this type.
     // Postpone the evaluation of this type.
-    CPPIdentifier *ident = new CPPIdentifier(get_fully_scoped_name());
+    CPPIdentifier *ident = new CPPIdentifier(get_fully_scoped_name(), _file);
 
 
     return CPPType::new_type(new CPPTBDType(ident));
     return CPPType::new_type(new CPPTBDType(ident));
   }
   }
@@ -318,7 +324,7 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
             rep->_template_scope = (CPPTemplateScope *)NULL;
             rep->_template_scope = (CPPTemplateScope *)NULL;
             CPPNameComponent nc(get_simple_name());
             CPPNameComponent nc(get_simple_name());
             nc.set_templ(pscope->_name.get_templ());
             nc.set_templ(pscope->_name.get_templ());
-            rep->_ident = new CPPIdentifier(nc);
+            rep->_ident = new CPPIdentifier(nc, _file);
           }
           }
         }
         }
       }
       }
@@ -356,7 +362,6 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
   assert(rep != NULL);
   assert(rep != NULL);
   if (rep != this) {
   if (rep != this) {
     _instantiations.insert(rep);
     _instantiations.insert(rep);
-    //    cerr << "Subst for " << *this << " is " << *rep << "\n";
   }
   }
   return rep;
   return rep;
 }
 }
@@ -377,15 +382,9 @@ output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
 
 
     if (is_template()) {
     if (is_template()) {
       CPPTemplateScope *tscope = get_template_scope();
       CPPTemplateScope *tscope = get_template_scope();
-      out << "< ";
       tscope->_parameters.output(out, scope);
       tscope->_parameters.output(out, scope);
-      out << " >";
     }
     }
 
 
-  } else if (!complete && !_typedefs.empty()) {
-    // If we have a typedef name, use it.
-    out << _typedefs.front()->get_local_name(scope);
-
   } else {
   } else {
     if (is_template()) {
     if (is_template()) {
       get_template_scope()->_parameters.write_formal(out, scope);
       get_template_scope()->_parameters.write_formal(out, scope);

+ 1 - 0
dtool/src/cppparser/cppTemplateParameterList.cxx

@@ -52,6 +52,7 @@ void CPPTemplateParameterList::
 build_subst_decl(const CPPTemplateParameterList &formal_params,
 build_subst_decl(const CPPTemplateParameterList &formal_params,
                  CPPDeclaration::SubstDecl &subst,
                  CPPDeclaration::SubstDecl &subst,
                  CPPScope *current_scope, CPPScope *global_scope) const {
                  CPPScope *current_scope, CPPScope *global_scope) const {
+
   Parameters::const_iterator pfi, pai;
   Parameters::const_iterator pfi, pai;
   for (pfi = formal_params._parameters.begin(), pai = _parameters.begin();
   for (pfi = formal_params._parameters.begin(), pai = _parameters.begin();
        pfi != formal_params._parameters.end() && pai != _parameters.end();
        pfi != formal_params._parameters.end() && pai != _parameters.end();

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác