Browse Source

Merge branch 'master' into cmake

Sam Edwards 10 years ago
parent
commit
69c22868e1
100 changed files with 9461 additions and 944 deletions
  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
-/samples
 /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:
 
 ```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

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

@@ -18,7 +18,7 @@
 static const float _PI = 3.14;
 
 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;
   _previous_conflict = false;
   _conflict = false;
@@ -67,7 +67,7 @@ bool AIBehaviors::is_conflict() {
       }
 
       if(is_on(_flee)) {
-        LVecBase3f dirn = _flee_force;
+        LVecBase3 dirn = _flee_force;
         dirn.normalize();
         _flee_force = _steering_force.length() * dirn * _flee_obj->_flee_weight;
       }
@@ -77,7 +77,7 @@ bool AIBehaviors::is_conflict() {
       }
 
       if(is_on(_evade)) {
-        LVecBase3f dirn = _evade_force;
+        LVecBase3 dirn = _evade_force;
         dirn.normalize();
         _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") {
     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(_conflict) {
@@ -299,13 +299,13 @@ LVecBase3f AIBehaviors::calculate_prioritized() {
 
   if(is_on(_arrival)) {
     if(_seek_obj != NULL) {
-      LVecBase3f dirn = _steering_force;
+      LVecBase3 dirn = _steering_force;
       dirn.normalize();
       _steering_force = ((_steering_force.length() - _arrival_force.length()) * dirn);
     }
 
     if(_pursue_obj != NULL) {
-      LVecBase3f dirn = _steering_force;
+      LVecBase3 dirn = _steering_force;
       dirn.normalize();
       _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
 // 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 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");
 }
 
-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);
   turn_on("seek");
 }
@@ -657,7 +657,7 @@ void AIBehaviors::seek(LVecBase3f pos, float seek_wt) {
 //
 // Function : flee
 // 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");
 }
 
-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_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.
   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.
   for(unsigned int i = 0; i < _flock_group->_ai_char_list.size(); i++) {
     if(_flock_group->_ai_char_list[i]->_name != _ai_char->_name) {
 
       //! 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();
 
       //! 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)))
         && (dist_vect.length() < _flock_group->_flock_vcone_radius)) {
           //! 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();
           ai_char_to_units.normalize();
           separation_force += (ai_char_to_units / to_units_dist);
 
           //! 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();
           total_neighbor_heading += neighbor_heading;
           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) {
     //! Alignment force calculation
     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();
     avg_neighbor_heading -= ai_char_heading;
     avg_neighbor_heading.normalize();
@@ -822,7 +822,7 @@ LVecBase3f AIBehaviors::do_flock() {
 
     //! Cohesion force calculation
     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_force = cohesion_dir * _ai_char->_movt_force;
   }
@@ -830,7 +830,7 @@ LVecBase3f AIBehaviors::do_flock() {
     _flock_done = true;
     turn_off("flock");
     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
@@ -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);
 }
 
@@ -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);
 }
 
@@ -1331,56 +1331,56 @@ switch(char_to_int(ai_type)) {
               if (is_on(_seek)) {
                 _behaviors_flags ^= _seek;
               }
-              _seek_force = LVecBase3f(0.0f, 0.0f, 0.0f);
+              _seek_force = LVecBase3(0.0f, 0.0f, 0.0f);
               break;
             }
     case 2: {
               if (is_on(_flee)) {
                 _behaviors_flags ^= _flee;
               }
-              _flee_force = LVecBase3f(0.0f, 0.0f, 0.0f);
+              _flee_force = LVecBase3(0.0f, 0.0f, 0.0f);
               break;
             }
     case 3: {
               if(is_on(_pursue)) {
                 _behaviors_flags ^= _pursue;
               }
-              _pursue_force = LVecBase3f(0.0f, 0.0f, 0.0f);
+              _pursue_force = LVecBase3(0.0f, 0.0f, 0.0f);
               break;
             }
     case 4: {
               if(is_on(_evade)) {
                 _behaviors_flags ^= _evade;
               }
-              _evade_force = LVecBase3f(0.0f, 0.0f, 0.0f);
+              _evade_force = LVecBase3(0.0f, 0.0f, 0.0f);
               break;
             }
     case 5: {
               if (is_on(_arrival)) {
                   _behaviors_flags ^= _arrival;
                 }
-                _arrival_force = LVecBase3f(0.0f, 0.0f, 0.0f);
+                _arrival_force = LVecBase3(0.0f, 0.0f, 0.0f);
               break;
             }
     case 6: {
               if(is_on(_flock)) {
                 _behaviors_flags ^= _flock;
               }
-              _flock_force = LVecBase3f(0.0f, 0.0f, 0.0f);
+              _flock_force = LVecBase3(0.0f, 0.0f, 0.0f);
               break;
             }
     case 7: {
               if(is_on(_wander)) {
                 _behaviors_flags ^= _wander;
               }
-              _wander_force = LVecBase3f(0.0f, 0.0f, 0.0f);
+              _wander_force = LVecBase3(0.0f, 0.0f, 0.0f);
               break;
             }
     case 8: {
               if(is_on(_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;
             }
     case 9:{

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

@@ -73,41 +73,41 @@ public:
   Flock *_flock_group;
 
   int _behaviors_flags;
-  LVecBase3f _steering_force;
+  LVecBase3 _steering_force;
 
   Seek *_seek_obj;
-  LVecBase3f _seek_force;
+  LVecBase3 _seek_force;
 
   Flee *_flee_obj;
-  LVecBase3f _flee_force;
+  LVecBase3 _flee_force;
 
   //! This list is used if the ai character needs to flee from multiple onjects.
   ListFlee _flee_list;
   ListFlee::iterator _flee_itr;
 
   Pursue *_pursue_obj;
-  LVecBase3f _pursue_force;
+  LVecBase3 _pursue_force;
 
   Evade *_evade_obj;
-  LVecBase3f _evade_force;
+  LVecBase3 _evade_force;
 
   //! This list is used if the ai character needs to evade from multiple onjects.
   ListEvade _evade_list;
   ListEvade::iterator _evade_itr;
 
   Arrival *_arrival_obj;
-  LVecBase3f _arrival_force;
+  LVecBase3 _arrival_force;
 
   //! Since Flock is a collective behavior the variables are declared within the AIBehaviors class.
   float _flock_weight;
-  LVecBase3f _flock_force;
+  LVecBase3 _flock_force;
   bool _flock_done;
 
   Wander * _wander_obj;
-  LVecBase3f _wander_force;
+  LVecBase3 _wander_force;
 
   ObstacleAvoidance *_obstacle_avoidance_obj;
-  LVecBase3f _obstacle_avoidance_force;
+  LVecBase3 _obstacle_avoidance_force;
 
   PathFollow *_path_follow_obj;
 
@@ -127,20 +127,20 @@ public:
 
   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();
-  LVecBase3f do_flock();
+  LVecBase3 do_flock();
 
   int char_to_int(string ai_type);
 
 PUBLISHED:
   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(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);
 
@@ -155,12 +155,12 @@ PUBLISHED:
   void obstacle_avoidance(float feeler_length = 1.0);
 
   void path_follow(float follow_wt);
-  void add_to_path(LVecBase3f pos);
+  void add_to_path(LVecBase3 pos);
   void start_follow(string type = "normal");
 
   // should have different function names.
   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 add_static_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;
   _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->_ai_char = this;
@@ -43,48 +43,43 @@ AICharacter::~AICharacter() {
 //                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;
 
-    LVecBase3f direction = _steering->_steering_force;
+    LVecBase3 direction = _steering->_steering_force;
     direction.normalize();
 
     _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.set_h(_ai_char_np.get_h() + 180);
       _ai_char_np.set_p(-_ai_char_np.get_p());
       _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;
 }
 
-void AICharacter::set_velocity(LVecBase3f velocity) {
+void AICharacter::set_velocity(LVecBase3 velocity) {
   _velocity = velocity;
 }
 

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

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

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

@@ -14,7 +14,7 @@
 
 #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) {
     _neighbours[i] = NULL;
   }

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

@@ -62,7 +62,7 @@ public:
   int _grid_x, _grid_y;
 
   // Position of the node in 3D space.
-  LVecBase3f _position;
+  LVecBase3 _position;
 
   // Dimensions of each face / cell on the mesh.
   // Height is given in case of expansion to a 3d mesh. Currently
@@ -77,7 +77,7 @@ public:
   AINode *_next;
 
 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();
 
   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.
   // 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->_score = -1;
   _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;
   float x = pos[0];
   float y = pos[1];

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

@@ -23,7 +23,7 @@
 typedef vector<Node *> NodeArray;
 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;
 
   if(_arrival_type) {
@@ -52,22 +52,22 @@ LVecBase3f Arrival::do_arrival() {
   _arrival_direction.normalize();
 
   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) {
       _ai_char->_steering->turn_off("arrival");
       _ai_char->_steering->turn_on("arrival_activate");
     }
     _arrival_done = true;
-    return(LVecBase3f(0.0, 0.0, 0.0));
+    return(LVecBase3(0.0, 0.0, 0.0));
   }
   else {
     _arrival_done = false;
   }
 
   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) {
     return(desired_force);
@@ -85,7 +85,7 @@ LVecBase3f Arrival::do_arrival() {
   }
 
   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() {
-  LVecBase3f dirn;
+  LVecBase3 dirn;
   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));
   }

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

@@ -27,9 +27,9 @@ public:
   AICharacter *_ai_char;
 
   NodePath _arrival_target;
-  LVecBase3f _arrival_target_pos;
+  LVecBase3 _arrival_target_pos;
   double _arrival_distance;
-  LVecBase3f _arrival_direction;
+  LVecBase3 _arrival_direction;
   bool _arrival_done;
 
   // 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();
-  LVecBase3f do_arrival();
+  LVecBase3 do_arrival();
   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");
 
   _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();
 
   _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((_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_on("evade_activate");
     _evade_done = true;
-    return(LVecBase3f(0.0, 0.0, 0.0));
+    return(LVecBase3(0.0, 0.0, 0.0));
   }
   else {
       _evade_done = false;

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

@@ -28,7 +28,7 @@ public:
 
   NodePath _evade_target;
   float _evade_weight;
-  LVecBase3f _evade_direction;
+  LVecBase3 _evade_direction;
   double _evade_distance;
   double _evade_relax_distance;
   bool _evade_done;
@@ -38,7 +38,7 @@ public:
                                           double relax_distance, float evade_wt);
 
   ~Evade();
-  LVecBase3f do_evade();
+  LVecBase3 do_evade();
   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::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){
 
     _ai_char = ai_ch;
@@ -57,10 +57,10 @@ Flee::~Flee() {
 
 /////////////////////////////////////////////////////////////////////////////////
 
-LVecBase3f Flee::do_flee() {
-  LVecBase3f dirn;
+LVecBase3 Flee::do_flee() {
+  LVecBase3 dirn;
   double distance;
-  LVecBase3f desired_force;
+  LVecBase3 desired_force;
 
   dirn = _ai_char->_ai_char_np.get_pos(_ai_char->_window_render) - _flee_present_pos;
   distance = dirn.length();
@@ -68,12 +68,12 @@ LVecBase3f Flee::do_flee() {
 
   if(distance > (_flee_distance + _flee_relax_distance)) {
     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;
     _ai_char->_steering->turn_off("flee");
     _ai_char->_steering->turn_on("flee_activate");
-    return(LVecBase3f(0.0, 0.0, 0.0));
+    return(LVecBase3(0.0, 0.0, 0.0));
   }
   else {
       return(desired_force);
@@ -90,7 +90,7 @@ LVecBase3f Flee::do_flee() {
 /////////////////////////////////////////////////////////////////////////////////
 
 void Flee::flee_activate() {
-  LVecBase3f dirn;
+  LVecBase3 dirn;
   double distance;
 
   _flee_activate_done = false;

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

@@ -26,23 +26,23 @@ class EXPCL_PANDAAI Flee {
 public:
   AICharacter *_ai_char;
 
-  LVecBase3f _flee_position;
+  LVecBase3 _flee_position;
   float _flee_weight;
-  LVecBase3f _flee_direction;
+  LVecBase3 _flee_direction;
   double _flee_distance;
   double _flee_relax_distance;
-  LVecBase3f _flee_present_pos;
+  LVecBase3 _flee_present_pos;
   bool _flee_done;
   bool _flee_activate_done;
 
   Flee(AICharacter *ai_ch, NodePath target_object, double panic_distance = 10.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);
 
   ~Flee();
-  LVecBase3f do_flee();
+  LVecBase3 do_flee();
   void flee_activate();
 };
 

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

@@ -1,7 +1,7 @@
 
 #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) {
     _neighbours[i] = NULL;
   }

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

@@ -47,7 +47,7 @@ public:
     int _grid_x, _grid_y;
 
     // Position of the node in 3D space.
-    LVecBase3f _position;
+    LVecBase3 _position;
 
     // Dimensions of each face / cell on the mesh.
     // 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.
     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();
 
     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
   PT(BoundingVolume) np_bounds = _ai_char->get_node_path().get_bounds();
   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 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) {
     PT(BoundingVolume) bounds = _ai_char->_world->_obstacles[i].get_bounds();
     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
     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];
@@ -51,13 +51,13 @@ bool ObstacleAvoidance::obstacle_detection() {
       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 *= (expanded_radius + np_sphere->get_radius()) ;
      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((_nearest_obstacle) && (perp.length() < expanded_radius - np_sphere->get_radius()) && (project.length() < feeler.length())) {
        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();
   CPT(BoundingSphere) bsphere = bounds->as_bounding_sphere();
   PT(BoundingVolume) np_bounds = _ai_char->get_node_path().get_bounds();
   CPT(BoundingSphere) np_sphere = np_bounds->as_bounding_sphere();
   double distance_needed = offset.length() - bsphere->get_radius() - np_sphere->get_radius();
   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();
     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();
     perpendicular_component.normalize();
-    LVecBase3f   avoidance = perpendicular_component;
+    LVecBase3   avoidance = perpendicular_component;
     // The more closer the obstacle, the more force it generates
     avoidance = (avoidance * _ai_char->get_max_force() * _ai_char->_movt_force) / (p + 0.01);
     return avoidance;
   }
   _ai_char->_steering->turn_on("obstacle_avoidance_activate");
   _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;
 
     ObstacleAvoidance(AICharacter *ai_char, float feeler_length);
-    LVecBase3f do_obstacle_avoidance();
+    LVecBase3 do_obstacle_avoidance();
     ~ObstacleAvoidance();
     void obstacle_avoidance_activate();
     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.
   int grid_x, grid_y;
   float l, w, h;
-  LVecBase3f position;
+  LVecBase3 position;
 
   // Variable to hold line data read from file.
   string line;
@@ -75,7 +75,7 @@ void PathFind::create_nav_mesh(const char* navmesh_filename) {
         l = atof(fields[4].c_str());
         w = atof(fields[5].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);
 
@@ -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(_ai_char->_steering->_path_follow_obj) {
       _ai_char->_steering->remove_ai("pathfollow");

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

@@ -43,7 +43,7 @@ public:
 
   int _grid_size;
   NodePath _path_find_target;
-  LVecBase3f _prev_position;
+  LVecBase3 _prev_position;
   PT(GeomNode) _parent;
   LineSegs *_pen;
   vector<int> _previous_obstacles;
@@ -62,7 +62,7 @@ public:
   void clear_previous_obstacles();
 
   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 add_obstacle_to_mesh(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);
 }
 
@@ -119,7 +119,7 @@ void PathFollow::do_follow() {
 
 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);
-  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);
 
   if(src && dst) {

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

@@ -13,7 +13,7 @@ class EXPCL_PANDAAI PathFollow {
 public:
   AICharacter *_ai_char;
   float _follow_weight;
-  vector<LVecBase3f> _path;
+  vector<LVecBase3> _path;
   int _curr_path_waypoint;
   bool _start;
   NodePath _dummy;
@@ -23,7 +23,7 @@ public:
 
   PathFollow(AICharacter *ai_ch, float follow_wt);
   ~PathFollow();
-  void add_to_path(LVecBase3f pos);
+  void add_to_path(LVecBase3 pos);
   void start(string type);
   void do_follow();
   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");
 
-  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();
 
   if(int(target_distance) == 0) {
     _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 {
     _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.normalize();
 
-  LVecBase3f desired_force = _pursue_direction * _ai_char->_movt_force;
+  LVecBase3 desired_force = _pursue_direction * _ai_char->_movt_force;
   return(desired_force);
 }

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

@@ -28,12 +28,12 @@ public:
 
   NodePath _pursue_target;
   float _pursue_weight;
-  LVecBase3f _pursue_direction;
+  LVecBase3 _pursue_direction;
   bool _pursue_done;
 
   Pursue(AICharacter *ai_ch, NodePath target_object, float pursue_wt);
   ~Pursue();
-  LVecBase3f do_pursue();
+  LVecBase3 do_pursue();
 };
 
 #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::Seek(AICharacter *ai_ch, LVecBase3f pos, float seek_wt) {
+Seek::Seek(AICharacter *ai_ch, LVecBase3 pos, float seek_wt) {
       _ai_char = ai_ch;
 
   _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();
 
     if(int(target_distance) == 0) {
         _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");
-    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);
 }

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

@@ -26,16 +26,16 @@ class EXPCL_PANDAAI Seek {
 public:
   AICharacter *_ai_char;
 
-  LVecBase3f _seek_position;
+  LVecBase3 _seek_position;
   float _seek_weight;
-  LVecBase3f _seek_direction;
+  LVecBase3 _seek_direction;
   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, LVecBase3f pos, float seek_wt = 1.0);
+  Seek(AICharacter *ai_ch, LVecBase3 pos, float seek_wt = 1.0);
   ~Seek();
-  LVecBase3f do_seek();
+  LVecBase3 do_seek();
 };
 
 #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
   switch(_flag) {
     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;
             }
     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;
             }
     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;
             }
     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;
             }
     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;
              }
   }
@@ -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
   double time_slice_1 = random_clamped() * 1.5;
   double time_slice_2 = random_clamped() * 1.5;
   double time_slice_3 = random_clamped() * 1.5;
   switch(_flag) {
   case 0: {
-            _wander_target += LVecBase3f(time_slice_1, time_slice_2, 0);
+            _wander_target += LVecBase3(time_slice_1, time_slice_2, 0);
             break;
           }
   case 1: {
-            _wander_target += LVecBase3f(0, time_slice_1, time_slice_2);
+            _wander_target += LVecBase3(0, time_slice_1, time_slice_2);
             break;
           }
   case 2: {
-            _wander_target += LVecBase3f(time_slice_1, 0, time_slice_2);
+            _wander_target += LVecBase3(time_slice_1, 0, time_slice_2);
             break;
           }
   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;
           }
 
   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 *= _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();
   // Project wander target onto global space
   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 *= _ai_char->_movt_force;
   double distance = (present_pos - _init_pos).length();
   if(_area_of_effect > 0 && distance > _area_of_effect) {
-    LVecBase3f direction = present_pos - _init_pos;
+    LVecBase3 direction = present_pos - _init_pos;
     direction.normalize();
     desired_force =  - direction * _ai_char->_movt_force;
-    LVecBase3f dirn = _ai_char->_steering->_steering_force;
+    LVecBase3 dirn = _ai_char->_steering->_steering_force;
     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;
 }

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

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

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

@@ -1019,11 +1019,6 @@ class Actor(DirectObject, NodePath):
         if (partName in partDict):
             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"):
         """
         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
 base = ShowBase.ShowBase()

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

@@ -1,5 +1,7 @@
 """instantiate global DirectNotify used in Direct"""
 
+__all__ = ['directNotify', 'giveNotify']
+
 import 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 
 # functions referencing it will be listed.
 
-REFERENCED_BY_RELATION = YES
+REFERENCED_BY_RELATION = NO
 
 # If the REFERENCES_RELATION tag is set to YES 
 # then for each documented function all documented entities 
 # 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) 
 # 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:
                 # New paragraph.
                 comment += '\n\n'
+                empty_line = False
             elif comment:
                 comment += '\n'
             comment += '/// ' + line
@@ -56,15 +57,29 @@ def block_comment(code):
 
         line = line.rstrip()
         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)
     if len(newcode) > 0:
@@ -73,6 +88,9 @@ def block_comment(code):
         return ""
 
 def translateFunctionName(name):
+    if name.startswith("__"):
+        return name
+
     new = ""
     for i in name.split("_"):
         if new == "":
@@ -85,32 +103,58 @@ def translateFunctionName(name):
             new += i[0].upper() + i[1:]
     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):
         token = interrogate_type_atomic_token(type)
         if token == 7:
             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):
     if interrogate_element_has_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) + ';'
 
 def processFunction(handle, function, isConstructor = False):
@@ -120,11 +164,12 @@ def processFunction(handle, function, isConstructor = False):
             print >>handle, block_comment(interrogate_wrapper_comment(wrapper))
         
         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):
-                print >>handle, translateTypeSpec(translated_type_name(interrogate_wrapper_return_type(wrapper))),
+                print >>handle, translated_type_name(interrogate_wrapper_return_type(wrapper)),
             else:
                 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 first:
                     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):
                     print >>handle, interrogate_wrapper_parameter_name(wrapper, i_param),
                 first = False
@@ -145,7 +190,7 @@ def processFunction(handle, function, isConstructor = False):
         print >>handle, ");"
 
 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)) ]
     
     if interrogate_type_has_comment(type):
@@ -157,7 +202,7 @@ def processType(handle, type):
             docstring = comment(interrogate_type_enum_value_comment(type, i_value))
             if 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:
         if interrogate_type_is_struct(type):
             classtype = "struct"
@@ -192,38 +237,54 @@ def processType(handle, type):
     
     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__":
     handle = open("pandadoc.hpp", "w")
     
     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
     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"))
 
     import panda3d.core
+    processModule(handle, "core")
 
     for lib in os.listdir(os.path.dirname(panda3d.__file__)):
         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()

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

@@ -491,7 +491,7 @@ class ConnectionRepository(
         elif self.connectMethod == self.CM_NET or (not hasattr(self,"connectNative")):
             # Try each of the servers in turn.
             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):
                     self.startReaderPollTask()
                     if successCallback:
@@ -503,7 +503,7 @@ class ConnectionRepository(
                 failureCallback(0, '', *failureArgs)
         elif self.connectMethod == self.CM_NATIVE:
             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):
                     self.startReaderPollTask()
                     if successCallback:
@@ -536,7 +536,7 @@ class ConnectionRepository(
         if ch.isConnectionReady():
             self.setConnectionHttp(ch)
             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 we have a recorder, we wrap the connect inside a
@@ -562,7 +562,7 @@ class ConnectionRepository(
             # No connection yet, but keep trying.
 
             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.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)
         # TODO: WHAT LOCATION SHOULD WE SET THIS TO?
         #av.reparentTo(hidden)
-        if (av.getParent().compareTo(self) == 0):
+        if av.getParent() == self:
             # only detach if object is directly parented
             av.detachNode()
         #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.
         """
         if not name:
-            name = self.getUrl().cStr()
+            name = str(self.getUrl())
         from direct.task import Task
         task = Task.Task(self.doTask)
         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.
         """
         if not name:
-            name = self.getUrl().cStr()
+            name = str(self.getUrl())
         from direct.task import Task
         task = Task.Task(self.doTask)
         task.callback = callback

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

@@ -16,11 +16,10 @@ clunky approach.  - Josh
 """
 
 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
 
 CARTOON_BODY="""
@@ -348,13 +347,13 @@ class CommonFilters:
         if (changed == "CartoonInk") or fullrebuild:
             if ("CartoonInk" in configuration):
                 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)
 
         if (changed == "BlurSharpen") or fullrebuild:
             if ("BlurSharpen" in configuration):
                 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 ("Bloom" in configuration):
@@ -386,9 +385,9 @@ class CommonFilters:
 
         if "VolumetricLighting" in self.configuration:
             caster = self.configuration["VolumetricLighting"].caster
-            casterpos = Point2()
+            casterpos = LPoint2()
             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:
             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.showbase.DirectObject import DirectObject
 
@@ -111,16 +110,16 @@ class FilterManager(DirectObject):
 
         winx = self.forcex
         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
             winy = winy * mul
 
@@ -198,7 +197,7 @@ class FilterManager(DirectObject):
         quad.setDepthTest(0)
         quad.setDepthWrite(0)
         quad.setTexture(colortex)
-        quad.setColor(Vec4(1,0.5,0.5,1))
+        quad.setColor(1, 0.5, 0.5, 1)
 
         cs = NodePath("dummy")
         cs.setState(self.camstate)
@@ -221,7 +220,7 @@ class FilterManager(DirectObject):
         self.setStackedClears(buffer, self.rclears, self.wclears)
         if (auxtex0):
             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):
             buffer.setClearActive(GraphicsOutput.RTPAuxRgba1, 1)
         self.region.disableClears()
@@ -262,7 +261,7 @@ class FilterManager(DirectObject):
         quad = NodePath(cm.generate())
         quad.setDepthTest(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")
         lens = OrthographicLens()
@@ -294,7 +293,7 @@ class FilterManager(DirectObject):
 
         winprops = WindowProperties()
         winprops.setSize(xsize, ysize)
-        props = FrameBufferProperties(self.win.getFbProperties())
+        props = FrameBufferProperties(FrameBufferProperties.getDefault())
         props.setBackBuffers(0)
         props.setRgbColor(1)
         props.setDepthBits(depthbits)

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

@@ -111,7 +111,7 @@ class LevelEditorBase(DirectObject):
         base.direct.deselect(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
             # removed obj, clear the reference
             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
         # move to multiple-instance sessions, it may have to be
         # 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
         # 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
         # it to its actual filename, to avoid race conditions when
         # updating this file.
-        tfile = Filename.temporary(self.rootDir.cStr(), '.xml')
+        tfile = Filename.temporary(str(self.rootDir), '.xml')
         if doc.SaveFile(tfile.toOsSpecific()):
             tfile.renameTo(filename)
 

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

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

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

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

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

@@ -1066,7 +1066,7 @@ class PackageInfo:
             return False
 
         # We mount it under its actual location on disk.
-        root = self.getPackageDir().cStr()
+        root = self.getPackageDir()
 
         vfs = VirtualFileSystem.getGlobalPtr()
         vfs.mount(mf, root, vfs.MFReadOnly)
@@ -1210,7 +1210,7 @@ class PackageInfo:
         # Write the file to a temporary filename, then atomically move
         # it to its actual filename, to avoid race conditions when
         # updating this file.
-        tfile = Filename.temporary(self.getPackageDir().cStr(), '.xml')
+        tfile = Filename.temporary(str(self.getPackageDir()), '.xml')
         if doc.SaveFile(tfile.toOsSpecific()):
             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/local/lib')
 
-        if os.uname()[1] == "pcbsd":
+        if self.platform.startswith('freebsd') and os.uname()[1] == "pcbsd":
             self.executablePath.appendDirectory('/usr/PCBSD/local/lib')
 
         # 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
             # documentation purposes.
 
-            importDescFilename = self.packageDesc.cStr()[:-3] + 'import.xml'
+            importDescFilename = str(self.packageDesc)[:-3] + 'import.xml'
             importDescFullpath = Filename(self.patchMaker.installDir, importDescFilename)
             doc = TiXmlDocument(importDescFullpath.toOsSpecific())
             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
             # disk space.
             xusage.SetAttribute('disk_space', str(self.getTotalSize()))
-            tfile = Filename.temporary(pathname.cStr(), '.xml')
+            tfile = Filename.temporary(str(pathname), '.xml')
             if doc.SaveFile(tfile.toOsSpecific()):
                 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,
 // instead of the dynamic runtime library, which is much better for
 // 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]
 
@@ -114,8 +113,8 @@
 // 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 LIB_PREFIX
   #define BUILDING_DLL BUILDING_P3D_PLUGIN
@@ -141,8 +140,8 @@
 // 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 BUILDING_DLL BUILDING_P3D_PLUGIN
 

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

@@ -16,10 +16,10 @@
 #include "wstring_encode.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 <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:
     strncpy(header, "Unverified signature!", hlen);
-    snprintf(text, tlen, unknown_auth_cert_text, _friendly_name.c_str());
+    snprintf(text, tlen, unknown_auth_cert_text);
     break;
 
   case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:

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

@@ -15,8 +15,8 @@
 #ifndef 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
 #include "openssl/x509.h"

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

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

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

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

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

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

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

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

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

@@ -19,10 +19,7 @@
 #include "virtualFileSystem.h"
 #include "nativeWindowHandle.h"
 
-#ifndef CPPPARSER
 #include "py_panda.h"
-IMPORT_THIS struct Dtool_PyTypedObject Dtool_WindowHandle;
-#endif
 
 // There is only one P3DPythonRun object in any given process space.
 // 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
   // 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) {
     PyErr_Print();
     return false;
   }
   Py_DECREF(result);
-  Py_DECREF(request_func);
-
 
   // 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
@@ -326,14 +321,14 @@ run_python() {
     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
   // taskMgr.run()).
@@ -603,10 +598,8 @@ handle_pyobj_command(TiXmlElement *xcommand, bool needs_response,
         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) {
       // 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);
 
   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);
-  Py_DECREF(main);
 
   if (result == NULL) {
     PyErr_Print();
@@ -1331,11 +1323,9 @@ set_p3d_filename(P3DCInstance *inst, TiXmlElement *xfparams) {
   }
 
   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,
      p3d_url.c_str());
-  Py_DECREF(token_list);
-  Py_DECREF(arg_list);
 
   if (result == NULL) {
     PyErr_Print();
@@ -1425,18 +1415,16 @@ setup_window(P3DCInstance *inst, TiXmlElement *xwparams) {
     // setupWindow() call.  For this, we need to create a Python
     // wrapper objcet.
     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);
 
   // TODO: direct this into the particular instance.  This will
   // require a specialized ShowBase replacement.
   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);
 
-  Py_DECREF(py_handle);
-
   if (result == NULL) {
     PyErr_Print();
     if (_interactive_console) {

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

@@ -27,7 +27,6 @@
 #include "handleStream.h"
 #include "p3dCInstance.h"
 #include "pandaFileStreamBuf.h"
-#include "pythonTask.h"
 #include "pmap.h"
 #include "pdeque.h"
 #include "pmutex.h"
@@ -173,8 +172,6 @@ private:
   PyObject *_browser_object_class;
   PyObject *_taskMgr;
 
-  PT(PythonTask) _check_comm_task;
-
   // This map keeps track of the PyObject pointers we have delivered
   // 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

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

@@ -15,30 +15,11 @@
 #include "p3dSplashWindow.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
 // 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.
 ////////////////////////////////////////////////////////////////////
 P3DSplashWindow::
-P3DSplashWindow(P3DInstance *inst, bool make_visible) : 
+P3DSplashWindow(P3DInstance *inst, bool make_visible) :
   _inst(inst),
   _fparams(inst->get_fparams()),
   _wparams(inst->get_wparams())
@@ -82,7 +63,7 @@ P3DSplashWindow(P3DInstance *inst, bool make_visible) :
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DSplashWindow::Destructor
 //       Access: Public, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 P3DSplashWindow::
 ~P3DSplashWindow() {
@@ -259,191 +240,25 @@ read_image_data(ImageData &image, string &data,
     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;
   }
 
-  /* 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;
 }
 
@@ -479,7 +294,7 @@ set_button_range(const ImageData &image) {
   // But it can't be larger than the window itself.
   _button_width = min(_button_width, _win_width);
   _button_height = min(_button_height, _win_height);
-      
+
   // Compute the top-left corner of the button image in window
   // coordinates.
   _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,
                        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,
                          int &bar_width, int &bar_height);
   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;
 
   // Go read the image.
-  string data;
   if (!read_image_data(image, image._data, image._filename)) {
     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::
 eval(const string &expression) const {
-  NPString npexpr = { expression.c_str(), expression.length() };
+  NPString npexpr = { expression.c_str(), (uint32_t)expression.length() };
 
   NPVariant result;
-  if (!browser->evaluate(_instance->get_npp_instance(), _npobj, 
+  if (!browser->evaluate(_instance->get_npp_instance(), _npobj,
                          &npexpr, &result)) {
     // Failed to eval.
     return NULL;

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

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

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

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

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

@@ -83,7 +83,6 @@
 #end bin_target
 
 #begin bin_target
-  #define BUILD_TARGET $[and $[HAVE_JPEG],$[HAVE_PNG]]
   #define USE_PACKAGES openssl zlib
   #define TARGET p3dembed
   #define LOCAL_LIBS plugin_common p3d_plugin_static
@@ -115,7 +114,7 @@
   // On Windows, we also need to build p3dembedw.exe, the non-console
   // 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 TARGET p3dembedw
   #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
   // call out to our instances and getters, rather than polling within
   // 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
 //       Access: Protected, Static
@@ -712,7 +712,7 @@ st_timer_callback(EventLoopTimerRef timer, void *user_data) {
 }
 #endif  // __APPLE__
 
-#ifdef __APPLE__
+#if defined(__APPLE__) && !__LP64__
 ////////////////////////////////////////////////////////////////////
 //     Function: Panda3DBase::timer_callback
 //       Access: Protected

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

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

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

@@ -187,3 +187,8 @@ class EventManager:
 
     def shutdown(self):
         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
 
 # 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 direct.showbase import PythonUtil
 #from direct.interval.IntervalManager import ivalMgr
@@ -29,11 +29,11 @@ from direct.showbase.BufferViewer import BufferViewer
 from direct.task import Task
 from direct.directutil import Verify
 from direct.showbase import GarbageReport
-import EventManager
 import math,sys,os
 import Loader
 import time
 import gc
+import atexit
 from direct.fsm import ClassicFSM
 from direct.fsm import State
 from direct.showbase import ExceptionVarDump
@@ -44,9 +44,17 @@ if __debug__:
 import OnScreenDebug
 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
 # 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):
         self.__dev__ = config.GetBool('want-dev', __debug__)
-        __builtin__.__dev__ = self.__dev__
+        builtins.__dev__ = self.__dev__
 
         logStackDump = (config.GetBool('log-stack-dump', False) or
                         config.GetBool('client-log-stack-dump', False))
@@ -65,11 +73,12 @@ class ShowBase(DirectObject.DirectObject):
         if logStackDump or 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")
 
-        # 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
 
         #debug running multiplier
@@ -108,13 +117,13 @@ class ShowBase(DirectObject.DirectObject):
         self.wantTk = 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
 
-        # 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 = []
 
         Task.TaskManager.taskTimerVerbose = self.config.GetBool('task-timer-verbose', 0)
@@ -139,13 +148,15 @@ class ShowBase(DirectObject.DirectObject):
         # we get a window-event.
         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
         if self.windowType is None:
             self.windowType = self.config.GetString('window-type', 'onscreen')
         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.frameRateMeter = None
         self.sceneGraphAnalyzerMeter = None
@@ -165,17 +176,29 @@ class ShowBase(DirectObject.DirectObject):
         self.trackball = None
         self.texmem = 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.cam2d = 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.camera2d = None
         self.camera2dp = None
+
+        ## This is a list of all cameras created with makeCamera, including base.cam.
         self.camList = []
+        ## Convenience accessor for base.cam.node()
         self.camNode = None
+        ## Convenience accessor for base.camNode.get_lens()
         self.camLens = None
         self.camFrustumVis = 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.tkRoot = None
 
@@ -189,6 +212,7 @@ class ShowBase(DirectObject.DirectObject):
 
         self.hidden = NodePath('hidden')
 
+        ## The global graphics engine, ie. GraphicsEngine.getGlobalPtr()
         self.graphicsEngine = GraphicsEngine.getGlobalPtr()
         self.setupRender()
         self.setupRender2d()
@@ -198,11 +222,11 @@ class ShowBase(DirectObject.DirectObject):
             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.shadowTrav = 0
         self.cTravStack = Stack()
         # Ditto for an AppTraverser.
         self.appTrav = 0
@@ -233,10 +257,6 @@ class ShowBase(DirectObject.DirectObject):
             random.seed(seed)
             #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.
         if self.windowType != 'none':
             props = WindowProperties.getDefault()
@@ -254,17 +274,22 @@ class ShowBase(DirectObject.DirectObject):
         self.loader = Loader.Loader(self)
         self.graphicsEngine.setDefaultLoader(self.loader.loader)
 
+        ## The global event manager, as imported from EventManagerGlobal.
         self.eventMgr = eventMgr
+        ## The global messenger, as imported from MessengerGlobal.
         self.messenger = messenger
+        ## The global bulletin board, as imported from BulletinBoardGlobal.
         self.bboard = bulletinBoard
+        ## The global task manager, as imported from TaskManagerGlobal.
         self.taskMgr = taskMgr
+        ## The global job manager, as imported from JobManagerGlobal.
         self.jobMgr = jobMgr
 
-        # Particle manager
+        ## Particle manager
         self.particleMgr = None
         self.particleMgrEnabled = 0
 
-        # Physics manager
+        ## Physics manager
         self.physicsMgr = None
         self.physicsMgrEnabled = 0
         self.physicsMgrAngular = 0
@@ -302,8 +327,8 @@ class ShowBase(DirectObject.DirectObject):
             # assigned to a single CPU
             autoAffinity = self.config.GetBool('auto-single-cpu-affinity', 0)
             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:
                 affinity = self.config.GetInt('client-cpu-affinity', -1)
             if (affinity in (None, -1)) and autoAffinity:
@@ -313,42 +338,44 @@ class ShowBase(DirectObject.DirectObject):
                 TrueClock.getGlobalPtr().setCpuAffinity(1 << (affinity % 32))
 
         # 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!"
 
-        __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
-        #__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__:
-            __builtin__.deltaProfiler = DeltaProfiler.DeltaProfiler("ShowBase")
-        __builtin__.onScreenDebug = OnScreenDebug.OnScreenDebug()
+            builtins.deltaProfiler = DeltaProfiler.DeltaProfiler("ShowBase")
+        builtins.onScreenDebug = OnScreenDebug.OnScreenDebug()
 
         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__:
             ShowBase.notify.debug('__dev__ == %s' % __dev__)
@@ -426,7 +453,7 @@ class ShowBase(DirectObject.DirectObject):
         self.cTrav = self.cTravStack.pop()
 
     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. """
 
         try:
@@ -445,8 +472,7 @@ class ShowBase(DirectObject.DirectObject):
         return 0
 
     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
         add stuff to this.
         """
@@ -470,11 +496,18 @@ class ShowBase(DirectObject.DirectObject):
         for cb in self.finalExitCallbacks[:]:
             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
         if self.config.GetBool('disable-sticky-keys', 0):
             allowAccessibilityShortcutKeys(True)
 
-        taskMgr.destroy()
+        self.ignoreAll()
+        self.shutdown()
 
         if getattr(self, 'musicManager', None):
             self.musicManager.shutdown()
@@ -501,19 +534,6 @@ class ShowBase(DirectObject.DirectObject):
         vfs = VirtualFileSystem.getGlobalPtr()
         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):
         """
         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
         rendering 3-d geometry.
         """
+        ## This is the root of the 3-D scene graph.
         self.render = NodePath('render')
         self.render.setAttrib(RescaleNormalAttrib.makeDefault())
 
@@ -1037,6 +1058,7 @@ class ShowBase(DirectObject.DirectObject):
         2-d objects and gui elements that are superimposed over the
         3-d geometry in the window.
         """
+        ## This is the root of the 2-D scene graph.
         self.render2d = NodePath('render2d')
 
         # Set up some overrides to turn off certain properties which
@@ -1057,22 +1079,26 @@ class ShowBase(DirectObject.DirectObject):
         self.render2d.setMaterialOff(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"))
+
+        aspectRatio = self.getAspectRatio()
         self.aspect2d.setScale(1.0 / aspectRatio, 1.0, 1.0)
 
         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
+        ## The Z position of the bottom border of the aspect2d screen.
         self.a2dBottom = -1.0
+        ## The X position of the left border of the aspect2d screen.
         self.a2dLeft = -aspectRatio
+        ## The X position of the right border of the aspect2d screen.
         self.a2dRight = aspectRatio
 
         self.a2dTopCenter = self.aspect2d.attachNewNode("a2dTopCenter")
@@ -1112,12 +1138,12 @@ class ShowBase(DirectObject.DirectObject):
         self.a2dBottomRight.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.setPos(-1, 0, 1)
+        xsize, ysize = self.getSize()
         if xsize > 0 and ysize > 0:
             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.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.node().setStartSort(16384)
+
+        aspectRatio = self.getAspectRatio()
         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
+        ## The Z position of the bottom border of the aspect2dp screen.
         self.a2dpBottom = -1.0
+        ## The X position of the left border of the aspect2dp screen.
         self.a2dpLeft = -aspectRatio
+        ## The X position of the right border of the aspect2dp screen.
         self.a2dpRight = aspectRatio
 
-
         self.a2dpTopCenter = self.aspect2dp.attachNewNode("a2dpTopCenter")
         self.a2dpBottomCenter = self.aspect2dp.attachNewNode("a2dpBottomCenter")
         self.a2dpLeftCenter = self.aspect2dp.attachNewNode("a2dpLeftCenter")
@@ -1184,13 +1212,13 @@ class ShowBase(DirectObject.DirectObject):
         self.a2dpBottomLeft.setPos(self.a2dpLeft, 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.node().setStartSort(16384)
         self.pixel2dp.setPos(-1, 0, 1)
+        xsize, ysize = self.getSize()
         if xsize > 0 and ysize > 0:
             self.pixel2dp.setScale(2.0 / xsize, 1.0, 2.0 / ysize)
 
@@ -1280,7 +1308,7 @@ class ShowBase(DirectObject.DirectObject):
             # camera.
             self.camera = self.render.attachNewNode(ModelNode('camera'))
             self.camera.node().setPreserveTransform(ModelNode.PTLocal)
-            __builtin__.camera = self.camera
+            builtins.camera = self.camera
 
             self.mouse2cam.node().setNode(self.camera.node())
 
@@ -1502,12 +1530,14 @@ class ShowBase(DirectObject.DirectObject):
             np = mw.getParent().attachNewNode(mouseRecorder)
             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()
+
+        ## 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.node().setPrefix('time-')
         self.timeButtonThrower.node().setTimeFlag(1)
@@ -1931,7 +1961,7 @@ class ShowBase(DirectObject.DirectObject):
         throw_new_frame()
         return Task.cont
 
-    def restart(self,clusterSync=False,cluster=None):
+    def restart(self, clusterSync=False, cluster=None):
         self.shutdown()
         # __resetPrevTransform goes at the very beginning of the frame.
         self.taskMgr.add(
@@ -1970,7 +2000,7 @@ class ShowBase(DirectObject.DirectObject):
         self.taskMgr.remove('dataLoop')
         self.taskMgr.remove('resetPrevTransform')
         self.taskMgr.remove('ivalLoop')
-        self.taskMgr.remove('garbage_collect')
+        self.taskMgr.remove('garbageCollectStates')
         self.eventMgr.shutdown()
 
     def getBackgroundColor(self, win = None):
@@ -2784,7 +2814,7 @@ class ShowBase(DirectObject.DirectObject):
             # wx is now the main loop, not us any more.
             self.run = self.wxRun
             self.taskMgr.run = self.wxRun
-            __builtin__.run = self.wxRun
+            builtins.run = self.wxRun
             if self.appRunner:
                 self.appRunner.run = self.wxRun
 
@@ -2846,7 +2876,7 @@ class ShowBase(DirectObject.DirectObject):
 
         # Create a new Tk root.
         self.tkRoot = Pmw.initialise()
-        __builtin__.tkroot = self.tkRoot
+        builtins.tkroot = self.tkRoot
 
         init_app_for_gui()
 
@@ -2863,7 +2893,7 @@ class ShowBase(DirectObject.DirectObject):
             # wx is now the main loop, not us any more.
             self.run = self.tkRun
             self.taskMgr.run = self.tkRun
-            __builtin__.run = self.tkRun
+            builtins.run = self.tkRun
             if self.appRunner:
                 self.appRunner.run = self.tkRun
 
@@ -2908,7 +2938,7 @@ class ShowBase(DirectObject.DirectObject):
             from direct.directtools import DirectSession
             base.direct.enable()
         else:
-            __builtin__.direct = self.direct = None
+            builtins.direct = self.direct = None
 
     def getRepository(self):
         return None
@@ -2931,11 +2961,12 @@ class ShowBase(DirectObject.DirectObject):
         self.startDirect(fWantDirect = fDirect, fWantTk = fTk, fWantWx = fWx)
 
     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 \
            (self.appRunner.interactiveConsole and not self.appRunner.initialAppImport):
             self.taskMgr.run()

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

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

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

@@ -1174,7 +1174,7 @@ class Freezer:
                 source = open(sourceFilename.toOsSpecific(), 'r').read()
                 if source and source[-1] != '\n':
                     source = source + '\n'
-                code = compile(source, sourceFilename.cStr(), 'exec')
+                code = compile(source, str(sourceFilename), 'exec')
 
         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
 are three pieces:
 
-    1. Source code from Sourceforge.
+    1. Source code from Github.
     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:
 
-    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
-    samples	- piece 3, sample programs
+
 
 If you have all of these, you're ready to go.  If not, then you
 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)
   --verbose         (print out more information)
+  --runtime         (build a runtime build instead of an SDK build)
   --installer       (build an installer)
   --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)
   --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)
+  --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-maya65      --no-maya65    (enable/disable use of MAYA65)
   --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-maya2009    --no-maya2009  (enable/disable use of MAYA2009)
   --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-max7        --no-max7      (enable/disable use of MAX7)
   --use-max8        --no-max8      (enable/disable use of MAX8)
   --use-max9        --no-max9      (enable/disable use of MAX9)
   --use-max2009     --no-max2009   (enable/disable use of MAX2009)
   --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-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-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-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-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-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-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)
   --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
 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
 situation, we recommend that you write a short script containing the
 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:
 
 	@echo off
-	makepanda --everything --no-helix
+	makepanda --everything --no-eigen
 
 This helps me avoid accidentally typing makepanda with the wrong
 options.

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

@@ -21,7 +21,7 @@
 #include "cppClassTemplateParameter.h"
 #include "cppTemplateParameterList.h"
 #include "cppInstanceIdentifier.h"
-#include "cppTypedef.h"
+#include "cppTypedefType.h"
 #include "cppTypeDeclaration.h"
 #include "cppVisibility.h"
 #include "cppIdentifier.h"
@@ -241,7 +241,8 @@ pop_struct() {
 %token KW_BOOL
 %token KW_CATCH
 %token KW_CHAR
-%token KW_WCHAR_T
+%token KW_CHAR16_T
+%token KW_CHAR32_T
 %token KW_CLASS
 %token KW_CONST
 %token KW_DELETE
@@ -294,6 +295,7 @@ pop_struct() {
 %token KW_VIRTUAL
 %token KW_VOID
 %token KW_VOLATILE
+%token KW_WCHAR_T
 %token KW_WHILE
 
 /* 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.struct_type> anonymous_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> struct_keyword
 %type <u.simple_type> simple_type
@@ -334,6 +335,7 @@ pop_struct() {
 %type <u.simple_type> simple_float_type
 %type <u.simple_type> simple_void_type
 %type <u.type> class_derivation_name
+%type <u.type> enum_element_type
 /*%type <u.type> typedefname*/
 %type <u.identifier> name
 %type <str> string
@@ -353,7 +355,7 @@ pop_struct() {
 
 /* 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 '{' ',' ';'
 
@@ -493,17 +495,21 @@ declaration:
   CPPDeclaration *getter = $5->find_symbol(current_scope, global_scope, current_lexer);
   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);
-  }
 
-  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 ')' ';'
 {
@@ -717,7 +723,8 @@ typedef_declaration:
     if (inst != (CPPInstance *)NULL) {
       inst->_storage_class |= (current_storage_class | $1);
       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:
         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
 {
-  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
 {
   $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
 {
   $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);
 }
-        | anonymous_enum
-{
-  $$ = CPPType::new_type($1);
-}
-        | named_enum
+        | enum
 {
   $$ = CPPType::new_type($1);
 }
@@ -1609,7 +1604,7 @@ type:
     $$ = et;
   }
 }
-        | enum_keyword name
+        | enum_keyword name ':' enum_element_type
 {
   CPPType *type = $2->find_type(current_scope, global_scope, false, current_lexer);
   if (type != NULL) {
@@ -1649,11 +1644,7 @@ type_decl:
 {
   $$ = new CPPTypeDeclaration(CPPType::new_type($1));
 }
-        | anonymous_enum
-{
-  $$ = CPPType::new_type($1);
-}
-        | named_enum
+        | enum
 {
   $$ = new CPPTypeDeclaration(CPPType::new_type($1));
 }
@@ -1672,9 +1663,27 @@ type_decl:
     }
     $$ = 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
 {
+  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);
   if (type != NULL) {
     $$ = 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 = 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);
 }
-        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
 {
   $$ = 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
 {
@@ -2132,7 +2163,8 @@ element:
         | SCOPE | PLUSPLUS | MINUSMINUS
         | TIMESEQUAL | DIVIDEEQUAL | MODEQUAL | PLUSEQUAL | MINUSEQUAL
         | 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_EXTERN | KW_EXPLICIT | KW_FALSE
         | KW_FLOAT | KW_FRIEND | KW_FOR | KW_GOTO
@@ -2369,6 +2401,18 @@ const_expr:
   CPPType *type =
     CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_wchar_t));
   $$ = 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 ')'
 {

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

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

@@ -13,7 +13,7 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "cppEnumType.h"
-#include "cppTypedef.h"
+#include "cppTypedefType.h"
 #include "cppExpression.h"
 #include "cppSimpleType.h"
 #include "cppConstType.h"
@@ -24,14 +24,37 @@
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPEnumType::Constructor
 //       Access: Public
-//  Description:
+//  Description: Creates an untyped, unscoped enum.
 ////////////////////////////////////////////////////////////////////
 CPPEnumType::
 CPPEnumType(CPPIdentifier *ident, CPPScope *current_scope,
             const CPPFile &file) :
   CPPExtensionType(T_enum, ident, current_scope, file),
+  _parent_scope(current_scope),
+  _element_type(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::
 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);
-  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);
 
   if (value == (CPPExpression *)NULL) {
@@ -81,6 +116,38 @@ is_incomplete() const {
   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
 //       Access: Public, Virtual
@@ -95,12 +162,34 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
   }
 
   CPPEnumType *rep = new CPPEnumType(*this);
+
   if (_ident != NULL) {
     rep->_ident =
       _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;
     rep = this;
   }
@@ -124,15 +213,14 @@ output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
     }
     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 {
     out << _type;
     if (_ident != NULL) {
       out << " " << _ident->get_local_name(scope);
     }
+    if (_element_type != NULL) {
+      out << " : " << _element_type->get_local_name(scope);
+    }
 
     out << " {\n";
     Elements::const_iterator ei;

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

@@ -34,12 +34,15 @@ class CPPEnumType : public CPPExtensionType {
 public:
   CPPEnumType(CPPIdentifier *ident, CPPScope *current_scope,
               const CPPFile &file);
+  CPPEnumType(CPPIdentifier *ident, CPPType *element_type,
+              CPPScope *current_scope, const CPPFile &file);
 
   CPPInstance *add_element(const string &name,
                            CPPExpression *value = (CPPExpression *)NULL);
 
   virtual bool is_incomplete() const;
 
+  virtual bool is_fully_specified() const;
   virtual CPPDeclaration *substitute_decl(SubstDecl &subst,
                                           CPPScope *current_scope,
                                           CPPScope *global_scope);
@@ -50,6 +53,9 @@ public:
 
   virtual CPPEnumType *as_enum_type();
 
+  CPPScope *_parent_scope;
+  CPPType *_element_type;
+
   typedef vector<CPPInstance *> Elements;
   Elements _elements;
   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
 //       Access: Public
@@ -226,7 +250,7 @@ CPPExpression(CPPIdentifier *ident, CPPScope *current_scope,
   CPPDeclaration(CPPFile())
 {
   CPPDeclaration *decl =
-    ident->find_symbol(current_scope, global_scope, error_sink);
+    ident->find_symbol(current_scope, global_scope);
 
   if (decl != NULL) {
     CPPInstance *inst = decl->as_instance();
@@ -245,6 +269,7 @@ CPPExpression(CPPIdentifier *ident, CPPScope *current_scope,
 
   _type = T_unknown_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.
 }
 
+////////////////////////////////////////////////////////////////////
+//     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
 //       Access: Public, Virtual
@@ -827,6 +912,7 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
         // Replacing the variable reference with another variable reference.
         rep->_u._variable = decl->as_instance();
         any_changed = true;
+
       } else if (decl->as_expression()) {
         // Replacing the variable reference with an expression.
         delete rep;
@@ -836,6 +922,43 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
     }
     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_construct:
   case T_new:
@@ -909,6 +1032,9 @@ is_tbd() const {
 
     return true;
 
+  case T_unknown_ident:
+    return true;
+
   case T_typecast:
   case T_construct:
   case T_new:
@@ -996,8 +1122,12 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
     break;
 
   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 &&
-        _u._variable->_initializer != NULL) {
+        _u._variable->_initializer != NULL &&
+        _u._variable->_vis > V_public) {
       // A const variable.  Fetch its assigned value.
       CPPConstType *const_type = _u._variable->_type->as_const_type();
       if (const_type != NULL) {
@@ -1434,4 +1564,3 @@ is_less(const CPPDeclaration *other) const {
 
   return false;
 }
-

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

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

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

@@ -14,7 +14,7 @@
 
 
 #include "cppExtensionType.h"
-#include "cppTypedef.h"
+#include "cppTypedefType.h"
 #include "cppIdentifier.h"
 #include "cppParser.h"
 #include "indent.h"
@@ -130,6 +130,29 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
   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

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

@@ -25,7 +25,9 @@ class CPPIdentifier;
 
 ///////////////////////////////////////////////////////////////////
 //       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 {
 public:
@@ -50,6 +52,9 @@ public:
                                           CPPScope *current_scope,
                                           CPPScope *global_scope);
 
+  virtual CPPType *resolve_type(CPPScope *current_scope,
+                                CPPScope *global_scope);
+
   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:
 ////////////////////////////////////////////////////////////////////
 CPPIdentifier::
-CPPIdentifier(const CPPNameComponent &name) {
+CPPIdentifier(const CPPNameComponent &name, const CPPFile &file) : _file(file) {
   _names.push_back(name);
   _native_scope = (CPPScope *)NULL;
 }
@@ -146,8 +146,10 @@ get_local_name(CPPScope *scope) const {
 
   if (scope == NULL || (_native_scope == NULL && _names.size() == 1)) {
     result = _names.back().get_name_with_templ(scope);
+
   } else if (_names.front().empty()) {
     result = get_fully_scoped_name();
+
   } else {
     // Determine the scope of everything up until but not including the
     // last name.
@@ -382,6 +384,7 @@ find_type(CPPScope *current_scope, CPPScope *global_scope,
   if (scope == NULL) {
     return NULL;
   }
+
   CPPType *type = scope->find_type(get_simple_name(), subst, global_scope);
   if (type != NULL && _names.back().has_templ()) {
     // This is a template type.
@@ -398,7 +401,6 @@ find_type(CPPScope *current_scope, CPPScope *global_scope,
       assert(new_type != NULL);
       if (new_type == type) {
         type = CPPType::new_type(new CPPTBDType((CPPIdentifier *)this));
-        //      type = new_type;
       } else {
         type = new_type;
       }
@@ -424,12 +426,50 @@ find_symbol(CPPScope *current_scope, CPPScope *global_scope,
   if (scope == 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;
   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()) {

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

@@ -36,7 +36,7 @@ class CPPTemplateParameterList;
 class CPPIdentifier {
 public:
   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 CPPNameComponent &name);
 
@@ -69,6 +69,10 @@ public:
   CPPDeclaration *find_symbol(CPPScope *current_scope,
                               CPPScope *global_scope,
                               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,
                                 CPPScope *global_scope,
                                 CPPPreprocessor *error_sink = NULL) const;

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

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

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

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

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

@@ -200,6 +200,7 @@ CPPPreprocessor() {
 
   _warning_count = 0;
   _error_count = 0;
+  _error_abort = false;
 #ifdef CPP_VERBOSE_LEX
   _token_index = 0;
 #endif
@@ -404,8 +405,7 @@ get_next_token0() {
 
     int token_type = IDENTIFIER;
     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;
     }
 
@@ -432,10 +432,14 @@ warning(const string &message, int line, int col, CPPFile file) {
     if (file.empty()) {
       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
       << " near line " << line << ", column " << col << ":\n";
-    indent(cerr, _files.size() * 2)
+    indent(cerr, indent_level)
       << message << "\n";
   }
   _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
     // reported when the nesting level collapses.
     return;
-  };
+  }
 
   if (_verbose >= 1) {
     if (line == 0) {
@@ -462,11 +466,20 @@ error(const string &message, int line, int col, CPPFile file) {
     if (file.empty()) {
       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
       << " near line " << line << ", column " << col << ":\n";
-    indent(cerr, _files.size() * 2)
+    indent(cerr, indent_level)
       << message << "\n";
+
+    if (_error_abort) {
+      cerr << "Aborting.\n";
+      abort();
+    }
   }
   _error_count++;
 }
@@ -603,7 +616,7 @@ init_type(const string &type) {
 ////////////////////////////////////////////////////////////////////
 bool CPPPreprocessor::
 push_file(const CPPFile &file) {
-  if (_verbose >= 2) {
+  if (_verbose >= 3) {
     indent(cerr, _files.size() * 2)
       << "Reading " << file << "\n";
   }
@@ -2009,7 +2022,8 @@ check_keyword(const string &name) {
   if (name == "bool") return KW_BOOL;
   if (name == "catch") return KW_CATCH;
   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 == "const") return KW_CONST;
   if (name == "delete") return KW_DELETE;
@@ -2061,6 +2075,7 @@ check_keyword(const string &name) {
   if (name == "virtual") return KW_VIRTUAL;
   if (name == "void") return KW_VOID;
   if (name == "volatile") return KW_VOLATILE;
+  if (name == "wchar_t") return KW_WCHAR_T;
   if (name == "while") return KW_WHILE;
 
   // These are alternative ways to refer to built-in operators.
@@ -2287,7 +2302,6 @@ unget(int c) {
   _unget = c;
 }
 
-
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPPreprocessor::nested_parse_template_instantiation
 //       Access: Private

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

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

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

@@ -16,7 +16,7 @@
 #include "cppScope.h"
 #include "cppDeclaration.h"
 #include "cppNamespace.h"
-#include "cppTypedef.h"
+#include "cppTypedefType.h"
 #include "cppTypeDeclaration.h"
 #include "cppExtensionType.h"
 #include "cppInstance.h"
@@ -136,7 +136,7 @@ add_declaration(CPPDeclaration *decl, CPPScope *global_scope,
 
   _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:
 ////////////////////////////////////////////////////////////////////
 void CPPScope::
-define_extension_type(CPPExtensionType *type) {
+define_extension_type(CPPExtensionType *type, CPPPreprocessor *error_sink) {
   assert(type != NULL);
-  string name = type->get_simple_name();
+  string name = type->get_local_name(this);
+  if (name.empty()) {
+    return;
+  }
 
   switch (type->_type) {
   case CPPExtensionType::T_class:
@@ -200,34 +203,59 @@ define_extension_type(CPPExtensionType *type) {
 
   case CPPExtensionType::T_union:
     _unions[name] = type;
+    break;
 
   case CPPExtensionType::T_enum:
     _enums[name] = type;
+    break;
   }
 
   // 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) {
     // 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()) {
+    string simple_name = type->get_simple_name();
+
     pair<Templates::iterator, bool> result =
-      _templates.insert(Templates::value_type(name, type));
+      _templates.insert(Templates::value_type(simple_name, type));
 
     if (!result.second) {
       // The template was not inserted because we already had a
@@ -277,7 +305,7 @@ add_using(CPPUsing *using_decl, CPPScope *global_scope,
   } else {
     CPPDeclaration *decl = using_decl->_ident->find_symbol(this, global_scope);
     if (decl != NULL) {
-      handle_declaration(decl, global_scope);
+      handle_declaration(decl, global_scope, error_sink);
     } else {
       if (error_sink != NULL) {
         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);
       CPPClassTemplateParameter *ctp = decl->as_class_template_parameter();
       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::
 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;
@@ -509,11 +539,11 @@ find_type(const string &name, bool recurse) const {
 CPPType *CPPScope::
 find_type(const string &name, CPPDeclaration::SubstDecl &subst,
           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;
-    return (*ti).second->_type->substitute_decl
+    return (*ti).second->substitute_decl
       (subst, current_scope, global_scope)->as_type();
   }
 
@@ -562,10 +592,14 @@ find_scope(const string &name, bool recurse) const {
 
   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) {
     CPPStructType::Derivation::const_iterator di;
@@ -613,10 +647,17 @@ find_scope(const string &name, CPPDeclaration::SubstDecl &subst,
   if (type == 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();
   if (st == NULL) {
     return NULL;
   }
+
   return st->_scope;
 }
 
@@ -631,10 +672,10 @@ find_symbol(const string &name, bool recurse) const {
     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;
@@ -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 {
     return _name.get_name_with_templ();
   }
@@ -816,8 +862,7 @@ write(ostream &out, int indent_level, CPPScope *scope) const {
     }
     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;
     }
 
@@ -880,7 +925,7 @@ copy_substitute_decl(CPPScope *to_scope, CPPDeclaration::SubstDecl &subst,
     }
     to_scope->_struct_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);
     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) {
       anything_changed = true;
     }
@@ -999,6 +1044,19 @@ copy_substitute_decl(CPPScope *to_scope, CPPDeclaration::SubstDecl &subst,
     CPPInstance *inst =
       (*vi).second->substitute_decl(subst, to_scope, global_scope)->as_instance();
     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) {
       anything_changed = true;
     }
@@ -1026,25 +1084,41 @@ copy_substitute_decl(CPPScope *to_scope, CPPDeclaration::SubstDecl &subst,
 //               functions, or whatever.
 ////////////////////////////////////////////////////////////////////
 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) {
     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();
     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;
   }
 
@@ -1052,7 +1126,7 @@ handle_declaration(CPPDeclaration *decl, CPPScope *global_scope) {
   if (typedecl != (CPPTypeDeclaration *)NULL) {
     CPPExtensionType *et = typedecl->_type->as_extension_type();
     if (et != NULL) {
-      define_extension_type(et);
+      define_extension_type(et, error_sink);
     }
     return;
   }
@@ -1061,6 +1135,13 @@ handle_declaration(CPPDeclaration *decl, CPPScope *global_scope) {
   if (inst != NULL) {
     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();
     if (!name.empty() && inst->get_scope(this, global_scope) == this) {
       if (inst->_type->as_function_type()) {
@@ -1107,6 +1188,6 @@ handle_declaration(CPPDeclaration *decl, CPPScope *global_scope) {
 
   CPPExtensionType *et = decl->as_extension_type();
   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 CPPNamespace;
 class CPPUsing;
-class CPPTypedef;
+class CPPTypedefType;
 class CPPInstance;
 class CPPFunctionGroup;
 class CPPTemplateScope;
@@ -66,7 +66,8 @@ public:
   virtual void add_enum_value(CPPInstance *inst,
                               CPPPreprocessor *preprocessor,
                               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 add_using(CPPUsing *using_decl, CPPScope *global_scope,
                          CPPPreprocessor *error_sink = NULL);
@@ -113,7 +114,8 @@ private:
   copy_substitute_decl(CPPScope *to_scope, CPPDeclaration::SubstDecl &subst,
                        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:
   typedef vector<CPPDeclaration *> Declarations;
@@ -128,8 +130,8 @@ public:
   typedef map<string, CPPNamespace *> Namespaces;
   Namespaces _namespaces;
 
-  typedef map<string, CPPTypedef *> Typedefs;
-  Typedefs _typedefs;
+  typedef map<string, CPPType *> Types;
+  Types _types;
   typedef map<string, CPPInstance *> Variables;
   Variables _variables;
   Variables _enum_values;

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

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

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

@@ -26,14 +26,16 @@
 class CPPSimpleType : public CPPType {
 public:
   enum Type {
+    T_unknown,
     T_bool,
     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_float,
     T_double,
     T_void,
-    T_unknown,
 
     // T_parameter is a special type which is assigned to expressions
     // that are discovered where a formal parameter was expected.

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

@@ -14,7 +14,7 @@
 
 
 #include "cppStructType.h"
-#include "cppTypedef.h"
+#include "cppTypedefType.h"
 #include "cppScope.h"
 #include "cppTypeProxy.h"
 #include "cppTemplateScope.h"
@@ -91,6 +91,13 @@ operator = (const CPPStructType &copy) {
 void CPPStructType::
 append_derivation(CPPType *base, CPPVisibility vis, bool is_virtual) {
   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;
     b._base = base;
     b._vis = vis;
@@ -110,7 +117,6 @@ get_scope() const {
   return _scope;
 }
 
-
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPStructType::is_abstract
 //       Access: Public
@@ -246,7 +252,7 @@ instantiate(const CPPTemplateParameterList *actual_params,
     // don't yet know what its associated struct type will be.
 
     // 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));
   }
@@ -318,7 +324,7 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
             rep->_template_scope = (CPPTemplateScope *)NULL;
             CPPNameComponent nc(get_simple_name());
             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);
   if (rep != this) {
     _instantiations.insert(rep);
-    //    cerr << "Subst for " << *this << " is " << *rep << "\n";
   }
   return rep;
 }
@@ -377,15 +382,9 @@ output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
 
     if (is_template()) {
       CPPTemplateScope *tscope = get_template_scope();
-      out << "< ";
       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 {
     if (is_template()) {
       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,
                  CPPDeclaration::SubstDecl &subst,
                  CPPScope *current_scope, CPPScope *global_scope) const {
+
   Parameters::const_iterator pfi, pai;
   for (pfi = formal_params._parameters.begin(), pai = _parameters.begin();
        pfi != formal_params._parameters.end() && pai != _parameters.end();

Some files were not shown because too many files changed in this diff