Browse Source

Merge branch 'master' into interrogate-overhaul

Conflicts:
	dtool/src/cppparser/cppBison.yxx
	dtool/src/interrogate/interfaceMakerPythonNative.cxx
rdb 10 years ago
parent
commit
e608fa69c7
100 changed files with 4585 additions and 623 deletions
  1. 0 1
      .gitignore
  2. 38 38
      contrib/src/ai/aiBehaviors.cxx
  3. 16 16
      contrib/src/ai/aiBehaviors.h
  4. 21 26
      contrib/src/ai/aiCharacter.cxx
  5. 4 4
      contrib/src/ai/aiCharacter.h
  6. 1 1
      contrib/src/ai/aiNode.cxx
  7. 2 2
      contrib/src/ai/aiNode.h
  8. 2 2
      contrib/src/ai/aiPathFinder.cxx
  9. 1 1
      contrib/src/ai/aiPathFinder.h
  10. 8 8
      contrib/src/ai/arrival.cxx
  11. 3 3
      contrib/src/ai/arrival.h
  12. 4 4
      contrib/src/ai/evade.cxx
  13. 2 2
      contrib/src/ai/evade.h
  14. 7 7
      contrib/src/ai/flee.cxx
  15. 5 5
      contrib/src/ai/flee.h
  16. 1 1
      contrib/src/ai/meshNode.cxx
  17. 2 2
      contrib/src/ai/meshNode.h
  18. 15 15
      contrib/src/ai/obstacleAvoidance.cxx
  19. 1 1
      contrib/src/ai/obstacleAvoidance.h
  20. 3 3
      contrib/src/ai/pathFind.cxx
  21. 2 2
      contrib/src/ai/pathFind.h
  22. 2 2
      contrib/src/ai/pathFollow.cxx
  23. 2 2
      contrib/src/ai/pathFollow.h
  24. 6 6
      contrib/src/ai/pursue.cxx
  25. 2 2
      contrib/src/ai/pursue.h
  26. 5 5
      contrib/src/ai/seek.cxx
  27. 5 5
      contrib/src/ai/seek.h
  28. 18 18
      contrib/src/ai/wander.cxx
  29. 3 3
      contrib/src/ai/wander.h
  30. 2 2
      direct/src/directscripts/Doxyfile.python
  31. 111 50
      direct/src/directscripts/extract_docs.py
  32. 1 1
      direct/src/filter/FilterManager.py
  33. 24 10
      direct/src/gui/DirectDialog.py
  34. 5 3
      direct/src/gui/DirectRadioButton.py
  35. 8 6
      direct/src/showbase/Transitions.py
  36. 8 2
      dtool/src/interrogate/interfaceMakerPythonNative.cxx
  37. 7 5
      makepanda/makepanda.py
  38. 1 1
      panda/src/bullet/bulletSoftBodyNode.cxx
  39. 16 19
      panda/src/cocoadisplay/cocoaGraphicsPipe.mm
  40. 7 13
      panda/src/display/config_display.cxx
  41. 0 3
      panda/src/display/config_display.h
  42. 26 21
      panda/src/display/frameBufferProperties.I
  43. 29 33
      panda/src/display/frameBufferProperties.cxx
  44. 1 1
      panda/src/display/frameBufferProperties.h
  45. 3 3
      panda/src/distort/nonlinearImager.cxx
  46. 8 3
      panda/src/doc/eggSyntax.txt
  47. 4 0
      panda/src/egg2pg/eggLoader.cxx
  48. 7 21
      panda/src/glstuff/glCgShaderContext_src.cxx
  49. 0 1
      panda/src/glstuff/glCgShaderContext_src.h
  50. 82 73
      panda/src/glstuff/glGraphicsBuffer_src.cxx
  51. 8 0
      panda/src/glstuff/glShaderContext_src.cxx
  52. 15 22
      panda/src/glxdisplay/glxGraphicsPipe.cxx
  53. 77 72
      panda/src/gobj/texture.cxx
  54. 7 0
      panda/src/gobj/texture.h
  55. 8 8
      panda/src/grutil/pfmVizzer.cxx
  56. 2 0
      panda/src/ode/odeRayGeom.I
  57. 2 0
      panda/src/ode/odeTriMeshData.h
  58. 17 22
      panda/src/osxdisplay/osxGraphicsPipe.cxx
  59. 1 1
      panda/src/pgraph/cullBinManager.h
  60. 7 5
      panda/src/pgraph/pandaNode.I
  61. 175 0
      panda/src/pnmimage/convert_srgb.I
  62. 165 0
      panda/src/pnmimage/convert_srgb.cxx
  63. 59 0
      panda/src/pnmimage/convert_srgb.h
  64. 151 0
      panda/src/pnmimage/convert_srgb_sse2.cxx
  65. 1 0
      panda/src/pnmimage/p3pnmimage_composite1.cxx
  66. 1 1
      panda/src/rocket/rocketRenderInterface.h
  67. 1 1
      panda/src/tinydisplay/zbuffer.h
  68. 16 30
      panda/src/wgldisplay/wglGraphicsPipe.cxx
  69. 1 1
      pandatool/src/daeegg/daeCharacter.cxx
  70. 1 1
      pandatool/src/daeegg/daeCharacter.h
  71. 1 1
      pandatool/src/daeegg/daeToEggConverter.cxx
  72. 7 0
      pandatool/src/daeegg/pre_fcollada_include.h
  73. 399 0
      samples/asteroids/main.py
  74. 39 0
      samples/asteroids/models/plane.egg
  75. BIN
      samples/asteroids/textures/asteroid1.png
  76. BIN
      samples/asteroids/textures/asteroid2.png
  77. BIN
      samples/asteroids/textures/asteroid3.png
  78. BIN
      samples/asteroids/textures/bullet.png
  79. BIN
      samples/asteroids/textures/ship.png
  80. BIN
      samples/asteroids/textures/stars.jpg
  81. 338 0
      samples/ball-in-maze/main.py
  82. BIN
      samples/ball-in-maze/models/ball.egg.pz
  83. BIN
      samples/ball-in-maze/models/iron05.jpg
  84. BIN
      samples/ball-in-maze/models/limba.jpg
  85. BIN
      samples/ball-in-maze/models/maze.egg.pz
  86. 199 0
      samples/boxing-robots/main.py
  87. BIN
      samples/boxing-robots/models/ring.egg.pz
  88. BIN
      samples/boxing-robots/models/robot.egg.pz
  89. BIN
      samples/boxing-robots/models/robot_head_down.egg.pz
  90. BIN
      samples/boxing-robots/models/robot_head_up.egg.pz
  91. BIN
      samples/boxing-robots/models/robot_left_punch.egg.pz
  92. BIN
      samples/boxing-robots/models/robot_right_punch.egg.pz
  93. 188 0
      samples/bump-mapping/main.py
  94. 1671 0
      samples/bump-mapping/models/abstractroom.egg
  95. BIN
      samples/bump-mapping/models/abstractroom.mb
  96. BIN
      samples/bump-mapping/models/brick-c.jpg
  97. BIN
      samples/bump-mapping/models/brick-n.jpg
  98. BIN
      samples/bump-mapping/models/fieldstone-c.jpg
  99. BIN
      samples/bump-mapping/models/fieldstone-n.jpg
  100. 497 0
      samples/bump-mapping/models/icosphere.egg

+ 0 - 1
.gitignore

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

+ 1 - 1
direct/src/filter/FilterManager.py

@@ -294,7 +294,7 @@ class FilterManager(DirectObject):
 
 
         winprops = WindowProperties()
         winprops = WindowProperties()
         winprops.setSize(xsize, ysize)
         winprops.setSize(xsize, ysize)
-        props = FrameBufferProperties(self.win.getFbProperties())
+        props = FrameBufferProperties(FrameBufferProperties.getDefault())
         props.setBackBuffers(0)
         props.setBackBuffers(0)
         props.setRgbColor(1)
         props.setRgbColor(1)
         props.setDepthBits(depthbits)
         props.setDepthBits(depthbits)

+ 24 - 10
direct/src/gui/DirectDialog.py

@@ -94,8 +94,9 @@ class DirectDialog(DirectFrame):
             ('text',              '',            None),
             ('text',              '',            None),
             ('text_align',        TextNode.ALeft,   None),
             ('text_align',        TextNode.ALeft,   None),
             ('text_scale',        0.06,          None),
             ('text_scale',        0.06,          None),
-            ('image',  DGG.getDefaultDialogGeom(),   None),
-            ('relief',            None,          None),
+            ('image',             None,          None),
+            ('relief',            DGG.RAISED,     None),
+            ('borderWidth',       (0.01, 0.01),  None),
             ('buttonTextList',    [],            DGG.INITOPT),
             ('buttonTextList',    [],            DGG.INITOPT),
             ('buttonGeomList',    [],            DGG.INITOPT),
             ('buttonGeomList',    [],            DGG.INITOPT),
             ('buttonImageList',   [],            DGG.INITOPT),
             ('buttonImageList',   [],            DGG.INITOPT),
@@ -210,10 +211,16 @@ class DirectDialog(DirectFrame):
         bounds = self.stateNodePath[0].getTightBounds()
         bounds = self.stateNodePath[0].getTightBounds()
         if image:
         if image:
             image.reparentTo(self.stateNodePath[0])
             image.reparentTo(self.stateNodePath[0])
-        l = bounds[0][0]
-        r = bounds[1][0]
-        b = bounds[0][2]
-        t = bounds[1][2]
+        if bounds is None:
+            l = 0
+            r = 0
+            b = 0
+            t = 0
+        else:
+            l = bounds[0][0]
+            r = bounds[1][0]
+            b = bounds[0][2]
+            t = bounds[1][2]
         # Center text and geom around origin
         # Center text and geom around origin
         # How far is center of text from origin?
         # How far is center of text from origin?
         xOffset = -(l+r)*0.5
         xOffset = -(l+r)*0.5
@@ -246,10 +253,16 @@ class DirectDialog(DirectFrame):
                 bl = br = bb = bt = 0
                 bl = br = bb = bt = 0
                 for button in self.buttonList:
                 for button in self.buttonList:
                     bounds = button.stateNodePath[0].getTightBounds()
                     bounds = button.stateNodePath[0].getTightBounds()
-                    bl = min(bl, bounds[0][0])
-                    br = max(br, bounds[1][0])
-                    bb = min(bb, bounds[0][2])
-                    bt = max(bt, bounds[1][2])
+                    if bounds is None:
+                        bl = 0
+                        br = 0
+                        bb = 0
+                        bt = 0
+                    else:
+                        bl = min(bl, bounds[0][0])
+                        br = max(br, bounds[1][0])
+                        bb = min(bb, bounds[0][2])
+                        bt = max(bt, bounds[1][2])
                 bl -= bpad[0]
                 bl -= bpad[0]
                 br += bpad[0]
                 br += bpad[0]
                 bb -= bpad[1]
                 bb -= bpad[1]
@@ -303,6 +316,7 @@ class DirectDialog(DirectFrame):
         # reduce bottom by pad, button height and 2*button pad
         # reduce bottom by pad, button height and 2*button pad
         b = min(b - self['midPad'] - bpad[1] - bHeight - bpad[1], b) - pad[1]
         b = min(b - self['midPad'] - bpad[1] - bHeight - bpad[1], b) - pad[1]
         t = t + self['topPad'] + pad[1]
         t = t + self['topPad'] + pad[1]
+        self['frameSize'] = (l, r, b, t)
         self['image_scale'] = (r - l, 1, t - b)
         self['image_scale'] = (r - l, 1, t - b)
         # Center frame about text and buttons
         # Center frame about text and buttons
         self['image_pos'] = ((l+r)*0.5, 0.0, (b+t)*0.5)
         self['image_pos'] = ((l+r)*0.5, 0.0, (b+t)*0.5)

+ 5 - 3
direct/src/gui/DirectRadioButton.py

@@ -43,7 +43,7 @@ class DirectRadioButton(DirectButton):
             ('boxGeom', None, None),
             ('boxGeom', None, None),
             ('boxGeomColor', None, None),
             ('boxGeomColor', None, None),
             ('boxGeomScale', 1.0, None),
             ('boxGeomScale', 1.0, None),
-            ('boxImage', loader.loadModel('models/gui/radio_button_gui'), None),
+            ('boxImage', None, None),
             ('boxImageScale', 1.0, None),
             ('boxImageScale', 1.0, None),
             ('boxImageColor', VBase4(1, 1, 1, 1), None),
             ('boxImageColor', VBase4(1, 1, 1, 1), None),
             ('boxRelief', None, None),
             ('boxRelief', None, None),
@@ -69,9 +69,11 @@ class DirectRadioButton(DirectButton):
         # Call option initialization functions
         # Call option initialization functions
         self.initialiseoptions(DirectRadioButton)
         self.initialiseoptions(DirectRadioButton)
         # After initialization with X giving it the correct size, put back space
         # After initialization with X giving it the correct size, put back space
-        if self['boxGeom'] ==  None:
+        if self['boxGeom'] is None:
+            if not 'boxRelief' in kw and self['boxImage'] is None:
+                self.indicator['relief'] = DGG.SUNKEN
             self.indicator['text'] = (' ', '*')
             self.indicator['text'] = (' ', '*')
-            self.indicator['text_pos'] = (0, -.5)
+            self.indicator['text_pos'] = (0, -.25)
         else:
         else:
             self.indicator['text'] = (' ', ' ')
             self.indicator['text'] = (' ', ' ')
 
 

+ 8 - 6
direct/src/showbase/Transitions.py

@@ -59,15 +59,12 @@ class Transitions:
 
 
         # Reload fade if its already been created
         # Reload fade if its already been created
         if self.fade:
         if self.fade:
-            del self.fade
+            self.fade.destroy()
             self.fade = None
             self.fade = None
             self.loadFade()
             self.loadFade()
 
 
     def loadFade(self):
     def loadFade(self):
-        if not self.fadeModel:
-            self.fadeModel = loader.loadModel(self.FadeModelName)
-
-        if self.fade == None:
+        if self.fade is None:
             # We create a DirectFrame for the fade polygon, instead of
             # We create a DirectFrame for the fade polygon, instead of
             # simply loading the polygon model and using it directly,
             # simply loading the polygon model and using it directly,
             # so that it will also obscure mouse events for objects
             # so that it will also obscure mouse events for objects
@@ -80,10 +77,15 @@ class Transitions:
                 image_scale = (4, 2, 2),
                 image_scale = (4, 2, 2),
                 state = DGG.NORMAL,
                 state = DGG.NORMAL,
                 )
                 )
+            if not self.fadeModel:
+                # No fade model was given, so we make this the fade model.
+                self.fade["relief"] = DGG.FLAT
+                self.fade["frameSize"] = (-2, 2, -1, 1)
+                self.fade["frameColor"] = (0, 0, 0, 1)
+                self.fade.setTransparency(TransparencyAttrib.MAlpha)
             self.fade.setBin('unsorted', 0)
             self.fade.setBin('unsorted', 0)
             self.fade.setColor(0,0,0,0)
             self.fade.setColor(0,0,0,0)
 
 
-    
     def getFadeInIval(self, t=0.5, finishIval=None):
     def getFadeInIval(self, t=0.5, finishIval=None):
         """
         """
         Returns an interval without starting it.  This is particularly useful in
         Returns an interval without starting it.  This is particularly useful in

+ 8 - 2
dtool/src/interrogate/interfaceMakerPythonNative.cxx

@@ -4625,8 +4625,14 @@ write_function_instance(ostream &out, FunctionRemap *remap,
         format_specifiers += "h";
         format_specifiers += "h";
         parameter_list += ", &" + param_name;
         parameter_list += ", &" + param_name;
       }
       }
-      expected_params += "int";
-      only_pyobjects = false;
+
+      extra_convert += "PyObject *" + param_name + "_long = PyNumber_Long(" + param_name + ");";
+      extra_param_check += " && " + param_name + "_long != NULL";
+      pexpr_string = "(" + type->get_local_name(&parser) + ")" +
+                     "PyLong_AsLongLong(" + param_name + "_long)";
+      extra_cleanup += "Py_XDECREF(" + param_name + "_long);";
+      expected_params += "long long";
+      ++num_params;
 
 
     } else if (TypeManager::is_unsigned_integer(type)) {
     } else if (TypeManager::is_unsigned_integer(type)) {
       if (args_type == AT_single_arg) {
       if (args_type == AT_single_arg) {

+ 7 - 5
makepanda/makepanda.py

@@ -949,7 +949,7 @@ def CompileCxx(obj,src,opts):
             if PkgSkip("TOUCHINPUT") == 0:
             if PkgSkip("TOUCHINPUT") == 0:
                 cmd += "/DWINVER=0x601 "
                 cmd += "/DWINVER=0x601 "
             cmd += "/Fo" + obj + " /nologo /c"
             cmd += "/Fo" + obj + " /nologo /c"
-            if (GetTargetArch() != 'x64' and PkgSkip("SSE2") == 0):
+            if GetTargetArch() != 'x64' and (not PkgSkip("SSE2") or 'SSE2' in opts):
                 cmd += " /arch:SSE2"
                 cmd += " /arch:SSE2"
             for x in ipath: cmd += " /I" + x
             for x in ipath: cmd += " /I" + x
             for (opt,dir) in INCDIRECTORIES:
             for (opt,dir) in INCDIRECTORIES:
@@ -1160,7 +1160,7 @@ def CompileCxx(obj,src,opts):
                 if optlevel >= 4 or GetTarget() == "android":
                 if optlevel >= 4 or GetTarget() == "android":
                     cmd += " -fno-rtti"
                     cmd += " -fno-rtti"
 
 
-        if PkgSkip("SSE2") == 0 and not arch.startswith("arm"):
+        if ('SSE2' in opts or not PkgSkip("SSE2")) and not arch.startswith("arm"):
             cmd += " -msse2"
             cmd += " -msse2"
 
 
         if optlevel >= 3:
         if optlevel >= 3:
@@ -1705,7 +1705,7 @@ def RunGenPyCode(target, inputs, opts):
     if (PkgSkip("PYTHON") != 0):
     if (PkgSkip("PYTHON") != 0):
         return
         return
 
 
-    cmdstr = sys.executable + " "
+    cmdstr = BracketNameWithQuotes(SDK["PYTHONEXEC"]) + " "
     if sys.version_info >= (2, 6):
     if sys.version_info >= (2, 6):
         cmdstr += "-B "
         cmdstr += "-B "
 
 
@@ -1729,7 +1729,7 @@ def RunGenPyCode(target, inputs, opts):
 def FreezePy(target, inputs, opts):
 def FreezePy(target, inputs, opts):
     assert len(inputs) > 0
     assert len(inputs) > 0
     # Make sure this function isn't called before genpycode is run.
     # Make sure this function isn't called before genpycode is run.
-    cmdstr = sys.executable + " "
+    cmdstr = BracketNameWithQuotes(SDK["PYTHONEXEC"]) + " "
     if sys.version_info >= (2, 6):
     if sys.version_info >= (2, 6):
         cmdstr += "-B "
         cmdstr += "-B "
 
 
@@ -1757,7 +1757,7 @@ def FreezePy(target, inputs, opts):
 def Package(target, inputs, opts):
 def Package(target, inputs, opts):
     assert len(inputs) == 1
     assert len(inputs) == 1
     # Invoke the ppackage script.
     # Invoke the ppackage script.
-    command = sys.executable + " "
+    command = BracketNameWithQuotes(SDK["PYTHONEXEC"]) + " "
     if GetOptimizeOption(opts) >= 4:
     if GetOptimizeOption(opts) >= 4:
         command += "-OO "
         command += "-OO "
 
 
@@ -3192,6 +3192,7 @@ if (not RUNTIME):
   OPTS=['DIR:panda/src/pnmimage', 'BUILDING:PANDA',  'ZLIB']
   OPTS=['DIR:panda/src/pnmimage', 'BUILDING:PANDA',  'ZLIB']
   TargetAdd('p3pnmimage_composite1.obj', opts=OPTS, input='p3pnmimage_composite1.cxx')
   TargetAdd('p3pnmimage_composite1.obj', opts=OPTS, input='p3pnmimage_composite1.cxx')
   TargetAdd('p3pnmimage_composite2.obj', opts=OPTS, input='p3pnmimage_composite2.cxx')
   TargetAdd('p3pnmimage_composite2.obj', opts=OPTS, input='p3pnmimage_composite2.cxx')
+  TargetAdd('p3pnmimage_convert_srgb_sse2.obj', opts=OPTS+['SSE2'], input='convert_srgb_sse2.cxx')
 
 
   OPTS=['DIR:panda/src/pnmimage', 'ZLIB']
   OPTS=['DIR:panda/src/pnmimage', 'ZLIB']
   IGATEFILES=GetDirectoryContents('panda/src/pnmimage', ["*.h", "*_composite*.cxx"])
   IGATEFILES=GetDirectoryContents('panda/src/pnmimage', ["*.h", "*_composite*.cxx"])
@@ -3621,6 +3622,7 @@ if (not RUNTIME):
   TargetAdd('libpanda.dll', input='p3pnmimagetypes_composite2.obj')
   TargetAdd('libpanda.dll', input='p3pnmimagetypes_composite2.obj')
   TargetAdd('libpanda.dll', input='p3pnmimage_composite1.obj')
   TargetAdd('libpanda.dll', input='p3pnmimage_composite1.obj')
   TargetAdd('libpanda.dll', input='p3pnmimage_composite2.obj')
   TargetAdd('libpanda.dll', input='p3pnmimage_composite2.obj')
+  TargetAdd('libpanda.dll', input='p3pnmimage_convert_srgb_sse2.obj')
   TargetAdd('libpanda.dll', input='p3text_composite1.obj')
   TargetAdd('libpanda.dll', input='p3text_composite1.obj')
   TargetAdd('libpanda.dll', input='p3text_composite2.obj')
   TargetAdd('libpanda.dll', input='p3text_composite2.obj')
   TargetAdd('libpanda.dll', input='p3tform_composite1.obj')
   TargetAdd('libpanda.dll', input='p3tform_composite1.obj')

+ 1 - 1
panda/src/bullet/bulletSoftBodyNode.cxx

@@ -1018,7 +1018,7 @@ make_tet_mesh(BulletSoftBodyWorldInfo &info, const char *ele, const char *face,
 
 
   for (int i=0; i<pos.size(); ++i) {
   for (int i=0; i<pos.size(); ++i) {
     int index = 0;
     int index = 0;
-    PN_stdfloat x, y, z;
+    float x, y, z;
 
 
     sscanf(node, "%d %f %f %f", &index, &x, &y, &z);
     sscanf(node, "%d %f %f %f", &index, &x, &y, &z);
     node += next_line(node);
     node += next_line(node);

+ 16 - 19
panda/src/cocoadisplay/cocoaGraphicsPipe.mm

@@ -324,34 +324,31 @@ make_output(const string &name,
   }
   }
 
 
   // Second thing to try: a GLGraphicsBuffer
   // Second thing to try: a GLGraphicsBuffer
+
   if (retry == 1) {
   if (retry == 1) {
-    if ((host==0)||
-  //        (!gl_support_fbo)||
-        ((flags&BF_require_parasite)!=0)||
-        ((flags&BF_require_window)!=0)) {
+    if (!gl_support_fbo || host == NULL ||
+        (flags & (BF_require_parasite | BF_require_window)) != 0) {
       return NULL;
       return NULL;
     }
     }
     // Early failure - if we are sure that this buffer WONT
     // Early failure - if we are sure that this buffer WONT
     // meet specs, we can bail out early.
     // meet specs, we can bail out early.
-    if ((flags & BF_fb_props_optional)==0) {
-      if ((fb_prop.get_indexed_color() > 0)||
-          (fb_prop.get_back_buffers() > 0)||
-          (fb_prop.get_accum_bits() > 0)||
-          (fb_prop.get_multisamples() > 0)) {
+    if ((flags & BF_fb_props_optional) == 0) {
+      if (fb_prop.get_indexed_color() ||
+          fb_prop.get_back_buffers() > 0 ||
+          fb_prop.get_accum_bits() > 0) {
         return NULL;
         return NULL;
       }
       }
     }
     }
-    // Early success - if we are sure that this buffer WILL
-    // meet specs, we can precertify it.
-    if ((cocoagsg != 0) &&
-        (cocoagsg->is_valid()) &&
-        (!cocoagsg->needs_reset()) &&
-        (cocoagsg->_supports_framebuffer_object) &&
-        (cocoagsg->_glDrawBuffers != 0) &&
-        (fb_prop.is_basic())) {
-      precertify = true;
+    if (cocoagsg != NULL && cocoagsg->is_valid() && !cocoagsg->needs_reset()) {
+      if (!cocoagsg->_supports_framebuffer_object ||
+          cocoagsg->_glDrawBuffers == NULL) {
+        return NULL;
+      } else {
+        // Early success - if we are sure that this buffer WILL
+        // meet specs, we can precertify it.
+        precertify = true;
+      }
     }
     }
-
     return new GLGraphicsBuffer(engine, this, name, fb_prop, win_prop,
     return new GLGraphicsBuffer(engine, this, name, fb_prop, win_prop,
                                 flags, gsg, host);
                                 flags, gsg, host);
   }
   }

+ 7 - 13
panda/src/display/config_display.cxx

@@ -418,19 +418,13 @@ ConfigVariableInt depth_bits
 ("depth-bits", 0,
 ("depth-bits", 0,
  PRC_DESC("The minimum number of depth buffer bits requested."));
  PRC_DESC("The minimum number of depth buffer bits requested."));
 ConfigVariableInt color_bits
 ConfigVariableInt color_bits
-("color-bits", 0,
- PRC_DESC("The minimum number of total color buffer bits requested.  This "
-          "value is like red-bits + blue-bits + green-bits except Panda "
-          "won't care how the bits are divided up."));
-ConfigVariableInt red_bits
-("red-bits", 0,
- PRC_DESC("The minimum number of red color buffer bits requested."));
-ConfigVariableInt green_bits
-("green-bits", 0,
- PRC_DESC("The minimum number of green color buffer bits requested."));
-ConfigVariableInt blue_bits
-("blue-bits", 0,
- PRC_DESC("The minimum number of blue color buffer bits requested."));
+("color-bits", "",
+ PRC_DESC("The minimum number of total color buffer bits requested.  If you "
+          "specify only one value, it will represent the total value for the "
+          "red, green and blue channels, and indicates you don't care how the "
+          "bits are divided up among the red, green and blue channels.  If "
+          "you specify three values, it represents three separate red, green "
+          "and blue bit requirements."));
 ConfigVariableInt alpha_bits
 ConfigVariableInt alpha_bits
 ("alpha-bits", 0,
 ("alpha-bits", 0,
  PRC_DESC("The minimum number of alpha buffer bits requested."));
  PRC_DESC("The minimum number of alpha buffer bits requested."));

+ 0 - 3
panda/src/display/config_display.h

@@ -97,9 +97,6 @@ extern EXPCL_PANDA_DISPLAY ConfigVariableBool framebuffer_srgb;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool framebuffer_float;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool framebuffer_float;
 extern EXPCL_PANDA_DISPLAY ConfigVariableInt depth_bits;
 extern EXPCL_PANDA_DISPLAY ConfigVariableInt depth_bits;
 extern EXPCL_PANDA_DISPLAY ConfigVariableInt color_bits;
 extern EXPCL_PANDA_DISPLAY ConfigVariableInt color_bits;
-extern EXPCL_PANDA_DISPLAY ConfigVariableInt red_bits;
-extern EXPCL_PANDA_DISPLAY ConfigVariableInt green_bits;
-extern EXPCL_PANDA_DISPLAY ConfigVariableInt blue_bits;
 extern EXPCL_PANDA_DISPLAY ConfigVariableInt alpha_bits;
 extern EXPCL_PANDA_DISPLAY ConfigVariableInt alpha_bits;
 extern EXPCL_PANDA_DISPLAY ConfigVariableInt stencil_bits;
 extern EXPCL_PANDA_DISPLAY ConfigVariableInt stencil_bits;
 extern EXPCL_PANDA_DISPLAY ConfigVariableInt accum_bits;
 extern EXPCL_PANDA_DISPLAY ConfigVariableInt accum_bits;

+ 26 - 21
panda/src/display/frameBufferProperties.I

@@ -305,37 +305,42 @@ get_float_depth() const {
 INLINE void FrameBufferProperties::
 INLINE void FrameBufferProperties::
 set_depth_bits(int n) {
 set_depth_bits(int n) {
   _property[FBP_depth_bits] = n;
   _property[FBP_depth_bits] = n;
-  _specified[FBP_depth_bits] = true;
+  _specified |= (1 << FBP_depth_bits);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: FrameBufferProperties::set_color_bits
 //     Function: FrameBufferProperties::set_color_bits
 //       Access: Published
 //       Access: Published
-//  Description:
+//  Description: Sets the number of requested color bits as a single
+//               number that represents the sum of the individual
+//               numbers of red, green and blue bits.  Panda won't
+//               care how the individual bits are divided up.
+//
+//               See also set_rgba_bits, which allows you to specify
+//               requirements for the individual components.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void FrameBufferProperties::
 INLINE void FrameBufferProperties::
 set_color_bits(int n) {
 set_color_bits(int n) {
   _property[FBP_color_bits] = n;
   _property[FBP_color_bits] = n;
-  _specified[FBP_color_bits] = true;
+  _specified |= (1 << FBP_color_bits);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: FrameBufferProperties::set_rgba_bits
 //     Function: FrameBufferProperties::set_rgba_bits
 //       Access: Published
 //       Access: Published
-//  Description: Sets all color bit requirements separately.
+//  Description: Convenience method for setting the red, green, blue
+//               and alpha bits in one go.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void FrameBufferProperties::
 INLINE void FrameBufferProperties::
 set_rgba_bits(int r, int g, int b, int a) {
 set_rgba_bits(int r, int g, int b, int a) {
   _property[FBP_red_bits] = r;
   _property[FBP_red_bits] = r;
-  _specified[FBP_red_bits] = true;
   _property[FBP_green_bits] = g;
   _property[FBP_green_bits] = g;
-  _specified[FBP_green_bits] = true;
   _property[FBP_blue_bits] = b;
   _property[FBP_blue_bits] = b;
-  _specified[FBP_blue_bits] = true;
   _property[FBP_alpha_bits] = a;
   _property[FBP_alpha_bits] = a;
-  _specified[FBP_alpha_bits] = true;
   _property[FBP_color_bits] = r + g + b;
   _property[FBP_color_bits] = r + g + b;
-  _specified[FBP_color_bits] = true;
+  _specified |= (1 << FBP_color_bits) | (1 << FBP_red_bits) |
+                (1 << FBP_green_bits) | (1 << FBP_blue_bits) |
+                (1 << FBP_alpha_bits);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -346,7 +351,7 @@ set_rgba_bits(int r, int g, int b, int a) {
 INLINE void FrameBufferProperties::
 INLINE void FrameBufferProperties::
 set_red_bits(int n) {
 set_red_bits(int n) {
   _property[FBP_red_bits] = n;
   _property[FBP_red_bits] = n;
-  _specified[FBP_red_bits] = true;
+  _specified |= (1 << FBP_red_bits);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -357,7 +362,7 @@ set_red_bits(int n) {
 INLINE void FrameBufferProperties::
 INLINE void FrameBufferProperties::
 set_green_bits(int n) {
 set_green_bits(int n) {
   _property[FBP_green_bits] = n;
   _property[FBP_green_bits] = n;
-  _specified[FBP_green_bits] = true;
+  _specified |= (1 << FBP_green_bits);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -368,7 +373,7 @@ set_green_bits(int n) {
 INLINE void FrameBufferProperties::
 INLINE void FrameBufferProperties::
 set_blue_bits(int n) {
 set_blue_bits(int n) {
   _property[FBP_blue_bits] = n;
   _property[FBP_blue_bits] = n;
-  _specified[FBP_blue_bits] = true;
+  _specified |= (1 << FBP_blue_bits);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -379,7 +384,7 @@ set_blue_bits(int n) {
 INLINE void FrameBufferProperties::
 INLINE void FrameBufferProperties::
 set_alpha_bits(int n) {
 set_alpha_bits(int n) {
   _property[FBP_alpha_bits] = n;
   _property[FBP_alpha_bits] = n;
-  _specified[FBP_alpha_bits] = true;
+  _specified |= (1 << FBP_alpha_bits);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -390,7 +395,7 @@ set_alpha_bits(int n) {
 INLINE void FrameBufferProperties::
 INLINE void FrameBufferProperties::
 set_stencil_bits(int n) {
 set_stencil_bits(int n) {
   _property[FBP_stencil_bits] = n;
   _property[FBP_stencil_bits] = n;
-  _specified[FBP_stencil_bits] = true;
+  _specified |= (1 << FBP_stencil_bits);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -401,7 +406,7 @@ set_stencil_bits(int n) {
 INLINE void FrameBufferProperties::
 INLINE void FrameBufferProperties::
 set_accum_bits(int n) {
 set_accum_bits(int n) {
   _property[FBP_accum_bits] = n;
   _property[FBP_accum_bits] = n;
-  _specified[FBP_accum_bits] = true;
+  _specified |= (1 << FBP_accum_bits);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -413,7 +418,7 @@ INLINE void FrameBufferProperties::
 set_aux_rgba(int n) {
 set_aux_rgba(int n) {
   nassertv(n < 4);
   nassertv(n < 4);
   _property[FBP_aux_rgba] = n;
   _property[FBP_aux_rgba] = n;
-  _specified[FBP_aux_rgba] = true;
+  _specified |= (1 << FBP_aux_rgba);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -425,7 +430,7 @@ INLINE void FrameBufferProperties::
 set_aux_hrgba(int n) {
 set_aux_hrgba(int n) {
   nassertv(n < 4);
   nassertv(n < 4);
   _property[FBP_aux_hrgba] = n;
   _property[FBP_aux_hrgba] = n;
-  _specified[FBP_aux_hrgba] = true;
+  _specified |= (1 << FBP_aux_hrgba);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -437,7 +442,7 @@ INLINE void FrameBufferProperties::
 set_aux_float(int n) {
 set_aux_float(int n) {
   nassertv(n < 4);
   nassertv(n < 4);
   _property[FBP_aux_float] = n;
   _property[FBP_aux_float] = n;
-  _specified[FBP_aux_float] = true;
+  _specified |= (1 << FBP_aux_float);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -448,7 +453,7 @@ set_aux_float(int n) {
 INLINE void FrameBufferProperties::
 INLINE void FrameBufferProperties::
 set_multisamples(int n) {
 set_multisamples(int n) {
   _property[FBP_multisamples] = n;
   _property[FBP_multisamples] = n;
-  _specified[FBP_multisamples] = true;
+  _specified |= (1 << FBP_multisamples);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -460,7 +465,7 @@ set_multisamples(int n) {
 INLINE void FrameBufferProperties::
 INLINE void FrameBufferProperties::
 set_coverage_samples(int n) {
 set_coverage_samples(int n) {
   _property[FBP_coverage_samples] = n;
   _property[FBP_coverage_samples] = n;
-  _specified[FBP_coverage_samples] = true;
+  _specified |= (1 << FBP_coverage_samples);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -471,7 +476,7 @@ set_coverage_samples(int n) {
 INLINE void FrameBufferProperties::
 INLINE void FrameBufferProperties::
 set_back_buffers(int n) {
 set_back_buffers(int n) {
   _property[FBP_back_buffers] = n;
   _property[FBP_back_buffers] = n;
-  _specified[FBP_back_buffers] = true;
+  _specified |= (1 << FBP_back_buffers);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 29 - 33
panda/src/display/frameBufferProperties.cxx

@@ -37,9 +37,9 @@ void FrameBufferProperties::
 operator = (const FrameBufferProperties &copy) {
 operator = (const FrameBufferProperties &copy) {
   _flags_specified = copy._flags_specified;
   _flags_specified = copy._flags_specified;
   _flags = copy._flags;
   _flags = copy._flags;
+  _specified = copy._specified;
 
 
   for (int i = 0; i < FBP_COUNT; ++i) {
   for (int i = 0; i < FBP_COUNT; ++i) {
-    _specified[i] = copy._specified[i];
     _property[i]  = copy._property[i];
     _property[i]  = copy._property[i];
   }
   }
 }
 }
@@ -144,17 +144,24 @@ get_default() {
   if (depth_bits > 0) {
   if (depth_bits > 0) {
     default_props.set_depth_bits(depth_bits);
     default_props.set_depth_bits(depth_bits);
   }
   }
-  if (color_bits > 0) {
-    default_props.set_color_bits(color_bits);
-  }
-  if (red_bits > 0) {
-    default_props.set_red_bits(red_bits);
-  }
-  if (green_bits > 0) {
-    default_props.set_green_bits(green_bits);
-  }
-  if (blue_bits > 0) {
-    default_props.set_blue_bits(blue_bits);
+  switch (color_bits.size()) {
+  case 0:
+    break;
+  case 1:
+    default_props.set_color_bits(color_bits[0]);
+    break;
+  case 3:
+    default_props.set_color_bits(color_bits[0] + color_bits[1] + color_bits[2]);
+    default_props.set_red_bits(color_bits[0]);
+    default_props.set_green_bits(color_bits[1]);
+    default_props.set_blue_bits(color_bits[2]);
+    break;
+  default:
+    default_props.set_color_bits(color_bits[0]);
+    display_cat.error()
+      << "Configuration variable color-bits takes either 1 or 3 values, not "
+      << color_bits.size() << "\n";
+    break;
   }
   }
   if (alpha_bits > 0) {
   if (alpha_bits > 0) {
     default_props.set_alpha_bits(alpha_bits);
     default_props.set_alpha_bits(alpha_bits);
@@ -189,10 +196,11 @@ operator == (const FrameBufferProperties &other) const {
     return false;
     return false;
   }
   }
 
 
+  if (_specified != other._specified) {
+    return false;
+  }
+
   for (int i = 0; i < FBP_COUNT; ++i) {
   for (int i = 0; i < FBP_COUNT; ++i) {
-    if (_specified[i] != other._specified[i]) {
-      return false;
-    }
     if (_property[i] != other._property[i]) {
     if (_property[i] != other._property[i]) {
       return false;
       return false;
     }
     }
@@ -214,9 +222,9 @@ clear() {
   _flags_specified = 0;
   _flags_specified = 0;
 
 
   for (int i = 0; i < FBP_COUNT; ++i) {
   for (int i = 0; i < FBP_COUNT; ++i) {
-    _specified[i] = 0;
     _property[i] = 0;
     _property[i] = 0;
   }
   }
+  _specified = 0;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -232,9 +240,9 @@ add_properties(const FrameBufferProperties &other) {
   _flags |= other._flags & other._flags_specified;
   _flags |= other._flags & other._flags_specified;
 
 
   for (int i = 0; i < FBP_COUNT; ++i) {
   for (int i = 0; i < FBP_COUNT; ++i) {
-    if (other._specified[i]) {
+    if (other._specified & (1 << i)) {
       _property[i] = other._property[i];
       _property[i] = other._property[i];
-      _specified[i] = true;
+      _specified |= (1 << i);
     }
     }
   }
   }
 }
 }
@@ -364,30 +372,18 @@ get_buffer_mask() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool FrameBufferProperties::
 bool FrameBufferProperties::
 is_any_specified() const {
 is_any_specified() const {
-  if (_flags_specified != 0) {
-    return true;
-  }
-
-  for (int i = 0; i < FBP_COUNT; ++i) {
-    if (_specified[i]) {
-      return true;
-    }
-  }
-  return false;
+  return (_flags_specified | _specified) != 0;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: FrameBufferProperties::set_all_specified
 //     Function: FrameBufferProperties::set_all_specified
 //       Access: Published
 //       Access: Published
-//  Description: sets all the specified bits.
+//  Description: Marks all bits as having been specified.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void FrameBufferProperties::
 void FrameBufferProperties::
 set_all_specified() {
 set_all_specified() {
   _flags_specified = FBF_all;
   _flags_specified = FBF_all;
-
-  for (int i = 0; i < FBP_COUNT; ++i) {
-    _specified[i] = true;
-  }
+  _specified = (1 << FBP_COUNT) - 1;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
panda/src/display/frameBufferProperties.h

@@ -67,7 +67,7 @@ private:
   };
   };
 
 
   int _property[FBP_COUNT];
   int _property[FBP_COUNT];
-  bool _specified[FBP_COUNT];
+  int _specified;
 
 
   int _flags;
   int _flags;
   int _flags_specified;
   int _flags_specified;

+ 3 - 3
panda/src/distort/nonlinearImager.cxx

@@ -27,7 +27,7 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: NonlinearImager::Constructor
 //     Function: NonlinearImager::Constructor
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 NonlinearImager::
 NonlinearImager::
 NonlinearImager() {
 NonlinearImager() {
@@ -38,7 +38,7 @@ NonlinearImager() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: NonlinearImager::Destructor
 //     Function: NonlinearImager::Destructor
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 NonlinearImager::
 NonlinearImager::
 ~NonlinearImager() {
 ~NonlinearImager() {
@@ -54,7 +54,7 @@ NonlinearImager::
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: NonlinearImager::add_screen
 //     Function: NonlinearImager::add_screen
 //       Access: Published
 //       Access: Published
-//               This version of this method is deprecated and will
+//  Description: This version of this method is deprecated and will
 //               soon be removed.  Use the version that takes two
 //               soon be removed.  Use the version that takes two
 //               parameters instead.
 //               parameters instead.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 8 - 3
panda/src/doc/eggSyntax.txt

@@ -1476,6 +1476,10 @@ GROUPING ENTRIES
     its geometry is used to define the extent of the collision
     its geometry is used to define the extent of the collision
     surface (unless the "descend" flag is given; see below).
     surface (unless the "descend" flag is given; see below).
 
 
+    It is now deprecated to use <Collide> without "descend"; it will
+    become the default soon.  You should always specify it for best
+    compatibility.
+
     Valid types so far are:
     Valid types so far are:
 
 
     Plane
     Plane
@@ -1538,11 +1542,12 @@ GROUPING ENTRIES
 
 
     descend
     descend
 
 
-      Instead of creating only one collision object of the given type,
-      each group descended from this node that contains geometry will
+      Each group descended from this node that contains geometry will
       define a new collision object of the given type.  The event
       define a new collision object of the given type.  The event
       name, if any, will also be inherited from the top node and
       name, if any, will also be inherited from the top node and
-      shared among all the collision objects.
+      shared among all the collision objects.  This option will soon
+      be the default; it is suggested that it is always specified for
+      most compatibility.
 
 
     keep
     keep
  
  

+ 4 - 0
panda/src/egg2pg/eggLoader.cxx

@@ -2970,6 +2970,10 @@ make_collision_solids(EggGroup *start_group, EggGroup *egg_group,
         make_collision_solids(start_group, DCAST(EggGroup, *ci), cnode);
         make_collision_solids(start_group, DCAST(EggGroup, *ci), cnode);
       }
       }
     }
     }
+  } else {
+    egg2pg_cat.warning()
+      << "Using <Collide> without 'descend' is deprecated.  'descend' "
+      << "will become the default in a future version of Panda3D.\n";
   }
   }
 }
 }
 
 

+ 7 - 21
panda/src/glstuff/glCgShaderContext_src.cxx

@@ -41,7 +41,6 @@ CLP(CgShaderContext)::
 CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext(s) {
 CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext(s) {
   _glgsg = glgsg;
   _glgsg = glgsg;
   _cg_program = 0;
   _cg_program = 0;
-  _glsl_profile = false;
 
 
   nassertv(s->get_language() == Shader::SL_Cg);
   nassertv(s->get_language() == Shader::SL_Cg);
 
 
@@ -63,10 +62,6 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte
     release_resources();
     release_resources();
 
 
   } else {
   } else {
-    if (cgGetProgramProfile(_cg_program) == CG_PROFILE_GLSLC) {
-      _glsl_profile = true;
-    }
-
     cgGLLoadProgram(_cg_program);
     cgGLLoadProgram(_cg_program);
     CGerror error = cgGetError();
     CGerror error = cgGetError();
     if (error != CG_NO_ERROR) {
     if (error != CG_NO_ERROR) {
@@ -351,14 +346,7 @@ issue_parameters(int altered) {
     if (altered & (_shader->_mat_spec[i]._dep[0] | _shader->_mat_spec[i]._dep[1])) {
     if (altered & (_shader->_mat_spec[i]._dep[0] | _shader->_mat_spec[i]._dep[1])) {
       const LMatrix4 *val = _glgsg->fetch_specified_value(_shader->_mat_spec[i], altered);
       const LMatrix4 *val = _glgsg->fetch_specified_value(_shader->_mat_spec[i], altered);
       if (!val) continue;
       if (!val) continue;
-#ifndef STDFLOAT_DOUBLE
-      // In this case, the data is already single-precision.
-      const PN_float32 *data = val->get_data();
-#else
-      // In this case, we have to convert it.
-      LMatrix4f valf = LCAST(PN_float32, *val);
-      const PN_float32 *data = valf.get_data();
-#endif
+      const PN_stdfloat *data = val->get_data();
 
 
       CGparameter p = _cg_parameter_map[_shader->_mat_spec[i]._id._seqno];
       CGparameter p = _cg_parameter_map[_shader->_mat_spec[i]._id._seqno];
       switch (_shader->_mat_spec[i]._piece) {
       switch (_shader->_mat_spec[i]._piece) {
@@ -377,13 +365,13 @@ issue_parameters(int altered) {
       case Shader::SMP_row3x3: GLfv(cgGLSetParameter3)(p, data+12); continue;
       case Shader::SMP_row3x3: GLfv(cgGLSetParameter3)(p, data+12); continue;
       case Shader::SMP_upper3x3:
       case Shader::SMP_upper3x3:
         {
         {
-          LMatrix3f upper3 = val->get_upper_3();
+          LMatrix3 upper3 = val->get_upper_3();
           GLfc(cgGLSetMatrixParameter)(p, upper3.get_data());
           GLfc(cgGLSetMatrixParameter)(p, upper3.get_data());
           continue;
           continue;
         }
         }
       case Shader::SMP_transpose3x3:
       case Shader::SMP_transpose3x3:
         {
         {
-          LMatrix3f upper3 = val->get_upper_3();
+          LMatrix3 upper3 = val->get_upper_3();
           GLfr(cgGLSetMatrixParameter)(p, upper3.get_data());
           GLfr(cgGLSetMatrixParameter)(p, upper3.get_data());
           continue;
           continue;
         }
         }
@@ -412,7 +400,7 @@ disable_shader_vertex_arrays() {
     CGparameter p = _cg_parameter_map[_shader->_var_spec[i]._id._seqno];
     CGparameter p = _cg_parameter_map[_shader->_var_spec[i]._id._seqno];
     if (p == 0) continue;
     if (p == 0) continue;
 
 
-    if (_glsl_profile && cgGetParameterBaseResource(p) == CG_ATTR0) {
+    if (cgGetParameterBaseResource(p) == CG_ATTR0) {
       int index = cgGetParameterResourceIndex(p);
       int index = cgGetParameterResourceIndex(p);
       if (index >= 8) {
       if (index >= 8) {
         _glgsg->_glClientActiveTexture(GL_TEXTURE0 + (index - 8));
         _glgsg->_glClientActiveTexture(GL_TEXTURE0 + (index - 8));
@@ -501,11 +489,9 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
           num_values = GL_BGRA;
           num_values = GL_BGRA;
         }
         }
 
 
-        // This is truly the most preposterous hack.  When using the GLSL
-        // profiles, cgGLSetParameterPointer relies on the the driver mapping
-        // standard attributes to fixed indices (and breaking the spec doing
-        // so), which only the NVIDIA drivers do.  Unbelievable.
-        if (_glsl_profile && cgGetParameterBaseResource(p) == CG_ATTR0) {
+        // cgGLSetParameterPointer is just stupidly bugged on every level.
+        // Sigh.  This seems to work on both NVIDIA and AMD cards now.
+        if (cgGetParameterBaseResource(p) == CG_ATTR0) {
           int index = cgGetParameterResourceIndex(p);
           int index = cgGetParameterResourceIndex(p);
           switch (index) {
           switch (index) {
           case 0:  // gl_Vertex
           case 0:  // gl_Vertex

+ 0 - 1
panda/src/glstuff/glCgShaderContext_src.h

@@ -52,7 +52,6 @@ public:
 
 
 private:
 private:
   CGprogram _cg_program;
   CGprogram _cg_program;
-  bool _glsl_profile;
 
 
   pvector<CGparameter> _cg_parameter_map;
   pvector<CGparameter> _cg_parameter_map;
 
 

+ 82 - 73
panda/src/glstuff/glGraphicsBuffer_src.cxx

@@ -30,10 +30,10 @@ CLP(GraphicsBuffer)(GraphicsEngine *engine, GraphicsPipe *pipe,
   GraphicsBuffer(engine, pipe, name, fb_prop, win_prop, flags, gsg, host),
   GraphicsBuffer(engine, pipe, name, fb_prop, win_prop, flags, gsg, host),
   _bind_texture_pcollector(_draw_window_pcollector, "Bind textures"),
   _bind_texture_pcollector(_draw_window_pcollector, "Bind textures"),
   _generate_mipmap_pcollector(_draw_window_pcollector, "Generate mipmaps"),
   _generate_mipmap_pcollector(_draw_window_pcollector, "Generate mipmaps"),
-  _resolve_multisample_pcollector(_draw_window_pcollector, "Resolve multisamples")
+  _resolve_multisample_pcollector(_draw_window_pcollector, "Resolve multisamples"),
+  _requested_multisamples(0),
+  _requested_coverage_samples(0)
 {
 {
-  CLP(GraphicsStateGuardian) *glgsg;
-
   // A FBO doesn't have a back buffer.
   // A FBO doesn't have a back buffer.
   _draw_buffer_type       = RenderBuffer::T_front;
   _draw_buffer_type       = RenderBuffer::T_front;
   _screenshot_buffer_type = RenderBuffer::T_front;
   _screenshot_buffer_type = RenderBuffer::T_front;
@@ -42,36 +42,6 @@ CLP(GraphicsBuffer)(GraphicsEngine *engine, GraphicsPipe *pipe,
   _fbo_multisample = 0;
   _fbo_multisample = 0;
   _initial_clear = true;
   _initial_clear = true;
   _needs_rebuild = true;
   _needs_rebuild = true;
-  DCAST_INTO_V(glgsg, _gsg);
-
-  if (glgsg->get_supports_framebuffer_multisample() && glgsg->get_supports_framebuffer_blit()) {
-    _requested_multisamples = fb_prop.get_multisamples();
-  } else {
-    _requested_multisamples = 0;
-  }
-
-  if (glgsg->get_supports_framebuffer_multisample_coverage_nv() && glgsg->get_supports_framebuffer_blit()) {
-    _requested_coverage_samples = fb_prop.get_coverage_samples();
-    // Note:  Only 4 and 8 actual samples are supported by the extension, with 8 or 16 coverage samples.
-    if ((_requested_coverage_samples <= 8) && (_requested_coverage_samples > 0)) {
-      _requested_multisamples = 4;
-      _requested_coverage_samples = 8;
-    } else if (_requested_coverage_samples > 8) {
-      if (_requested_multisamples < 8) {
-        _requested_multisamples = 4;
-      } else {
-        _requested_multisamples = 8;
-      }
-      _requested_coverage_samples = 16;
-    }
-
-  } else {
-    _requested_coverage_samples = 0;
-  }
-
-  if (_requested_multisamples > glgsg->_max_fb_samples) {
-    _requested_multisamples = glgsg->_max_fb_samples;
-  }
 
 
   _rb_size_x = 0;
   _rb_size_x = 0;
   _rb_size_y = 0;
   _rb_size_y = 0;
@@ -382,9 +352,9 @@ rebuild_bitplanes() {
     }
     }
   }
   }
 
 
-  // Decide whether we should use a depth stencil or just a regular depth attachment.
-  // If nothing was attached to either RTP_depth_stencil or RTP_depth, we use a
-  // depth-stencil renderbuffer.
+  // Decide whether we should use a depth stencil or just a regular depth
+  // attachment.  If nothing was attached to either RTP_depth_stencil or
+  // RTP_depth, we use a depth-stencil renderbuffer.
   _use_depth_stencil = false;
   _use_depth_stencil = false;
   if (_gsg->get_supports_depth_stencil()) {
   if (_gsg->get_supports_depth_stencil()) {
     if (attach[RTP_depth_stencil]) {
     if (attach[RTP_depth_stencil]) {
@@ -396,19 +366,16 @@ rebuild_bitplanes() {
       // explicitly bound something to RTP_depth.
       // explicitly bound something to RTP_depth.
       _use_depth_stencil = false;
       _use_depth_stencil = false;
 
 
-    } else if (_fb_properties.get_float_depth()) {
-      // Let's not bother with a depth-stencil buffer
-      // if a float buffer was requested.
-      _use_depth_stencil = false;
-
-    } else if (_fb_properties.get_depth_bits() > 24) {
-      // We can't give more than 24 depth bits with a depth-stencil buffer.
-      _use_depth_stencil = false;
-
     } else if (_fb_properties.get_stencil_bits() > 0) {
     } else if (_fb_properties.get_stencil_bits() > 0) {
       // The user requested stencil bits.  Let's take the hint.
       // The user requested stencil bits.  Let's take the hint.
       _use_depth_stencil = true;
       _use_depth_stencil = true;
 
 
+    } else if (_fb_properties.get_depth_bits() > 24 ||
+               _fb_properties.get_float_depth()) {
+      // 32-bit float depth is supported in conjunction with depth stencil,
+      // but it's a waste.  Let's not do it unless the user requested stencil.
+      _use_depth_stencil = false;
+
     } else if (_fb_properties.get_depth_bits() > 0) {
     } else if (_fb_properties.get_depth_bits() > 0) {
       // Let's use a depth stencil buffer by default, if a depth
       // Let's use a depth stencil buffer by default, if a depth
       // buffer was requested.
       // buffer was requested.
@@ -416,10 +383,9 @@ rebuild_bitplanes() {
     }
     }
   }
   }
 
 
-  // Knowing this, we can already be a tiny bit
-  // more accurate about the framebuffer properties.
+  // Knowing this, we can already be a tiny bit more accurate about the
+  // framebuffer properties.
   if (_use_depth_stencil) {
   if (_use_depth_stencil) {
-    _fb_properties.set_depth_bits(24);
     _fb_properties.set_stencil_bits(8);
     _fb_properties.set_stencil_bits(8);
   } else {
   } else {
     _fb_properties.set_stencil_bits(0);
     _fb_properties.set_stencil_bits(0);
@@ -553,8 +519,7 @@ rebuild_bitplanes() {
 #endif  // OPENGLES
 #endif  // OPENGLES
 
 
   if (!_have_any_color) {
   if (!_have_any_color) {
-    _fb_properties.set_color_bits(0);
-    _fb_properties.set_alpha_bits(0);
+    _fb_properties.set_rgba_bits(0, 0, 0, 0);
   }
   }
 
 
   _initial_clear = false;
   _initial_clear = false;
@@ -699,8 +664,7 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
         glGetTexLevelParameteriv(target, 0, GL_TEXTURE_BLUE_SIZE, &blue_size);
         glGetTexLevelParameteriv(target, 0, GL_TEXTURE_BLUE_SIZE, &blue_size);
         glGetTexLevelParameteriv(target, 0, GL_TEXTURE_ALPHA_SIZE, &alpha_size);
         glGetTexLevelParameteriv(target, 0, GL_TEXTURE_ALPHA_SIZE, &alpha_size);
 
 
-        _fb_properties.set_color_bits(red_size + green_size + blue_size);
-        _fb_properties.set_alpha_bits(alpha_size);
+        _fb_properties.set_rgba_bits(red_size, green_size, blue_size, alpha_size);
       }
       }
 #endif
 #endif
     }
     }
@@ -717,6 +681,7 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
     // No texture to bind.  Instead, create a renderbuffer.
     // No texture to bind.  Instead, create a renderbuffer.
     // Choose a suitable renderbuffer format based on the requirements.
     // Choose a suitable renderbuffer format based on the requirements.
 #ifdef OPENGLES
 #ifdef OPENGLES
+    // OpenGL ES case.
     GLuint gl_format = GL_RGBA4;
     GLuint gl_format = GL_RGBA4;
     switch (slot) {
     switch (slot) {
     case RTP_depth_stencil:
     case RTP_depth_stencil:
@@ -731,6 +696,7 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
         gl_format = GL_DEPTH_COMPONENT16;
         gl_format = GL_DEPTH_COMPONENT16;
       }
       }
       break;
       break;
+    //NB: we currently use RTP_stencil to store the right eye for stereo.
     //case RTP_stencil:
     //case RTP_stencil:
     //  gl_format = GL_STENCIL_INDEX8;
     //  gl_format = GL_STENCIL_INDEX8;
     //  break
     //  break
@@ -762,7 +728,8 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
     GLuint gl_format = GL_RGBA;
     GLuint gl_format = GL_RGBA;
     switch (slot) {
     switch (slot) {
       case RTP_depth_stencil:
       case RTP_depth_stencil:
-        if (_fb_properties.get_float_depth()) {
+        if (_fb_properties.get_depth_bits() > 24 ||
+            _fb_properties.get_float_depth()) {
           gl_format = GL_DEPTH32F_STENCIL8;
           gl_format = GL_DEPTH32F_STENCIL8;
         } else {
         } else {
           gl_format = GL_DEPTH24_STENCIL8;
           gl_format = GL_DEPTH24_STENCIL8;
@@ -775,7 +742,7 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
           gl_format = GL_DEPTH_COMPONENT32;
           gl_format = GL_DEPTH_COMPONENT32;
         } else if (_fb_properties.get_depth_bits() > 16) {
         } else if (_fb_properties.get_depth_bits() > 16) {
           gl_format = GL_DEPTH_COMPONENT24;
           gl_format = GL_DEPTH_COMPONENT24;
-        } else if (_fb_properties.get_depth_bits() > 8) {
+        } else if (_fb_properties.get_depth_bits() > 1) {
           gl_format = GL_DEPTH_COMPONENT16;
           gl_format = GL_DEPTH_COMPONENT16;
         } else {
         } else {
           gl_format = GL_DEPTH_COMPONENT;
           gl_format = GL_DEPTH_COMPONENT;
@@ -903,8 +870,7 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
         glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_GREEN_SIZE_EXT, &green_size);
         glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_GREEN_SIZE_EXT, &green_size);
         glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_BLUE_SIZE_EXT, &blue_size);
         glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_BLUE_SIZE_EXT, &blue_size);
         glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_ALPHA_SIZE_EXT, &alpha_size);
         glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_ALPHA_SIZE_EXT, &alpha_size);
-        _fb_properties.set_color_bits(red_size + green_size + blue_size);
-        _fb_properties.set_alpha_bits(alpha_size);
+        _fb_properties.set_rgba_bits(red_size, green_size, blue_size, alpha_size);
       }
       }
       glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, 0);
       glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, 0);
       glgsg->_glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, attachpoint,
       glgsg->_glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, attachpoint,
@@ -976,7 +942,6 @@ bind_slot_multisample(bool rb_resize, Texture **attach, RenderTexturePlane slot,
             format = GL_DEPTH_COMPONENT32;
             format = GL_DEPTH_COMPONENT32;
             break;
             break;
           default:
           default:
-            format = GL_DEPTH_COMPONENT;
             break;
             break;
         }
         }
       }
       }
@@ -1269,14 +1234,12 @@ open_buffer() {
 
 
   // Describe the framebuffer properties of the FBO.
   // Describe the framebuffer properties of the FBO.
   //
   //
-  // Unfortunately, we can't possibly predict which formats
+  // Unfortunately, we can't currently predict which formats
   // the implementation will allow us to use at this point, so
   // the implementation will allow us to use at this point, so
   // we'll just have to make some guesses and parrot the rest
   // we'll just have to make some guesses and parrot the rest
   // of the properties back to the user.
   // of the properties back to the user.
   // When we actually attach the textures, we'll update the
   // When we actually attach the textures, we'll update the
   // properties more appropriately.
   // properties more appropriately.
-  // This is probably safe, as we can usually bind just about
-  // any supported texture format to the FBO.
 
 
   // Rounding the depth bits is not spectacular, but at least we're
   // Rounding the depth bits is not spectacular, but at least we're
   // telling the user *something* about what we're going to get.
   // telling the user *something* about what we're going to get.
@@ -1286,6 +1249,9 @@ open_buffer() {
   if (_fb_properties.get_color_bits() == 0 &&
   if (_fb_properties.get_color_bits() == 0 &&
       _fb_properties.get_rgb_color()) {
       _fb_properties.get_rgb_color()) {
     _fb_properties.set_color_bits(1);
     _fb_properties.set_color_bits(1);
+    _fb_properties.set_red_bits(1);
+    _fb_properties.set_green_bits(1);
+    _fb_properties.set_blue_bits(1);
   }
   }
 
 
   // Actually, let's always get a colour buffer for now until we
   // Actually, let's always get a colour buffer for now until we
@@ -1294,18 +1260,28 @@ open_buffer() {
     _fb_properties.set_color_bits(1);
     _fb_properties.set_color_bits(1);
   }
   }
 
 
-  if (_fb_properties.get_depth_bits() >= 32) {
+  if (_fb_properties.get_depth_bits() > 24) {
     _fb_properties.set_depth_bits(32);
     _fb_properties.set_depth_bits(32);
   } else if (_fb_properties.get_depth_bits() > 16) {
   } else if (_fb_properties.get_depth_bits() > 16) {
     _fb_properties.set_depth_bits(24);
     _fb_properties.set_depth_bits(24);
-  } else if (_fb_properties.get_depth_bits() > 8) {
+  } else {
     _fb_properties.set_depth_bits(16);
     _fb_properties.set_depth_bits(16);
   }
   }
 
 
-  // We're not going to get more than this, ever.
+  // We're not going to get more than this, ever.  At least not until OpenGL
+  // introduces 64-bit texture formats.
   if (_fb_properties.get_color_bits() > 96) {
   if (_fb_properties.get_color_bits() > 96) {
     _fb_properties.set_color_bits(96);
     _fb_properties.set_color_bits(96);
   }
   }
+  if (_fb_properties.get_red_bits() > 32) {
+    _fb_properties.set_red_bits(32);
+  }
+  if (_fb_properties.get_green_bits() > 32) {
+    _fb_properties.set_green_bits(32);
+  }
+  if (_fb_properties.get_blue_bits() > 32) {
+    _fb_properties.set_blue_bits(32);
+  }
   if (_fb_properties.get_alpha_bits() > 32) {
   if (_fb_properties.get_alpha_bits() > 32) {
     _fb_properties.set_alpha_bits(32);
     _fb_properties.set_alpha_bits(32);
   }
   }
@@ -1317,30 +1293,63 @@ open_buffer() {
 
 
   // We currently only support color formats this big as float.
   // We currently only support color formats this big as float.
   if (_fb_properties.get_color_bits() > 16 * 3) {
   if (_fb_properties.get_color_bits() > 16 * 3) {
-    _fb_properties.set_color_bits(32 * 3);
     _fb_properties.set_float_color(true);
     _fb_properties.set_float_color(true);
-
-    if (_fb_properties.get_alpha_bits() > 0) {
-      _fb_properties.set_alpha_bits(32);
-    }
   }
   }
 
 
   if (_fb_properties.get_srgb_color()) {
   if (_fb_properties.get_srgb_color()) {
-    _fb_properties.set_color_bits(24);
+    // This is the only sRGB color format OpenGL supports.
+    _fb_properties.set_rgba_bits(8, 8, 8,
+      (_fb_properties.get_alpha_bits() > 0) ? 8 : 0);
     _fb_properties.set_float_color(false);
     _fb_properties.set_float_color(false);
-
-    if (_fb_properties.get_alpha_bits() > 0) {
-      _fb_properties.set_alpha_bits(32);
-    }
   }
   }
 
 
   if (!_gsg->get_supports_depth_stencil()) {
   if (!_gsg->get_supports_depth_stencil()) {
     // At least we know we won't be getting stencil bits.
     // At least we know we won't be getting stencil bits.
     _fb_properties.set_stencil_bits(0);
     _fb_properties.set_stencil_bits(0);
+
+  } else if (_fb_properties.get_stencil_bits() > 0) {
+    // We don't currently support stencil-only targets.
+    _fb_properties.set_stencil_bits(8);
+    if (_fb_properties.get_depth_bits() < 24) {
+      _fb_properties.set_depth_bits(24);
+    }
   }
   }
+
+  // Accumulation buffers aren't supported for FBOs.
   _fb_properties.set_accum_bits(0);
   _fb_properties.set_accum_bits(0);
 
 
+  if (glgsg->get_supports_framebuffer_multisample() && glgsg->get_supports_framebuffer_blit()) {
+    _requested_multisamples = _fb_properties.get_multisamples();
+  } else {
+    _requested_multisamples = 0;
+  }
+
+#ifndef OPENGLES
+  if (glgsg->get_supports_framebuffer_multisample_coverage_nv() && glgsg->get_supports_framebuffer_blit()) {
+    _requested_coverage_samples = _fb_properties.get_coverage_samples();
+    // Note:  Only 4 and 8 actual samples are supported by the extension, with 8 or 16 coverage samples.
+    if ((_requested_coverage_samples <= 8) && (_requested_coverage_samples > 0)) {
+      _requested_multisamples = 4;
+      _requested_coverage_samples = 8;
+    } else if (_requested_coverage_samples > 8) {
+      if (_requested_multisamples < 8) {
+        _requested_multisamples = 4;
+      } else {
+        _requested_multisamples = 8;
+      }
+      _requested_coverage_samples = 16;
+    }
+
+  } else {
+    _requested_coverage_samples = 0;
+  }
+#endif
+
+  if (_requested_multisamples > glgsg->_max_fb_samples) {
+    _requested_multisamples = glgsg->_max_fb_samples;
+  }
   _fb_properties.set_multisamples(_requested_multisamples);
   _fb_properties.set_multisamples(_requested_multisamples);
+  _fb_properties.set_coverage_samples(_requested_coverage_samples);
 
 
   // Update aux settings to reflect the GL_MAX_DRAW_BUFFERS limit,
   // Update aux settings to reflect the GL_MAX_DRAW_BUFFERS limit,
   // if we exceed it, that is.
   // if we exceed it, that is.

+ 8 - 0
panda/src/glstuff/glShaderContext_src.cxx

@@ -1069,13 +1069,21 @@ issue_parameters(int altered) {
       case Shader::SMP_row3x3: _glgsg->_glUniform3fv(p, 1, data+12); continue;
       case Shader::SMP_row3x3: _glgsg->_glUniform3fv(p, 1, data+12); continue;
       case Shader::SMP_upper3x3:
       case Shader::SMP_upper3x3:
         {
         {
+#ifndef STDFLOAT_DOUBLE
           LMatrix3f upper3 = val->get_upper_3();
           LMatrix3f upper3 = val->get_upper_3();
+#else
+          LMatrix3f upper3 = valf.get_upper_3();
+#endif
           _glgsg->_glUniformMatrix3fv(p, 1, false, upper3.get_data());
           _glgsg->_glUniformMatrix3fv(p, 1, false, upper3.get_data());
           continue;
           continue;
         }
         }
       case Shader::SMP_transpose3x3:
       case Shader::SMP_transpose3x3:
         {
         {
+#ifndef STDFLOAT_DOUBLE
           LMatrix3f upper3 = val->get_upper_3();
           LMatrix3f upper3 = val->get_upper_3();
+#else
+          LMatrix3f upper3 = valf.get_upper_3();
+#endif
           _glgsg->_glUniformMatrix3fv(p, 1, true, upper3.get_data());
           _glgsg->_glUniformMatrix3fv(p, 1, true, upper3.get_data());
           continue;
           continue;
         }
         }

+ 15 - 22
panda/src/glxdisplay/glxGraphicsPipe.cxx

@@ -136,35 +136,28 @@ make_output(const string &name,
   // Second thing to try: a GLGraphicsBuffer
   // Second thing to try: a GLGraphicsBuffer
 
 
   if (retry == 1) {
   if (retry == 1) {
-    if ((host==0)||
-        (!gl_support_fbo)||
-        ((flags&BF_require_parasite)!=0)||
-        ((flags&BF_require_window)!=0)) {
+    if (!gl_support_fbo || host == NULL ||
+        (flags & (BF_require_parasite | BF_require_window)) != 0) {
       return NULL;
       return NULL;
     }
     }
     // Early failure - if we are sure that this buffer WONT
     // Early failure - if we are sure that this buffer WONT
     // meet specs, we can bail out early.
     // meet specs, we can bail out early.
-    int _fbo_multisample = 0;
-    if (!ConfigVariableBool("framebuffer-object-multisample", false, PRC_DESC("Enabled Multisample."))) {
-      _fbo_multisample = 16;
-    }
-    if ((flags & BF_fb_props_optional)==0) {
-      if ((fb_prop.get_indexed_color() > 0)||
-          (fb_prop.get_back_buffers() > 0)||
-          (fb_prop.get_accum_bits() > 0)||
-          (fb_prop.get_multisamples() > _fbo_multisample)) {
+    if ((flags & BF_fb_props_optional) == 0) {
+      if (fb_prop.get_indexed_color() ||
+          fb_prop.get_back_buffers() > 0 ||
+          fb_prop.get_accum_bits() > 0) {
         return NULL;
         return NULL;
       }
       }
     }
     }
-    // Early success - if we are sure that this buffer WILL
-    // meet specs, we can precertify it.
-    if ((posixgsg != 0) &&
-        (posixgsg->is_valid()) &&
-        (!posixgsg->needs_reset()) &&
-        (posixgsg->_supports_framebuffer_object) &&
-        (posixgsg->_glDrawBuffers != 0)&&
-        (fb_prop.is_basic())) {
-      precertify = true;
+    if (posixgsg != NULL && posixgsg->is_valid() && !posixgsg->needs_reset()) {
+      if (!posixgsg->_supports_framebuffer_object ||
+          posixgsg->_glDrawBuffers == NULL) {
+        return NULL;
+      } else {
+        // Early success - if we are sure that this buffer WILL
+        // meet specs, we can precertify it.
+        precertify = true;
+      }
     }
     }
     return new GLGraphicsBuffer(engine, this, name, fb_prop, win_prop,
     return new GLGraphicsBuffer(engine, this, name, fb_prop, win_prop,
                                 flags, gsg, host);
                                 flags, gsg, host);

+ 77 - 72
panda/src/gobj/texture.cxx

@@ -41,6 +41,7 @@
 #include "pbitops.h"
 #include "pbitops.h"
 #include "streamReader.h"
 #include "streamReader.h"
 #include "texturePeeker.h"
 #include "texturePeeker.h"
+#include "convert_srgb.h"
 
 
 #ifdef HAVE_SQUISH
 #ifdef HAVE_SQUISH
 #include <squish.h>
 #include <squish.h>
@@ -131,46 +132,6 @@ struct DDSHeader {
   DDSCaps2 caps;
   DDSCaps2 caps;
 };
 };
 
 
-// This table is used for converting unsigned char texture values in an sRGB
-// texture to linear RGB values, for use in mipmap generation.
-static float srgb_to_lrgbf[256] = {0.000000f, 0.000304f, 0.000607f, 0.000911f,
-  0.001214f, 0.001518f, 0.001821f, 0.002125f, 0.002428f, 0.002732f, 0.003035f,
-  0.003347f, 0.003677f, 0.004025f, 0.004391f, 0.004777f, 0.005182f, 0.005605f,
-  0.006049f, 0.006512f, 0.006995f, 0.007499f, 0.008023f, 0.008568f, 0.009134f,
-  0.009721f, 0.010330f, 0.010960f, 0.011612f, 0.012286f, 0.012983f, 0.013702f,
-  0.014444f, 0.015209f, 0.015996f, 0.016807f, 0.017642f, 0.018500f, 0.019382f,
-  0.020289f, 0.021219f, 0.022174f, 0.023153f, 0.024158f, 0.025187f, 0.026241f,
-  0.027321f, 0.028426f, 0.029557f, 0.030713f, 0.031896f, 0.033105f, 0.034340f,
-  0.035601f, 0.036889f, 0.038204f, 0.039546f, 0.040915f, 0.042311f, 0.043735f,
-  0.045186f, 0.046665f, 0.048172f, 0.049707f, 0.051269f, 0.052861f, 0.054480f,
-  0.056128f, 0.057805f, 0.059511f, 0.061246f, 0.063010f, 0.064803f, 0.066626f,
-  0.068478f, 0.070360f, 0.072272f, 0.074214f, 0.076185f, 0.078187f, 0.080220f,
-  0.082283f, 0.084376f, 0.086500f, 0.088656f, 0.090842f, 0.093059f, 0.095307f,
-  0.097587f, 0.099899f, 0.102242f, 0.104616f, 0.107023f, 0.109462f, 0.111932f,
-  0.114435f, 0.116971f, 0.119538f, 0.122139f, 0.124772f, 0.127438f, 0.130136f,
-  0.132868f, 0.135633f, 0.138432f, 0.141263f, 0.144128f, 0.147027f, 0.149960f,
-  0.152926f, 0.155926f, 0.158961f, 0.162029f, 0.165132f, 0.168269f, 0.171441f,
-  0.174647f, 0.177888f, 0.181164f, 0.184475f, 0.187821f, 0.191202f, 0.194618f,
-  0.198069f, 0.201556f, 0.205079f, 0.208637f, 0.212231f, 0.215861f, 0.219526f,
-  0.223228f, 0.226966f, 0.230740f, 0.234551f, 0.238398f, 0.242281f, 0.246201f,
-  0.250158f, 0.254152f, 0.258183f, 0.262251f, 0.266356f, 0.270498f, 0.274677f,
-  0.278894f, 0.283149f, 0.287441f, 0.291771f, 0.296138f, 0.300544f, 0.304987f,
-  0.309469f, 0.313989f, 0.318547f, 0.323143f, 0.327778f, 0.332452f, 0.337164f,
-  0.341914f, 0.346704f, 0.351533f, 0.356400f, 0.361307f, 0.366253f, 0.371238f,
-  0.376262f, 0.381326f, 0.386429f, 0.391572f, 0.396755f, 0.401978f, 0.407240f,
-  0.412543f, 0.417885f, 0.423268f, 0.428690f, 0.434154f, 0.439657f, 0.445201f,
-  0.450786f, 0.456411f, 0.462077f, 0.467784f, 0.473531f, 0.479320f, 0.485150f,
-  0.491021f, 0.496933f, 0.502886f, 0.508881f, 0.514918f, 0.520996f, 0.527115f,
-  0.533276f, 0.539479f, 0.545724f, 0.552011f, 0.558340f, 0.564712f, 0.571125f,
-  0.577580f, 0.584078f, 0.590619f, 0.597202f, 0.603827f, 0.610496f, 0.617207f,
-  0.623960f, 0.630757f, 0.637597f, 0.644480f, 0.651406f, 0.658375f, 0.665387f,
-  0.672443f, 0.679542f, 0.686685f, 0.693872f, 0.701102f, 0.708376f, 0.715694f,
-  0.723055f, 0.730461f, 0.737910f, 0.745404f, 0.752942f, 0.760525f, 0.768151f,
-  0.775822f, 0.783538f, 0.791298f, 0.799103f, 0.806952f, 0.814847f, 0.822786f,
-  0.830770f, 0.838799f, 0.846873f, 0.854993f, 0.863157f, 0.871367f, 0.879622f,
-  0.887923f, 0.896269f, 0.904661f, 0.913099f, 0.921582f, 0.930111f, 0.938686f,
-  0.947307f, 0.955973f, 0.964686f, 0.973445f, 0.982251f, 0.991102f, 1.000000f};
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::Constructor
 //     Function: Texture::Constructor
 //       Access: Published
 //       Access: Published
@@ -4436,7 +4397,7 @@ do_get_clear_data(const CData *cdata, unsigned char *into) const {
   switch (cdata->_component_type) {
   switch (cdata->_component_type) {
   case T_unsigned_byte:
   case T_unsigned_byte:
     {
     {
-      LColorf scaled = cdata->_clear_color.fmin(LColorf(1)).fmax(LColorf::zero());
+      LColor scaled = cdata->_clear_color.fmin(LColor(1)).fmax(LColor::zero());
       scaled *= 255;
       scaled *= 255;
       switch (cdata->_num_components) {
       switch (cdata->_num_components) {
       case 2:
       case 2:
@@ -4457,7 +4418,7 @@ do_get_clear_data(const CData *cdata, unsigned char *into) const {
 
 
   case T_unsigned_short:
   case T_unsigned_short:
     {
     {
-      LColorf scaled = cdata->_clear_color.fmin(LColorf(1)).fmax(LColorf::zero());
+      LColor scaled = cdata->_clear_color.fmin(LColor(1)).fmax(LColor::zero());
       scaled *= 65535;
       scaled *= 65535;
       switch (cdata->_num_components) {
       switch (cdata->_num_components) {
       case 2:
       case 2:
@@ -6990,7 +6951,13 @@ do_filter_2d_mipmap_pages(const CData *cdata,
     // We currently only support sRGB mipmap generation for
     // We currently only support sRGB mipmap generation for
     // unsigned byte textures, due to our use of a lookup table.
     // unsigned byte textures, due to our use of a lookup table.
     nassertv(cdata->_component_type == T_unsigned_byte);
     nassertv(cdata->_component_type == T_unsigned_byte);
-    filter_component = &filter_2d_unsigned_byte_srgb;
+
+    if (has_sse2_sRGB_encode()) {
+      filter_component = &filter_2d_unsigned_byte_srgb_sse2;
+    } else {
+      filter_component = &filter_2d_unsigned_byte_srgb;
+    }
+
     // Alpha is always linear.
     // Alpha is always linear.
     filter_alpha = &filter_2d_unsigned_byte;
     filter_alpha = &filter_2d_unsigned_byte;
 
 
@@ -7140,7 +7107,13 @@ do_filter_3d_mipmap_level(const CData *cdata,
     // We currently only support sRGB mipmap generation for
     // We currently only support sRGB mipmap generation for
     // unsigned byte textures, due to our use of a lookup table.
     // unsigned byte textures, due to our use of a lookup table.
     nassertv(cdata->_component_type == T_unsigned_byte);
     nassertv(cdata->_component_type == T_unsigned_byte);
-    filter_component = &filter_3d_unsigned_byte_srgb;
+
+    if (has_sse2_sRGB_encode()) {
+      filter_component = &filter_3d_unsigned_byte_srgb_sse2;
+    } else {
+      filter_component = &filter_3d_unsigned_byte_srgb;
+    }
+
     // Alpha is always linear.
     // Alpha is always linear.
     filter_alpha = &filter_3d_unsigned_byte;
     filter_alpha = &filter_3d_unsigned_byte;
 
 
@@ -7385,18 +7358,32 @@ filter_2d_unsigned_byte(unsigned char *&p, const unsigned char *&q,
 void Texture::
 void Texture::
 filter_2d_unsigned_byte_srgb(unsigned char *&p, const unsigned char *&q,
 filter_2d_unsigned_byte_srgb(unsigned char *&p, const unsigned char *&q,
                              size_t pixel_size, size_t row_size) {
                              size_t pixel_size, size_t row_size) {
-  float result = (srgb_to_lrgbf[q[0]] +
-                  srgb_to_lrgbf[q[pixel_size]] +
-                  srgb_to_lrgbf[q[row_size]] +
-                  srgb_to_lrgbf[q[pixel_size + row_size]]) / 4.0f;
-
-  // This is based on the formula out of the EXT_texture_sRGB
-  // specification, except the factors are multiplied with 255.0f.
-  if (result < 0.0031308f) {
-    *p = (unsigned char)(result * 3294.6f);
-  } else {
-    *p = (unsigned char)(269.025f * powf(result, 0.41666f) - 14.025f);
-  }
+  float result = (decode_sRGB_float(q[0]) +
+                  decode_sRGB_float(q[pixel_size]) +
+                  decode_sRGB_float(q[row_size]) +
+                  decode_sRGB_float(q[pixel_size + row_size]));
+
+  *p = encode_sRGB_uchar(result * 0.25f);
+  ++p;
+  ++q;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::filter_2d_unsigned_byte_srgb_sse2
+//       Access: Public, Static
+//  Description: Averages a 2x2 block of pixel components into a
+//               single pixel component, for producing the next mipmap
+//               level.  Increments p and q to the next component.
+////////////////////////////////////////////////////////////////////
+void Texture::
+filter_2d_unsigned_byte_srgb_sse2(unsigned char *&p, const unsigned char *&q,
+                                  size_t pixel_size, size_t row_size) {
+  float result = (decode_sRGB_float(q[0]) +
+                  decode_sRGB_float(q[pixel_size]) +
+                  decode_sRGB_float(q[row_size]) +
+                  decode_sRGB_float(q[pixel_size + row_size]));
+
+  *p = encode_sRGB_uchar_sse2(result * 0.25f);
   ++p;
   ++p;
   ++q;
   ++q;
 }
 }
@@ -7470,22 +7457,40 @@ filter_3d_unsigned_byte(unsigned char *&p, const unsigned char *&q,
 void Texture::
 void Texture::
 filter_3d_unsigned_byte_srgb(unsigned char *&p, const unsigned char *&q,
 filter_3d_unsigned_byte_srgb(unsigned char *&p, const unsigned char *&q,
                              size_t pixel_size, size_t row_size, size_t page_size) {
                              size_t pixel_size, size_t row_size, size_t page_size) {
-  float result = (srgb_to_lrgbf[q[0]] +
-                  srgb_to_lrgbf[q[pixel_size]] +
-                  srgb_to_lrgbf[q[row_size]] +
-                  srgb_to_lrgbf[q[pixel_size + row_size]] +
-                  srgb_to_lrgbf[q[page_size]] +
-                  srgb_to_lrgbf[q[pixel_size + page_size]] +
-                  srgb_to_lrgbf[q[row_size + page_size]] +
-                  srgb_to_lrgbf[q[pixel_size + row_size + page_size]]) / 8.0f;
-
-  // This is based on the formula out of the EXT_texture_sRGB
-  // specification, except the factors are multiplied with 255.0f.
-  if (result < 0.0031308f) {
-    *p = (unsigned char)(result * 3294.6f);
-  } else {
-    *p = (unsigned char)(269.025f * powf(result, 0.41666f) - 14.025f);
-  }
+  float result = (decode_sRGB_float(q[0]) +
+                  decode_sRGB_float(q[pixel_size]) +
+                  decode_sRGB_float(q[row_size]) +
+                  decode_sRGB_float(q[pixel_size + row_size]) +
+                  decode_sRGB_float(q[page_size]) +
+                  decode_sRGB_float(q[pixel_size + page_size]) +
+                  decode_sRGB_float(q[row_size + page_size]) +
+                  decode_sRGB_float(q[pixel_size + row_size + page_size]));
+
+  *p = encode_sRGB_uchar(result * 0.125f);
+  ++p;
+  ++q;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::filter_3d_unsigned_byte_srgb_sse2
+//       Access: Public, Static
+//  Description: Averages a 2x2x2 block of pixel components into a
+//               single pixel component, for producing the next mipmap
+//               level.  Increments p and q to the next component.
+////////////////////////////////////////////////////////////////////
+void Texture::
+filter_3d_unsigned_byte_srgb_sse2(unsigned char *&p, const unsigned char *&q,
+                                  size_t pixel_size, size_t row_size, size_t page_size) {
+  float result = (decode_sRGB_float(q[0]) +
+                  decode_sRGB_float(q[pixel_size]) +
+                  decode_sRGB_float(q[row_size]) +
+                  decode_sRGB_float(q[pixel_size + row_size]) +
+                  decode_sRGB_float(q[page_size]) +
+                  decode_sRGB_float(q[pixel_size + page_size]) +
+                  decode_sRGB_float(q[row_size + page_size]) +
+                  decode_sRGB_float(q[pixel_size + row_size + page_size]));
+
+  *p = encode_sRGB_uchar_sse2(result * 0.125f);
   ++p;
   ++p;
   ++q;
   ++q;
 }
 }

+ 7 - 0
panda/src/gobj/texture.h

@@ -752,6 +752,9 @@ private:
   static void filter_2d_unsigned_byte_srgb(unsigned char *&p,
   static void filter_2d_unsigned_byte_srgb(unsigned char *&p,
                                            const unsigned char *&q,
                                            const unsigned char *&q,
                                            size_t pixel_size, size_t row_size);
                                            size_t pixel_size, size_t row_size);
+  static void filter_2d_unsigned_byte_srgb_sse2(unsigned char *&p,
+                                                const unsigned char *&q,
+                                                size_t pixel_size, size_t row_size);
   static void filter_2d_unsigned_short(unsigned char *&p,
   static void filter_2d_unsigned_short(unsigned char *&p,
                                        const unsigned char *&q,
                                        const unsigned char *&q,
                                        size_t pixel_size, size_t row_size);
                                        size_t pixel_size, size_t row_size);
@@ -766,6 +769,10 @@ private:
                                            const unsigned char *&q,
                                            const unsigned char *&q,
                                            size_t pixel_size, size_t row_size,
                                            size_t pixel_size, size_t row_size,
                                            size_t page_size);
                                            size_t page_size);
+  static void filter_3d_unsigned_byte_srgb_sse2(unsigned char *&p,
+                                                const unsigned char *&q,
+                                                size_t pixel_size, size_t row_size,
+                                                size_t page_size);
   static void filter_3d_unsigned_short(unsigned char *&p,
   static void filter_3d_unsigned_short(unsigned char *&p,
                                        const unsigned char *&q,
                                        const unsigned char *&q,
                                        size_t pixel_size, size_t row_size,
                                        size_t pixel_size, size_t row_size,

+ 8 - 8
panda/src/grutil/pfmVizzer.cxx

@@ -57,11 +57,11 @@ void PfmVizzer::
 project(const Lens *lens, const PfmFile *undist_lut) {
 project(const Lens *lens, const PfmFile *undist_lut) {
   nassertv(_pfm.is_valid());
   nassertv(_pfm.is_valid());
 
 
-  static LMatrix4f to_uv(0.5f, 0.0f, 0.0f, 0.0f,
-                         0.0f, 0.5f, 0.0f, 0.0f, 
-                         0.0f, 0.0f, 0.5f, 0.0f, 
-                         0.5f, 0.5f, 0.5f, 1.0f);
-  
+  static LMatrix4 to_uv(0.5f, 0.0f, 0.0f, 0.0f,
+                        0.0f, 0.5f, 0.0f, 0.0f,
+                        0.0f, 0.0f, 0.5f, 0.0f,
+                        0.5f, 0.5f, 0.5f, 1.0f);
+
   for (int yi = 0; yi < _pfm.get_y_size(); ++yi) {
   for (int yi = 0; yi < _pfm.get_y_size(); ++yi) {
     for (int xi = 0; xi < _pfm.get_x_size(); ++xi) {
     for (int xi = 0; xi < _pfm.get_x_size(); ++xi) {
       if (!_pfm.has_point(xi, yi)) {
       if (!_pfm.has_point(xi, yi)) {
@@ -79,8 +79,8 @@ project(const Lens *lens, const PfmFile *undist_lut) {
       } else {
       } else {
         // Now the lens gives us coordinates in the range [-1, 1].
         // Now the lens gives us coordinates in the range [-1, 1].
         // Rescale these to [0, 1].
         // Rescale these to [0, 1].
-        LPoint3f uvw = film * to_uv;
-        
+        LPoint3f uvw = LCAST(float, film * to_uv);
+
         if (undist_lut != NULL) {
         if (undist_lut != NULL) {
           // Apply the undistortion map, if given.
           // Apply the undistortion map, if given.
           LPoint3f p2;
           LPoint3f p2;
@@ -88,7 +88,7 @@ project(const Lens *lens, const PfmFile *undist_lut) {
           uvw = p2;
           uvw = p2;
           uvw[1] = 1.0 - uvw[1];
           uvw[1] = 1.0 - uvw[1];
         }
         }
-        
+
         p = uvw;
         p = uvw;
       }
       }
     }
     }

+ 2 - 0
panda/src/ode/odeRayGeom.I

@@ -11,6 +11,8 @@
 // with this source code in a file named "LICENSE."
 // with this source code in a file named "LICENSE."
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
+
+
 INLINE void OdeRayGeom::
 INLINE void OdeRayGeom::
 set_length(dReal length) {
 set_length(dReal length) {
   dGeomRaySetLength(_id, length);
   dGeomRaySetLength(_id, length);

+ 2 - 0
panda/src/ode/odeTriMeshData.h

@@ -62,6 +62,7 @@ PUBLISHED:
   // INLINE void get_buffer(unsigned char** buf, int* buf_len) const;
   // INLINE void get_buffer(unsigned char** buf, int* buf_len) const;
   // INLINE void set_buffer(unsigned char* buf);
   // INLINE void set_buffer(unsigned char* buf);
   // INLINE void update();
   // INLINE void update();
+
   virtual void write(ostream &out = cout, unsigned int indent=0) const;
   virtual void write(ostream &out = cout, unsigned int indent=0) const;
   void write_faces(ostream &out) const;
   void write_faces(ostream &out) const;
 
 
@@ -90,6 +91,7 @@ public:
                             const int* indices, int index_count, \
                             const int* indices, int index_count, \
                             const int* normals);
                             const int* normals);
   */
   */
+
   INLINE void preprocess();
   INLINE void preprocess();
 
 
   INLINE dTriMeshDataID get_id() const;
   INLINE dTriMeshDataID get_id() const;

+ 17 - 22
panda/src/osxdisplay/osxGraphicsPipe.cxx

@@ -412,37 +412,32 @@ make_output(const string &name,
     return new osxGraphicsWindow(engine, this, name, fb_prop, win_prop,
     return new osxGraphicsWindow(engine, this, name, fb_prop, win_prop,
                                  flags, gsg, host);
                                  flags, gsg, host);
   }
   }
-  
+
   // Second thing to try: a GLGraphicsBuffer
   // Second thing to try: a GLGraphicsBuffer
-  
+
   if (retry == 1) {
   if (retry == 1) {
-    if (!osx_support_gl_buffer) {
-      return NULL;
-    }
-    if ((host==0)||
-        ((flags&BF_require_parasite)!=0)||
-        ((flags&BF_require_window)!=0)) {
+    if (!osx_support_gl_buffer || !gl_support_fbo || host == NULL ||
+        (flags & (BF_require_parasite | BF_require_window)) != 0) {
       return NULL;
       return NULL;
     }
     }
     // Early failure - if we are sure that this buffer WONT
     // Early failure - if we are sure that this buffer WONT
     // meet specs, we can bail out early.
     // meet specs, we can bail out early.
-    if ((flags & BF_fb_props_optional)==0) {
-      if ((fb_prop.get_indexed_color() > 0)||
-          (fb_prop.get_back_buffers() > 0)||
-          (fb_prop.get_accum_bits() > 0)||
-          (fb_prop.get_multisamples() > 0)) {
+    if ((flags & BF_fb_props_optional) == 0) {
+      if (fb_prop.get_indexed_color() ||
+          fb_prop.get_back_buffers() > 0 ||
+          fb_prop.get_accum_bits() > 0) {
         return NULL;
         return NULL;
       }
       }
     }
     }
-    // Early success - if we are sure that this buffer WILL
-    // meet specs, we can precertify it.
-    if ((osxgsg != 0) &&
-        (osxgsg->is_valid()) &&
-        (!osxgsg->needs_reset()) &&
-        (osxgsg->_supports_framebuffer_object) &&
-        (osxgsg->_glDrawBuffers != 0)&&
-        (fb_prop.is_basic())) {
-      precertify = true;
+    if (posixgsg != NULL && posixgsg->is_valid() && !posixgsg->needs_reset()) {
+      if (!posixgsg->_supports_framebuffer_object ||
+          posixgsg->_glDrawBuffers == NULL) {
+        return NULL;
+      } else {
+        // Early success - if we are sure that this buffer WILL
+        // meet specs, we can precertify it.
+        precertify = true;
+      }
     }
     }
     return new GLGraphicsBuffer(engine, this, name, fb_prop, win_prop, flags, gsg, host);
     return new GLGraphicsBuffer(engine, this, name, fb_prop, win_prop, flags, gsg, host);
   }
   }

+ 1 - 1
panda/src/pgraph/cullBinManager.h

@@ -99,7 +99,7 @@ private:
   class EXPCL_PANDA_PGRAPH BinDefinition {
   class EXPCL_PANDA_PGRAPH BinDefinition {
   public:
   public:
 #ifndef NDEBUG
 #ifndef NDEBUG
-    LColorf _flash_color;
+    LColor _flash_color;
     bool _flash_active;
     bool _flash_active;
 #endif
 #endif
     bool _in_use;
     bool _in_use;

+ 7 - 5
panda/src/pgraph/pandaNode.I

@@ -721,13 +721,15 @@ get_user_bounds(int pipeline_stage, Thread *current_thread) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void PandaNode::
 INLINE void PandaNode::
 mark_bounds_stale(int pipeline_stage, Thread *current_thread) const {
 mark_bounds_stale(int pipeline_stage, Thread *current_thread) const {
-  // It's important that we don't hold the lock during the call to
-  // force_bounds_stale().
+  // We check whether it is already marked stale.  If so, we don't have
+  // to make the call to force_bounds_stale().
   bool is_stale_bounds;
   bool is_stale_bounds;
   {
   {
     CDStageReader cdata(_cycler, pipeline_stage, current_thread);
     CDStageReader cdata(_cycler, pipeline_stage, current_thread);
-    is_stale_bounds = (cdata->_last_bounds_update != cdata->_next_update);
+    is_stale_bounds = (cdata->_last_update != cdata->_next_update);
   }
   }
+  // It's important that we don't hold the lock during the call to
+  // force_bounds_stale().
   if (!is_stale_bounds) {
   if (!is_stale_bounds) {
     ((PandaNode *)this)->force_bounds_stale(pipeline_stage, current_thread);
     ((PandaNode *)this)->force_bounds_stale(pipeline_stage, current_thread);
   }
   }
@@ -1833,7 +1835,7 @@ get_off_clip_planes() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE CPT(BoundingVolume) PandaNodePipelineReader::
 INLINE CPT(BoundingVolume) PandaNodePipelineReader::
 get_bounds() const {
 get_bounds() const {
-  nassertr(_cdata->_last_update == _cdata->_next_update, _cdata->_external_bounds);
+  nassertr(_cdata->_last_bounds_update == _cdata->_next_update, _cdata->_external_bounds);
   return _cdata->_external_bounds;
   return _cdata->_external_bounds;
 }
 }
 
 
@@ -1852,7 +1854,7 @@ get_bounds() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE int PandaNodePipelineReader::
 INLINE int PandaNodePipelineReader::
 get_nested_vertices() const {
 get_nested_vertices() const {
-  nassertr(_cdata->_last_update == _cdata->_next_update, _cdata->_nested_vertices);
+  nassertr(_cdata->_last_bounds_update == _cdata->_next_update, _cdata->_nested_vertices);
   return _cdata->_nested_vertices;
   return _cdata->_nested_vertices;
 }
 }
 
 

+ 175 - 0
panda/src/pnmimage/convert_srgb.I

@@ -0,0 +1,175 @@
+// Filename: convert_srgb.I
+// Created by:  rdb (29Oct14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: decode_sRGB_float
+//  Description: Decodes the sRGB-encoded unsigned char value to
+//               a linearized float in the range 0-1.
+////////////////////////////////////////////////////////////////////
+CONSTEXPR float decode_sRGB_float(unsigned char val) {
+  return to_linear_float_table[val];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: encode_sRGB_float
+//  Description: Decodes the sRGB-encoded floating-point value in
+//               the range 0-1 to a linearized float in the range
+//               0-1.  Inputs outside this range produce invalid
+//               results.
+////////////////////////////////////////////////////////////////////
+INLINE float decode_sRGB_float(float val) {
+  return (val <= 0.04045f)
+    ? (val * (1.f / 12.92f))
+    : cpow((val + 0.055f) * (1.f / 1.055f), 2.4f);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: decode_sRGB_uchar
+//  Description: Decodes the sRGB-encoded unsigned char value to
+//               a linearized unsigned char value.
+////////////////////////////////////////////////////////////////////
+CONSTEXPR unsigned char decode_sRGB_uchar(unsigned char val) {
+  return to_linear_uchar_table[val];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: decode_sRGB_uchar
+//  Description: Decodes the sRGB-encoded floating-point value in
+//               the range 0-1 to a linearized unsigned char value.
+//               Inputs outside this range are clamped.
+////////////////////////////////////////////////////////////////////
+INLINE unsigned char decode_sRGB_uchar(float val) {
+  return (val <= 0.04045f)
+    ? (unsigned char)(max(0.f, val) * (255.f / 12.92f) + 0.5f)
+    : (unsigned char)(cpow((min(val, 1.f) + 0.055f) * (1.f / 1.055f), 2.4f) * 255.f + 0.5f);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: encode_sRGB_float
+//  Description: Encodes the linearized unsigned char value to an
+//               sRGB-encoded floating-point value in ther range 0-1.
+////////////////////////////////////////////////////////////////////
+INLINE float
+encode_sRGB_float(unsigned char val) {
+  // This seems like a very unlikely use case, so I didn't bother
+  // making a look-up table for this.
+  return (val == 0) ? 0
+    : (1.055f * cpow((float)val * (1.f / 255.f), 0.41666f) - 0.055);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: encode_sRGB_float
+//  Description: Encodes the linearized floating-point value in the
+//               range 0-1 to an sRGB-encoded float in the range
+//               0-1.  Inputs outside this range produce invalid
+//               results.
+////////////////////////////////////////////////////////////////////
+INLINE float
+encode_sRGB_float(float val) {
+  return (val < 0.0031308f)
+    ? (val * 12.92f)
+    : (1.055f * cpow(val, 0.41666f) - 0.055);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: encode_sRGB_uchar
+//  Description: Encodes the linearized unsigned char value to an
+//               sRGB-encoded unsigned char value.
+////////////////////////////////////////////////////////////////////
+CONSTEXPR unsigned char
+encode_sRGB_uchar(unsigned char val) {
+  return to_srgb8_table[val];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: encode_sRGB_uchar
+//  Description: Encodes the linearized floating-point value in the
+//               range 0-1 to an sRGB-encoded unsigned char value.
+//               Inputs outside this range are clamped.
+//
+//               When SSE2 support is known at compile time, this
+//               automatically uses an optimized version.  Otherwise,
+//               it does not attempt runtime CPU detection.  If you
+//               know that SSE2 is supported (ie. if the function
+//               has_sse2_sRGB_encode() returns true) you should
+//               call encode_sRGB_uchar_sse2 instead.
+////////////////////////////////////////////////////////////////////
+INLINE unsigned char
+encode_sRGB_uchar(float val) {
+#if defined(__SSE2__) || (_M_IX86_FP >= 2) || defined(_M_X64) || defined(_M_AMD64)
+  // Use a highly optimized approximation that has more than enough
+  // accuracy for an unsigned char.
+  return encode_sRGB_uchar_sse2(val);
+#else
+  return (val < 0.0031308f)
+    ? (unsigned char) (max(0.f, val) * 3294.6f + 0.5f)
+    : (unsigned char) (269.025f * cpow(min(val, 1.f), 0.41666f) - 13.525f);
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: encode_sRGB_uchar
+//  Description: Encodes the linearized floating-point color value
+//               an sRGB-encoded xel in the range 0-255.
+//
+//               When SSE2 support is known at compile time, this
+//               automatically uses an optimized version.  Otherwise,
+//               it does not attempt runtime CPU detection.  If you
+//               know that SSE2 is supported (ie. if the function
+//               has_sse2_sRGB_encode() returns true) you should
+//               call encode_sRGB_uchar_sse2 instead.
+////////////////////////////////////////////////////////////////////
+INLINE void
+encode_sRGB_uchar(const LColorf &color, xel &into) {
+#if defined(__SSE2__) || (_M_IX86_FP >= 2) || defined(_M_X64) || defined(_M_AMD64)
+  // SSE2 support compiled-in; we're guaranteed to have it.
+  encode_sRGB_uchar_sse2(color, into);
+#else
+  // Boring, slow, non-SSE2 version.
+  PPM_ASSIGN(into,
+    encode_sRGB_uchar(color[0]),
+    encode_sRGB_uchar(color[1]),
+    encode_sRGB_uchar(color[2]));
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: encode_sRGB_uchar
+//  Description: Encodes the linearized floating-point color value
+//               an sRGB-encoded xel and alpha in the range 0-255.
+//               The alpha value is not sRGB-encoded.
+//
+//               When SSE2 support is known at compile time, this
+//               automatically uses an optimized version.  Otherwise,
+//               it does not attempt runtime CPU detection.  If you
+//               know that SSE2 is supported (ie. if the function
+//               has_sse2_sRGB_encode() returns true) you should
+//               call encode_sRGB_uchar_sse2 instead.
+////////////////////////////////////////////////////////////////////
+INLINE void
+encode_sRGB_uchar(const LColorf &color, xel &into, xelval &into_alpha) {
+#if defined(__SSE2__) || (_M_IX86_FP >= 2) || defined(_M_X64) || defined(_M_AMD64)
+  // SSE2 support compiled-in; we're guaranteed to have it.
+  encode_sRGB_uchar_sse2(color, into, into_alpha);
+#else
+  // Boring, slow, non-SSE2 version.
+  PPM_ASSIGN(into,
+    encode_sRGB_uchar(color[0]),
+    encode_sRGB_uchar(color[1]),
+    encode_sRGB_uchar(color[2]));
+
+  into_alpha = (xelval) (color[3] * 255.f + 0.5f);
+#endif
+}

+ 165 - 0
panda/src/pnmimage/convert_srgb.cxx

@@ -0,0 +1,165 @@
+// Filename: convert_srgb.cxx
+// Created by:  rdb (13Nov14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "convert_srgb.h"
+
+#ifdef __GNUC__
+#include <cpuid.h>
+#endif
+
+#ifdef _WIN32
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif
+#include <windows.h>
+#endif
+
+// Lookup tables for converting from unsigned char formats.
+ALIGN_64BYTE const
+unsigned char to_srgb8_table[256] = { 0x00, 0x0d, 0x16, 0x1c, 0x22, 0x26, 0x2a,
+  0x2e, 0x32, 0x35, 0x38, 0x3b, 0x3d, 0x40, 0x42, 0x45, 0x47, 0x49, 0x4b, 0x4d,
+  0x4f, 0x51, 0x53, 0x55, 0x56, 0x58, 0x5a, 0x5c, 0x5d, 0x5f, 0x60, 0x62, 0x63,
+  0x65, 0x66, 0x68, 0x69, 0x6a, 0x6c, 0x6d, 0x6e, 0x70, 0x71, 0x72, 0x73, 0x75,
+  0x76, 0x77, 0x78, 0x79, 0x7a, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
+  0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90,
+  0x91, 0x92, 0x93, 0x94, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9b,
+  0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa3, 0xa4, 0xa5, 0xa6,
+  0xa7, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xac, 0xad, 0xad, 0xae, 0xaf, 0xaf,
+  0xb0, 0xb1, 0xb2, 0xb2, 0xb3, 0xb4, 0xb4, 0xb5, 0xb6, 0xb6, 0xb7, 0xb8, 0xb9,
+  0xb9, 0xba, 0xbb, 0xbb, 0xbc, 0xbd, 0xbd, 0xbe, 0xbe, 0xbf, 0xc0, 0xc0, 0xc1,
+  0xc2, 0xc2, 0xc3, 0xc4, 0xc4, 0xc5, 0xc5, 0xc6, 0xc7, 0xc7, 0xc8, 0xc8, 0xc9,
+  0xca, 0xca, 0xcb, 0xcb, 0xcc, 0xcd, 0xcd, 0xce, 0xce, 0xcf, 0xd0, 0xd0, 0xd1,
+  0xd1, 0xd2, 0xd2, 0xd3, 0xd4, 0xd4, 0xd5, 0xd5, 0xd6, 0xd6, 0xd7, 0xd7, 0xd8,
+  0xd8, 0xd9, 0xda, 0xda, 0xdb, 0xdb, 0xdc, 0xdc, 0xdd, 0xdd, 0xde, 0xde, 0xdf,
+  0xdf, 0xe0, 0xe0, 0xe1, 0xe2, 0xe2, 0xe3, 0xe3, 0xe4, 0xe4, 0xe5, 0xe5, 0xe6,
+  0xe6, 0xe7, 0xe7, 0xe8, 0xe8, 0xe9, 0xe9, 0xea, 0xea, 0xeb, 0xeb, 0xec, 0xec,
+  0xed, 0xed, 0xee, 0xee, 0xee, 0xef, 0xef, 0xf0, 0xf0, 0xf1, 0xf1, 0xf2, 0xf2,
+  0xf3, 0xf3, 0xf4, 0xf4, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf7, 0xf7, 0xf8, 0xf8,
+  0xf9, 0xf9, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfd, 0xfd, 0xfe, 0xfe,
+  0xff, 0xff};
+
+ALIGN_64BYTE const
+unsigned char to_linear_uchar_table[256] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02,
+  0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04,
+  0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x07,
+  0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0b,
+  0x0b, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0f, 0x0f, 0x10, 0x10,
+  0x11, 0x11, 0x11, 0x12, 0x12, 0x13, 0x13, 0x14, 0x14, 0x15, 0x16, 0x16, 0x17,
+  0x17, 0x18, 0x18, 0x19, 0x19, 0x1a, 0x1b, 0x1b, 0x1c, 0x1d, 0x1d, 0x1e, 0x1e,
+  0x1f, 0x20, 0x20, 0x21, 0x22, 0x23, 0x23, 0x24, 0x25, 0x25, 0x26, 0x27, 0x28,
+  0x29, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33,
+  0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+  0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4c, 0x4d,
+  0x4e, 0x4f, 0x50, 0x51, 0x52, 0x54, 0x55, 0x56, 0x57, 0x58, 0x5a, 0x5b, 0x5c,
+  0x5d, 0x5f, 0x60, 0x61, 0x63, 0x64, 0x65, 0x67, 0x68, 0x69, 0x6b, 0x6c, 0x6d,
+  0x6f, 0x70, 0x72, 0x73, 0x74, 0x76, 0x77, 0x79, 0x7a, 0x7c, 0x7d, 0x7f, 0x80,
+  0x82, 0x83, 0x85, 0x86, 0x88, 0x8a, 0x8b, 0x8d, 0x8e, 0x90, 0x92, 0x93, 0x95,
+  0x97, 0x98, 0x9a, 0x9c, 0x9d, 0x9f, 0xa1, 0xa3, 0xa4, 0xa6, 0xa8, 0xaa, 0xab,
+  0xad, 0xaf, 0xb1, 0xb3, 0xb5, 0xb7, 0xb8, 0xba, 0xbc, 0xbe, 0xc0, 0xc2, 0xc4,
+  0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
+  0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa,
+  0xfd, 0xff};
+
+ALIGN_64BYTE
+const float to_linear_float_table[256] = { 0, 0.000304f, 0.000607f, 0.000911f,
+  0.001214f, 0.001518f, 0.001821f, 0.002125f, 0.002428f, 0.002732f, 0.003035f,
+  0.003347f, 0.003677f, 0.004025f, 0.004391f, 0.004777f, 0.005182f, 0.005605f,
+  0.006049f, 0.006512f, 0.006995f, 0.007499f, 0.008023f, 0.008568f, 0.009134f,
+  0.009721f, 0.010330f, 0.010960f, 0.011612f, 0.012286f, 0.012983f, 0.013702f,
+  0.014444f, 0.015209f, 0.015996f, 0.016807f, 0.017642f, 0.018500f, 0.019382f,
+  0.020289f, 0.021219f, 0.022174f, 0.023153f, 0.024158f, 0.025187f, 0.026241f,
+  0.027321f, 0.028426f, 0.029557f, 0.030713f, 0.031896f, 0.033105f, 0.034340f,
+  0.035601f, 0.036889f, 0.038204f, 0.039546f, 0.040915f, 0.042311f, 0.043735f,
+  0.045186f, 0.046665f, 0.048172f, 0.049707f, 0.051269f, 0.052861f, 0.054480f,
+  0.056128f, 0.057805f, 0.059511f, 0.061246f, 0.063010f, 0.064803f, 0.066626f,
+  0.068478f, 0.070360f, 0.072272f, 0.074214f, 0.076185f, 0.078187f, 0.080220f,
+  0.082283f, 0.084376f, 0.086500f, 0.088656f, 0.090842f, 0.093059f, 0.095307f,
+  0.097587f, 0.099899f, 0.102242f, 0.104616f, 0.107023f, 0.109462f, 0.111932f,
+  0.114435f, 0.116971f, 0.119538f, 0.122139f, 0.124772f, 0.127438f, 0.130136f,
+  0.132868f, 0.135633f, 0.138432f, 0.141263f, 0.144128f, 0.147027f, 0.149960f,
+  0.152926f, 0.155926f, 0.158961f, 0.162029f, 0.165132f, 0.168269f, 0.171441f,
+  0.174647f, 0.177888f, 0.181164f, 0.184475f, 0.187821f, 0.191202f, 0.194618f,
+  0.198069f, 0.201556f, 0.205079f, 0.208637f, 0.212231f, 0.215861f, 0.219526f,
+  0.223228f, 0.226966f, 0.230740f, 0.234551f, 0.238398f, 0.242281f, 0.246201f,
+  0.250158f, 0.254152f, 0.258183f, 0.262251f, 0.266356f, 0.270498f, 0.274677f,
+  0.278894f, 0.283149f, 0.287441f, 0.291771f, 0.296138f, 0.300544f, 0.304987f,
+  0.309469f, 0.313989f, 0.318547f, 0.323143f, 0.327778f, 0.332452f, 0.337164f,
+  0.341914f, 0.346704f, 0.351533f, 0.356400f, 0.361307f, 0.366253f, 0.371238f,
+  0.376262f, 0.381326f, 0.386429f, 0.391572f, 0.396755f, 0.401978f, 0.407240f,
+  0.412543f, 0.417885f, 0.423268f, 0.428690f, 0.434154f, 0.439657f, 0.445201f,
+  0.450786f, 0.456411f, 0.462077f, 0.467784f, 0.473531f, 0.479320f, 0.485150f,
+  0.491021f, 0.496933f, 0.502886f, 0.508881f, 0.514918f, 0.520996f, 0.527115f,
+  0.533276f, 0.539479f, 0.545724f, 0.552011f, 0.558340f, 0.564712f, 0.571125f,
+  0.577580f, 0.584078f, 0.590619f, 0.597202f, 0.603827f, 0.610496f, 0.617207f,
+  0.623960f, 0.630757f, 0.637597f, 0.644480f, 0.651406f, 0.658375f, 0.665387f,
+  0.672443f, 0.679542f, 0.686685f, 0.693872f, 0.701102f, 0.708376f, 0.715694f,
+  0.723055f, 0.730461f, 0.737910f, 0.745404f, 0.752942f, 0.760525f, 0.768151f,
+  0.775822f, 0.783538f, 0.791298f, 0.799103f, 0.806952f, 0.814847f, 0.822786f,
+  0.830770f, 0.838799f, 0.846873f, 0.854993f, 0.863157f, 0.871367f, 0.879622f,
+  0.887923f, 0.896269f, 0.904661f, 0.913099f, 0.921582f, 0.930111f, 0.938686f,
+  0.947307f, 0.955973f, 0.964686f, 0.973445f, 0.982251f, 0.991102f, 1.000000f};
+
+
+#if defined(__SSE2__) || (_M_IX86_FP >= 2) || defined(_M_X64) || defined(_M_AMD64)
+// SSE2 support enabled at compile time.  No runtime detection mechanism needed.
+bool
+has_sse2_sRGB_encode() {
+  return true;
+}
+
+#else
+// SSE2 support not guaranteed.  Use a runtime detection mechanism.
+
+bool
+has_sse2_sRGB_encode() {
+#if defined(__GNUC__)
+  unsigned int a, b, c, d;
+  static const bool has_support =
+    (__get_cpuid(1, &a, &b, &c, &d) == 1 && (d & 0x04000000) != 0);
+
+#elif defined(_WIN32)
+  static const bool has_support =
+    (IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE) != FALSE);
+
+#else
+  static const bool has_support = false;
+#endif
+
+  if (pnmimage_cat.is_debug()) {
+    static bool checked = false;
+    if (!checked) {
+#if defined(__GNUC__) || defined(_WIN32)
+      if (has_support) {
+        pnmimage_cat.debug()
+          << "Runtime detection reports SSE2 instructions available: "
+          << "SSE2-optimized sRGB encoding routines enabled.\n";
+      } else {
+        pnmimage_cat.debug()
+          << "Runtime detection reports SSE2 instructions unavailable: "
+          << "SSE2-optimized sRGB encoding routines disabled.\n";
+      }
+#else
+      pnmimage_cat.debug()
+        << "No runtime detection mechanism for SSE2 instructions available: "
+        << "SSE2-optimized sRGB encoding routines disabled.\n";
+#endif
+      checked = true;
+    }
+  }
+
+  return has_support;
+}
+
+#endif  // __SSE2__

+ 59 - 0
panda/src/pnmimage/convert_srgb.h

@@ -0,0 +1,59 @@
+// Filename: convert_srgb.h
+// Created by:  rdb (13Nov14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CONVERT_SRGB_H
+#define CONVERT_SRGB_H
+
+#include "pandabase.h"
+#include "luse.h"
+#include "pnmimage_base.h"
+
+// The below functions can encode and decode sRGB colors in various
+// representations.  Some of them are implemented using look-up tables,
+// some others using SSE2 intrinsics.
+extern EXPCL_PANDA_PNMIMAGE const unsigned char to_srgb8_table[256];
+extern EXPCL_PANDA_PNMIMAGE const unsigned char to_linear_uchar_table[256];
+extern EXPCL_PANDA_PNMIMAGE const float to_linear_float_table[256];
+
+EXPCL_PANDA_PNMIMAGE CONSTEXPR float decode_sRGB_float(unsigned char val);
+EXPCL_PANDA_PNMIMAGE INLINE float decode_sRGB_float(float val);
+EXPCL_PANDA_PNMIMAGE CONSTEXPR unsigned char decode_sRGB_uchar(unsigned char val);
+EXPCL_PANDA_PNMIMAGE INLINE unsigned char decode_sRGB_uchar(float val);
+
+EXPCL_PANDA_PNMIMAGE INLINE float encode_sRGB_float(unsigned char val);
+EXPCL_PANDA_PNMIMAGE INLINE float encode_sRGB_float(float val);
+EXPCL_PANDA_PNMIMAGE CONSTEXPR unsigned char encode_sRGB_uchar(unsigned char val);
+EXPCL_PANDA_PNMIMAGE INLINE unsigned char encode_sRGB_uchar(float val);
+
+// These functions convert more than one component in one go,
+// which can be faster due to vectorization.
+EXPCL_PANDA_PNMIMAGE INLINE void encode_sRGB_uchar(const LColorf &from,
+                                                   xel &into);
+EXPCL_PANDA_PNMIMAGE INLINE void encode_sRGB_uchar(const LColorf &from,
+                                                   xel &into, xelval &into_alpha);
+
+// Use these functions if you know that SSE2 support is available.
+// Otherwise, they will crash!
+EXPCL_PANDA_PNMIMAGE unsigned char encode_sRGB_uchar_sse2(float val);
+EXPCL_PANDA_PNMIMAGE void encode_sRGB_uchar_sse2(const LColorf &from,
+                                                 xel &into);
+EXPCL_PANDA_PNMIMAGE void encode_sRGB_uchar_sse2(const LColorf &from,
+                                                 xel &into, xelval &into_alpha);
+
+// Use the following to find out if you can call either of the above.
+EXPCL_PANDA_PNMIMAGE bool has_sse2_sRGB_encode();
+
+#include "convert_srgb.I"
+
+#endif

+ 151 - 0
panda/src/pnmimage/convert_srgb_sse2.cxx

@@ -0,0 +1,151 @@
+// Filename: convert_srgb_sse2.cxx
+// Created by:  rdb (13Nov14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+// This file should always be compiled with SSE2 support.  These
+// functions will only be called when SSE2 support is detected at
+// run-time.
+
+#include "convert_srgb.h"
+#include "luse.h"
+
+#if defined(__SSE2__) || (_M_IX86_FP >= 2) || defined(_M_X64) || defined(_M_AMD64)
+
+#include <xmmintrin.h>
+#include <emmintrin.h>
+
+static INLINE __m128i _encode_sRGB_sse2_mul255(__m128 val) {
+  // This an SSE2-based approximation of the sRGB encode function.
+  // It has a maximum error of around 0.001, which is by far small
+  // enough for a uchar.  It is also at least 10x as fast as the
+  // original; up to 40x when taking advantage of vectorization.
+  // Note that the fourth float is only multiplied with 255.
+
+  // Part of the code in this function is derived from:
+  // http://stackoverflow.com/a/6486630/2135754
+
+  // Clamp to 0-1 range.
+  val = _mm_max_ps(val, _mm_set1_ps(0.0f));
+  val = _mm_min_ps(val, _mm_set1_ps(1.0f));
+
+  // Pre-multiply with constant factor to adjust for exp bias.
+  __m128 xf = _mm_mul_ps(val, _mm_set1_ps(6.3307e18f));
+
+  // Approximate logarithm by... casting!
+  xf = _mm_cvtepi32_ps(_mm_castps_si128(xf));
+
+  // Multiply 'logarithm' by power.
+  xf = _mm_mul_ps(xf, _mm_set1_ps(2.0f / 3.0f));
+
+  // Reverse operation of above: cast the other way.
+  xf = _mm_castsi128_ps(_mm_cvtps_epi32(xf));
+
+  // Make an overestimate and an underestimate.
+  __m128 xover = _mm_mul_ps(val, xf);
+  __m128 xunder = _mm_mul_ps(_mm_mul_ps(val, val),
+                             _mm_rsqrt_ps(xf));
+
+  // Average the two factors, with a slight bias.
+  __m128 xavg = _mm_mul_ps(_mm_add_ps(xover, xunder),
+                           _mm_set1_ps(0.5286098f));
+
+  // Take square root twice.  Note that this is faster than
+  // the more expensive _mm_sqrt_ps instruction.
+  xavg = _mm_mul_ps(xavg, _mm_rsqrt_ps(xavg));
+  xavg = _mm_mul_ps(xavg, _mm_rsqrt_ps(xavg));
+
+  // Bring it into the correct range.  These factors are determined
+  // not on the basis of accuracy, but are chosen such that the
+  // decoder lookup table produces an equivalent result for any value.
+  xavg = _mm_mul_ps(xavg, _mm_set1_ps(269.122f));
+  xavg = _mm_sub_ps(xavg, _mm_set1_ps(13.55f));
+
+  // Compute the linear section.  This is also the path that
+  // the alpha channel takes, so we set the alpha multiplier
+  // to 255 (since alpha is not sRGB-converted).
+  __m128 lval = _mm_mul_ps(val,
+    _mm_set_ps(255.0f, 3294.6f, 3294.6f, 3294.6f));
+
+  lval = _mm_add_ps(lval, _mm_set1_ps(0.5f));
+
+  // Decide which version to return.  Rig the alpha
+  // comparator to always fail so that the linear path
+  // is always chosen for alpha.
+  __m128 mask = _mm_cmpge_ps(val,
+    _mm_set_ps(2.0f, 0.0031308f, 0.0031308f, 0.0031308f));
+
+  // This is a non-branching way to return one or the other value.
+  return _mm_cvttps_epi32(_mm_or_ps(
+    _mm_and_ps(mask, xavg),
+    _mm_andnot_ps(mask, lval)));
+}
+
+unsigned char
+encode_sRGB_uchar_sse2(float val) {
+  // Running only a single component through this function is still
+  // way faster than the equivalent non-SSE2 version.
+  return (unsigned char)
+    _mm_extract_epi16(_encode_sRGB_sse2_mul255(_mm_set1_ps(val)), 0);
+}
+
+void
+encode_sRGB_uchar_sse2(const LColorf &color, xel &into) {
+#ifdef LINMATH_ALIGN
+  __m128 vec = _mm_load_ps(color.get_data());
+#else
+  __m128 vec = _mm_loadu_ps(color.get_data());
+#endif
+
+  __m128i vals = _encode_sRGB_sse2_mul255(vec);
+  into.r = _mm_extract_epi16(vals, 0);
+  into.g = _mm_extract_epi16(vals, 2);
+  into.b = _mm_extract_epi16(vals, 4);
+}
+
+void
+encode_sRGB_uchar_sse2(const LColorf &color, xel &into, xelval &into_alpha) {
+#ifdef LINMATH_ALIGN
+  __m128 vec = _mm_load_ps(color.get_data());
+#else
+  __m128 vec = _mm_loadu_ps(color.get_data());
+#endif
+
+  __m128i vals = _encode_sRGB_sse2_mul255(vec);
+  into.r = _mm_extract_epi16(vals, 0);
+  into.g = _mm_extract_epi16(vals, 2);
+  into.b = _mm_extract_epi16(vals, 4);
+  into_alpha = _mm_extract_epi16(vals, 6);
+}
+
+#else
+// Somehow we're still compiling this without SSE2 support.  We'll
+// still have to define these functions, but emit a warning that the
+// build system isn't configured properly.
+#warning convert_srgb_sse2.cxx is being compiled without SSE2 support!
+
+unsigned char
+encode_sRGB_uchar_sse2(float val) {
+  return encode_sRGB_uchar(val);
+}
+
+void
+encode_sRGB_uchar_sse2(const LColorf &color, xel &into) {
+  encode_sRGB_uchar(color, into);
+}
+
+void
+encode_sRGB_uchar_sse2(const LColorf &color, xel &into, xelval &into_alpha) {
+  encode_sRGB_uchar(color, into, into_alpha);
+}
+
+#endif

+ 1 - 0
panda/src/pnmimage/p3pnmimage_composite1.cxx

@@ -1,4 +1,5 @@
 #include "config_pnmimage.cxx"
 #include "config_pnmimage.cxx"
+#include "convert_srgb.cxx"
 #include "pfmFile.cxx"
 #include "pfmFile.cxx"
 #include "pnm-image-filter.cxx"
 #include "pnm-image-filter.cxx"
 #include "pnmbitio.cxx"
 #include "pnmbitio.cxx"

+ 1 - 1
panda/src/rocket/rocketRenderInterface.h

@@ -63,7 +63,7 @@ private:
 
 
   // Hold the scissor settings and whether or not to enable scissoring.
   // Hold the scissor settings and whether or not to enable scissoring.
   bool _enable_scissor;
   bool _enable_scissor;
-  LVecBase4f _scissor;
+  LVecBase4 _scissor;
 
 
   // These are temporarily filled in by render().
   // These are temporarily filled in by render().
   CullTraverser *_trav;
   CullTraverser *_trav;

+ 1 - 1
panda/src/tinydisplay/zbuffer.h

@@ -75,7 +75,7 @@ typedef unsigned int ZPOINT;
   ((((unsigned int)(a) << 24) & 0xff000000) | (((unsigned int)(r) << 16) & 0xff0000) | (((unsigned int)(g) << 8) & 0xff00) | (unsigned int)(b))
   ((((unsigned int)(a) << 24) & 0xff000000) | (((unsigned int)(r) << 16) & 0xff0000) | (((unsigned int)(g) << 8) & 0xff00) | (unsigned int)(b))
 
 
 #define SRGB_TO_PIXEL(r,g,b) \
 #define SRGB_TO_PIXEL(r,g,b) \
-  ((encode_sRGB[(unsigned int)(r) >> 4] << 16) | (encode_sRGB10[(unsigned int)(g) >> 4] << 8) | (encode_sRGB[(unsigned int)(b) >> 4]))
+  ((encode_sRGB[(unsigned int)(r) >> 4] << 16) | (encode_sRGB[(unsigned int)(g) >> 4] << 8) | (encode_sRGB[(unsigned int)(b) >> 4]))
 #define SRGBA_TO_PIXEL(r,g,b,a) \
 #define SRGBA_TO_PIXEL(r,g,b,a) \
   ((((unsigned int)(a) << 16) & 0xff000000) | (encode_sRGB[(unsigned int)(r) >> 4] << 16) | (encode_sRGB[(unsigned int)(g) >> 4] << 8) | (encode_sRGB[(unsigned int)(b) >> 4]))
   ((((unsigned int)(a) << 16) & 0xff000000) | (encode_sRGB[(unsigned int)(r) >> 4] << 16) | (encode_sRGB[(unsigned int)(g) >> 4] << 8) | (encode_sRGB[(unsigned int)(b) >> 4]))
 
 

+ 16 - 30
panda/src/wgldisplay/wglGraphicsPipe.cxx

@@ -153,46 +153,32 @@ make_output(const string &name,
     return new wglGraphicsWindow(engine, this, name, fb_prop, win_prop,
     return new wglGraphicsWindow(engine, this, name, fb_prop, win_prop,
                                  flags, gsg, host);
                                  flags, gsg, host);
   }
   }
-  
+
   // Second thing to try: a GLGraphicsBuffer
   // Second thing to try: a GLGraphicsBuffer
-  
+
   if (retry == 1) {
   if (retry == 1) {
-    if ((!gl_support_fbo)||
-        (host==0)||
-        ((flags&BF_require_parasite)!=0)||
-        ((flags&BF_require_window)!=0)) {
+    if (!gl_support_fbo || host == NULL ||
+        (flags & (BF_require_parasite | BF_require_window)) != 0) {
       return NULL;
       return NULL;
     }
     }
     // Early failure - if we are sure that this buffer WONT
     // Early failure - if we are sure that this buffer WONT
     // meet specs, we can bail out early.
     // meet specs, we can bail out early.
-    int _fbo_multisample = 0;
-    if (!ConfigVariableBool("framebuffer-object-multisample", false, PRC_DESC("Enabled Multisample."))) {
-        _fbo_multisample = 16;
-    }
-    if ((flags & BF_fb_props_optional)==0) {
+    if ((flags & BF_fb_props_optional) == 0) {
       if (fb_prop.get_indexed_color() ||
       if (fb_prop.get_indexed_color() ||
-          (fb_prop.get_back_buffers() > 0)||
-          (fb_prop.get_accum_bits() > 0)||
-          (fb_prop.get_multisamples() > _fbo_multisample)) {
+          fb_prop.get_back_buffers() > 0 ||
+          fb_prop.get_accum_bits() > 0) {
         return NULL;
         return NULL;
       }
       }
     }
     }
-    if ((wglgsg != 0) &&
-        (wglgsg->is_valid()) &&
-        (!wglgsg->needs_reset()) &&
-	!wglgsg->_supports_framebuffer_object) {
-      return NULL;
-    }
-
-    // Early success - if we are sure that this buffer WILL
-    // meet specs, we can precertify it.
-    if ((wglgsg != 0) &&
-        (wglgsg->is_valid()) &&
-        (!wglgsg->needs_reset()) &&
-        (wglgsg->_supports_framebuffer_object) &&
-        (wglgsg->_glDrawBuffers != 0)&&
-        (fb_prop.is_basic())) {
-      precertify = true;
+    if (wglgsg != NULL && wglgsg->is_valid() && !wglgsg->needs_reset()) {
+      if (!wglgsg->_supports_framebuffer_object ||
+          wglgsg->_glDrawBuffers == NULL) {
+        return NULL;
+      } else {
+        // Early success - if we are sure that this buffer WILL
+        // meet specs, we can precertify it.
+        precertify = true;
+      }
     }
     }
     return new GLGraphicsBuffer(engine, this, name, fb_prop, win_prop,
     return new GLGraphicsBuffer(engine, this, name, fb_prop, win_prop,
                                 flags, gsg, host);
                                 flags, gsg, host);

+ 1 - 1
pandatool/src/daeegg/daeCharacter.cxx

@@ -320,7 +320,7 @@ build_table(EggTable *parent, FCDSceneNode* node, const pset<float> &keys) {
   }
   }
 
 
   // Quantize the FPS, otherwise Panda complains about FPS mismatches.
   // Quantize the FPS, otherwise Panda complains about FPS mismatches.
-  float fps = round(((keys.size() - 1) / timing_total) * 100) * 0.01f;
+  float fps = cfloor(((keys.size() - 1) / timing_total) * 100 + 0.5f) * 0.01f;
   xform->set_fps(fps);
   xform->set_fps(fps);
 
 
   // Loop through the children joints
   // Loop through the children joints

+ 1 - 1
pandatool/src/daeegg/daeCharacter.h

@@ -45,7 +45,7 @@ public:
       _bind_pose(LMatrix4d::ident_mat()) {}
       _bind_pose(LMatrix4d::ident_mat()) {}
 
 
     LMatrix4d _bind_pose;
     LMatrix4d _bind_pose;
-    const PT(EggGroup) _group;
+    PT(EggGroup) _group;
     const FCDSceneNode *_scene_node;
     const FCDSceneNode *_scene_node;
     DaeCharacter *_character;
     DaeCharacter *_character;
   };
   };

+ 1 - 1
pandatool/src/daeegg/daeToEggConverter.cxx

@@ -228,7 +228,7 @@ convert_file(const Filename &filename) {
       Characters::iterator it;
       Characters::iterator it;
       DaeCharacter *character;
       DaeCharacter *character;
       for (it = _characters.begin(); it != _characters.end(); ++it) {
       for (it = _characters.begin(); it != _characters.end(); ++it) {
-        DaeCharacter *character = *it;
+        character = *it;
 
 
         // Collect key frame timings.
         // Collect key frame timings.
         if (get_animation_convert() == AC_both ||
         if (get_animation_convert() == AC_both ||

+ 7 - 0
pandatool/src/daeegg/pre_fcollada_include.h

@@ -22,6 +22,13 @@
   #error You must include pre_fcollada_include.h before including FCollada.h!
   #error You must include pre_fcollada_include.h before including FCollada.h!
 #endif
 #endif
 
 
+#ifdef _WIN32
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif
+#include <winsock2.h>
+#endif
+
 // FCollada expects LINUX to be defined on linux
 // FCollada expects LINUX to be defined on linux
 #ifdef IS_LINUX
 #ifdef IS_LINUX
   #ifndef LINUX
   #ifndef LINUX

+ 399 - 0
samples/asteroids/main.py

@@ -0,0 +1,399 @@
+#!/usr/bin/env python
+
+# Author: Shao Zhang, Phil Saltzman, and Greg Lindley
+# Last Updated: 2015-03-13
+#
+# This tutorial demonstrates the use of tasks. A task is a function that
+# gets called once every frame. They are good for things that need to be
+# updated very often. In the case of asteroids, we use tasks to update
+# the positions of all the objects, and to check if the bullets or the
+# ship have hit the asteroids.
+#
+# Note: This definitely a complicated example. Tasks are the cores of
+# most games so it seemed appropriate to show what a full game in Panda
+# could look like.
+
+from direct.showbase.ShowBase import ShowBase
+from panda3d.core import TextNode, TransparencyAttrib
+from panda3d.core import LPoint3, LVector3
+from direct.gui.OnscreenText import OnscreenText
+from direct.task.Task import Task
+from math import sin, cos, pi
+from random import randint, choice, random
+from direct.interval.MetaInterval import Sequence
+from direct.interval.FunctionInterval import Wait, Func
+import sys
+
+# Constants that will control the behavior of the game. It is good to
+# group constants like this so that they can be changed once without
+# having to find everywhere they are used in code
+SPRITE_POS = 55     # At default field of view and a depth of 55, the screen
+# dimensions is 40x30 units
+SCREEN_X = 20       # Screen goes from -20 to 20 on X
+SCREEN_Y = 15       # Screen goes from -15 to 15 on Y
+TURN_RATE = 360     # Degrees ship can turn in 1 second
+ACCELERATION = 10   # Ship acceleration in units/sec/sec
+MAX_VEL = 6         # Maximum ship velocity in units/sec
+MAX_VEL_SQ = MAX_VEL ** 2  # Square of the ship velocity
+DEG_TO_RAD = pi / 180  # translates degrees to radians for sin and cos
+BULLET_LIFE = 2     # How long bullets stay on screen before removed
+BULLET_REPEAT = .2  # How often bullets can be fired
+BULLET_SPEED = 10   # Speed bullets move
+AST_INIT_VEL = 1    # Velocity of the largest asteroids
+AST_INIT_SCALE = 3  # Initial asteroid scale
+AST_VEL_SCALE = 2.2  # How much asteroid speed multiplies when broken up
+AST_SIZE_SCALE = .6  # How much asteroid scale changes when broken up
+AST_MIN_SCALE = 1.1  # If and asteroid is smaller than this and is hit,
+# it disapears instead of splitting up
+
+
+# This helps reduce the amount of code used by loading objects, since all of
+# the objects are pretty much the same.
+def loadObject(tex=None, pos=LPoint3(0, 0), depth=SPRITE_POS, scale=1,
+               transparency=True):
+    # Every object uses the plane model and is parented to the camera
+    # so that it faces the screen.
+    obj = loader.loadModel("models/plane")
+    obj.reparentTo(camera)
+
+    # Set the initial position and scale.
+    obj.setPos(pos.getX(), depth, pos.getY())
+    obj.setScale(scale)
+
+    # This tells Panda not to worry about the order that things are drawn in
+    # (ie. disable Z-testing).  This prevents an effect known as Z-fighting.
+    obj.setBin("unsorted", 0)
+    obj.setDepthTest(False)
+
+    if transparency:
+        # Enable transparency blending.
+        obj.setTransparency(TransparencyAttrib.MAlpha)
+
+    if tex:
+        # Load and set the requested texture.
+        tex = loader.loadTexture("textures/" + tex)
+        obj.setTexture(tex, 1)
+
+    return obj
+
+
+# Macro-like function used to reduce the amount to code needed to create the
+# on screen instructions
+def genLabelText(text, i):
+    return OnscreenText(text=text, parent=base.a2dTopLeft, pos=(0.07, -.06 * i - 0.1),
+                        fg=(1, 1, 1, 1), align=TextNode.ALeft, shadow=(0, 0, 0, 0.5), scale=.05)
+
+
+class AsteroidsDemo(ShowBase):
+
+    def __init__(self):
+        # Initialize the ShowBase class from which we inherit, which will
+        # create a window and set up everything we need for rendering into it.
+        ShowBase.__init__(self)
+
+        # This code puts the standard title and instruction text on screen
+        self.title = OnscreenText(text="Panda3D: Tutorial - Tasks",
+                                  parent=base.a2dBottomRight, scale=.07,
+                                  align=TextNode.ARight, pos=(-0.1, 0.1),
+                                  fg=(1, 1, 1, 1), shadow=(0, 0, 0, 0.5))
+        self.escapeText = genLabelText("ESC: Quit", 0)
+        self.leftkeyText = genLabelText("[Left Arrow]: Turn Left (CCW)", 1)
+        self.rightkeyText = genLabelText("[Right Arrow]: Turn Right (CW)", 2)
+        self.upkeyText = genLabelText("[Up Arrow]: Accelerate", 3)
+        self.spacekeyText = genLabelText("[Space Bar]: Fire", 4)
+
+        # Disable default mouse-based camera control.  This is a method on the
+        # ShowBase class from which we inherit.
+        self.disableMouse()
+
+        # Load the background starfield.
+        self.setBackgroundColor((0, 0, 0, 1))
+        self.bg = loadObject("stars.jpg", scale=146, depth=200,
+                             transparency=False)
+
+        # Load the ship and set its initial velocity.
+        self.ship = loadObject("ship.png")
+        self.setVelocity(self.ship, LVector3.zero())
+
+        # A dictionary of what keys are currently being pressed
+        # The key events update this list, and our task will query it as input
+        self.keys = {"turnLeft": 0, "turnRight": 0,
+                     "accel": 0, "fire": 0}
+
+        self.accept("escape", sys.exit)  # Escape quits
+        # Other keys events set the appropriate value in our key dictionary
+        self.accept("arrow_left",     self.setKey, ["turnLeft", 1])
+        self.accept("arrow_left-up",  self.setKey, ["turnLeft", 0])
+        self.accept("arrow_right",    self.setKey, ["turnRight", 1])
+        self.accept("arrow_right-up", self.setKey, ["turnRight", 0])
+        self.accept("arrow_up",       self.setKey, ["accel", 1])
+        self.accept("arrow_up-up",    self.setKey, ["accel", 0])
+        self.accept("space",          self.setKey, ["fire", 1])
+
+        # Now we create the task. taskMgr is the task manager that actually
+        # calls the function each frame. The add method creates a new task.
+        # The first argument is the function to be called, and the second
+        # argument is the name for the task.  It returns a task object which
+        # is passed to the function each frame.
+        self.gameTask = taskMgr.add(self.gameLoop, "gameLoop")
+
+        # Stores the time at which the next bullet may be fired.
+        self.nextBullet = 0.0
+
+        # This list will stored fired bullets.
+        self.bullets = []
+
+        # Complete initialization by spawning the asteroids.
+        self.spawnAsteroids()
+
+    # As described earlier, this simply sets a key in the self.keys dictionary
+    # to the given value.
+    def setKey(self, key, val):
+        self.keys[key] = val
+
+    def setVelocity(self, obj, val):
+        obj.setPythonTag("velocity", val)
+
+    def getVelocity(self, obj):
+        return obj.getPythonTag("velocity")
+
+    def setExpires(self, obj, val):
+        obj.setPythonTag("expires", val)
+
+    def getExpires(self, obj):
+        return obj.getPythonTag("expires")
+
+    def spawnAsteroids(self):
+        # Control variable for if the ship is alive
+        self.alive = True
+        self.asteroids = []  # List that will contain our asteroids
+
+        for i in range(10):
+            # This loads an asteroid. The texture chosen is random
+            # from "asteroid1.png" to "asteroid3.png".
+            asteroid = loadObject("asteroid%d.png" % (randint(1, 3)),
+                                  scale=AST_INIT_SCALE)
+            self.asteroids.append(asteroid)
+
+            # This is kind of a hack, but it keeps the asteroids from spawning
+            # near the player.  It creates the list (-20, -19 ... -5, 5, 6, 7,
+            # ... 20) and chooses a value from it. Since the player starts at 0
+            # and this list doesn't contain anything from -4 to 4, it won't be
+            # close to the player.
+            asteroid.setX(choice(range(-SCREEN_X, -5) + range(5, SCREEN_X)))
+            # Same thing for Y, but from -15 to 15
+            asteroid.setZ(choice(range(-SCREEN_Y, -5) + range(5, SCREEN_Y)))
+
+            # Heading is a random angle in radians
+            heading = random() * 2 * pi
+
+            # Converts the heading to a vector and multiplies it by speed to
+            # get a velocity vector
+            v = LVector3(sin(heading), 0, cos(heading)) * AST_INIT_VEL
+            self.setVelocity(self.asteroids[i], v)
+
+    # This is our main task function, which does all of the per-frame
+    # processing.  It takes in self like all functions in a class, and task,
+    # the task object returned by taskMgr.
+    def gameLoop(self, task):
+        # Get the time elapsed since the next frame.  We need this for our
+        # distance and velocity calculations.
+        dt = globalClock.getDt()
+
+        # If the ship is not alive, do nothing.  Tasks return Task.cont to
+        # signify that the task should continue running. If Task.done were
+        # returned instead, the task would be removed and would no longer be
+        # called every frame.
+        if not self.alive:
+            return Task.cont
+
+        # update ship position
+        self.updateShip(dt)
+
+        # check to see if the ship can fire
+        if self.keys["fire"] and task.time > self.nextBullet:
+            self.fire(task.time)  # If so, call the fire function
+            # And disable firing for a bit
+            self.nextBullet = task.time + BULLET_REPEAT
+        # Remove the fire flag until the next spacebar press
+        self.keys["fire"] = 0
+
+        # update asteroids
+        for obj in self.asteroids:
+            self.updatePos(obj, dt)
+
+        # update bullets
+        newBulletArray = []
+        for obj in self.bullets:
+            self.updatePos(obj, dt)  # Update the bullet
+            # Bullets have an experation time (see definition of fire)
+            # If a bullet has not expired, add it to the new bullet list so
+            # that it will continue to exist.
+            if self.getExpires(obj) > task.time:
+                newBulletArray.append(obj)
+            else:
+                obj.removeNode()  # Otherwise, remove it from the scene.
+        # Set the bullet array to be the newly updated array
+        self.bullets = newBulletArray
+
+        # Check bullet collision with asteroids
+        # In short, it checks every bullet against every asteroid. This is
+        # quite slow.  A big optimization would be to sort the objects left to
+        # right and check only if they overlap.  Framerate can go way down if
+        # there are many bullets on screen, but for the most part it's okay.
+        for bullet in self.bullets:
+            # This range statement makes it step though the asteroid list
+            # backwards.  This is because if an asteroid is removed, the
+            # elements after it will change position in the list.  If you go
+            # backwards, the length stays constant.
+            for i in range(len(self.asteroids) - 1, -1, -1):
+                asteroid = self.asteroids[i]
+                # Panda's collision detection is more complicated than we need
+                # here.  This is the basic sphere collision check. If the
+                # distance between the object centers is less than sum of the
+                # radii of the two objects, then we have a collision. We use
+                # lengthSquared() since it is faster than length().
+                if ((bullet.getPos() - asteroid.getPos()).lengthSquared() <
+                    (((bullet.getScale().getX() + asteroid.getScale().getX())
+                      * .5) ** 2)):
+                    # Schedule the bullet for removal
+                    self.setExpires(bullet, 0)
+                    self.asteroidHit(i)      # Handle the hit
+
+        # Now we do the same collision pass for the ship
+        shipSize = self.ship.getScale().getX()
+        for ast in self.asteroids:
+            # Same sphere collision check for the ship vs. the asteroid
+            if ((self.ship.getPos() - ast.getPos()).lengthSquared() <
+                    (((shipSize + ast.getScale().getX()) * .5) ** 2)):
+                # If there is a hit, clear the screen and schedule a restart
+                self.alive = False         # Ship is no longer alive
+                # Remove every object in asteroids and bullets from the scene
+                for i in self.asteroids + self.bullets:
+                    i.removeNode()
+                self.bullets = []          # Clear the bullet list
+                self.ship.hide()           # Hide the ship
+                # Reset the velocity
+                self.setVelocity(self.ship, LVector3(0, 0, 0))
+                Sequence(Wait(2),          # Wait 2 seconds
+                         Func(self.ship.setR, 0),  # Reset heading
+                         Func(self.ship.setX, 0),  # Reset position X
+                         # Reset position Y (Z for Panda)
+                         Func(self.ship.setZ, 0),
+                         Func(self.ship.show),     # Show the ship
+                         Func(self.spawnAsteroids)).start()  # Remake asteroids
+                return Task.cont
+
+        # If the player has successfully destroyed all asteroids, respawn them
+        if len(self.asteroids) == 0:
+            self.spawnAsteroids()
+
+        return Task.cont    # Since every return is Task.cont, the task will
+        # continue indefinitely
+
+    # Updates the positions of objects
+    def updatePos(self, obj, dt):
+        vel = self.getVelocity(obj)
+        newPos = obj.getPos() + (vel * dt)
+
+        # Check if the object is out of bounds. If so, wrap it
+        radius = .5 * obj.getScale().getX()
+        if newPos.getX() - radius > SCREEN_X:
+            newPos.setX(-SCREEN_X)
+        elif newPos.getX() + radius < -SCREEN_X:
+            newPos.setX(SCREEN_X)
+        if newPos.getZ() - radius > SCREEN_Y:
+            newPos.setZ(-SCREEN_Y)
+        elif newPos.getZ() + radius < -SCREEN_Y:
+            newPos.setZ(SCREEN_Y)
+
+        obj.setPos(newPos)
+
+    # The handler when an asteroid is hit by a bullet
+    def asteroidHit(self, index):
+        # If the asteroid is small it is simply removed
+        if self.asteroids[index].getScale().getX() <= AST_MIN_SCALE:
+            self.asteroids[index].removeNode()
+            # Remove the asteroid from the list of asteroids.
+            del self.asteroids[index]
+        else:
+            # If it is big enough, divide it up into little asteroids.
+            # First we update the current asteroid.
+            asteroid = self.asteroids[index]
+            newScale = asteroid.getScale().getX() * AST_SIZE_SCALE
+            asteroid.setScale(newScale)  # Rescale it
+
+            # The new direction is chosen as perpendicular to the old direction
+            # This is determined using the cross product, which returns a
+            # vector perpendicular to the two input vectors.  By crossing
+            # velocity with a vector that goes into the screen, we get a vector
+            # that is orthagonal to the original velocity in the screen plane.
+            vel = self.getVelocity(asteroid)
+            speed = vel.length() * AST_VEL_SCALE
+            vel.normalize()
+            vel = LVector3(0, 1, 0).cross(vel)
+            vel *= speed
+            self.setVelocity(asteroid, vel)
+
+            # Now we create a new asteroid identical to the current one
+            newAst = loadObject(scale=newScale)
+            self.setVelocity(newAst, vel * -1)
+            newAst.setPos(asteroid.getPos())
+            newAst.setTexture(asteroid.getTexture(), 1)
+            self.asteroids.append(newAst)
+
+    # This updates the ship's position. This is similar to the general update
+    # but takes into account turn and thrust
+    def updateShip(self, dt):
+        heading = self.ship.getR()  # Heading is the roll value for this model
+        # Change heading if left or right is being pressed
+        if self.keys["turnRight"]:
+            heading += dt * TURN_RATE
+            self.ship.setR(heading % 360)
+        elif self.keys["turnLeft"]:
+            heading -= dt * TURN_RATE
+            self.ship.setR(heading % 360)
+
+        # Thrust causes acceleration in the direction the ship is currently
+        # facing
+        if self.keys["accel"]:
+            heading_rad = DEG_TO_RAD * heading
+            # This builds a new velocity vector and adds it to the current one
+            # relative to the camera, the screen in Panda is the XZ plane.
+            # Therefore all of our Y values in our velocities are 0 to signify
+            # no change in that direction.
+            newVel = \
+                LVector3(sin(heading_rad), 0, cos(heading_rad)) * ACCELERATION * dt
+            newVel += self.getVelocity(self.ship)
+            # Clamps the new velocity to the maximum speed. lengthSquared() is
+            # used again since it is faster than length()
+            if newVel.lengthSquared() > MAX_VEL_SQ:
+                newVel.normalize()
+                newVel *= MAX_VEL
+            self.setVelocity(self.ship, newVel)
+
+        # Finally, update the position as with any other object
+        self.updatePos(self.ship, dt)
+
+    # Creates a bullet and adds it to the bullet list
+    def fire(self, time):
+        direction = DEG_TO_RAD * self.ship.getR()
+        pos = self.ship.getPos()
+        bullet = loadObject("bullet.png", scale=.2)  # Create the object
+        bullet.setPos(pos)
+        # Velocity is in relation to the ship
+        vel = (self.getVelocity(self.ship) +
+               (LVector3(sin(direction), 0, cos(direction)) *
+                BULLET_SPEED))
+        self.setVelocity(bullet, vel)
+        # Set the bullet expiration time to be a certain amount past the
+        # current time
+        self.setExpires(bullet, time + BULLET_LIFE)
+
+        # Finally, add the new bullet to the list
+        self.bullets.append(bullet)
+
+# We now have everything we need. Make an instance of the class and start
+# 3D rendering
+demo = AsteroidsDemo()
+demo.run()

+ 39 - 0
samples/asteroids/models/plane.egg

@@ -0,0 +1,39 @@
+<CoordinateSystem> { Y-Up }
+
+<Comment> {
+  "maya2egg plane.mb plane.egg"
+}
+<Group> groundPlane_transform {
+}
+<Group> pPlane1 {
+  <VertexPool> pPlaneShape1.verts {
+    <Vertex> 1 {
+      -0.5 -0.5 0
+      <Normal> { 0 0 -1 }
+      <UV> { 0 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 2 {
+      -0.5 0.5 0
+      <Normal> { 0 0 -1 }
+      <UV> { 0 1 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 3 {
+      0.5 -0.5 0
+      <Normal> { 0 0 -1 }
+      <UV> { 1 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 4 {
+      0.5 0.5 0
+      <Normal> { 0 0 -1 }
+      <UV> { 1 1 }
+      <RGBA> { 1 1 1 1 }
+    }
+  }
+  <Polygon> {
+    <Normal> { 0 0 -1 }
+    <VertexRef>{ 3 4 2 1 <Ref> { pPlaneShape1.verts } }
+  }
+}

BIN
samples/asteroids/textures/asteroid1.png


BIN
samples/asteroids/textures/asteroid2.png


BIN
samples/asteroids/textures/asteroid3.png


BIN
samples/asteroids/textures/bullet.png


BIN
samples/asteroids/textures/ship.png


BIN
samples/asteroids/textures/stars.jpg


+ 338 - 0
samples/ball-in-maze/main.py

@@ -0,0 +1,338 @@
+#!/usr/bin/env python
+
+# Author: Shao Zhang, Phil Saltzman
+# Last Updated: 2015-03-13
+#
+# This tutorial shows how to detect and respond to collisions. It uses solids
+# create in code and the egg files, how to set up collision masks, a traverser,
+# and a handler, how to detect collisions, and how to dispatch function based
+# on the collisions. All of this is put together to simulate a labyrinth-style
+# game
+
+from direct.showbase.ShowBase import ShowBase
+from panda3d.core import CollisionTraverser, CollisionNode
+from panda3d.core import CollisionHandlerQueue, CollisionRay
+from panda3d.core import Material, LRotationf, NodePath
+from panda3d.core import AmbientLight, DirectionalLight
+from panda3d.core import TextNode
+from panda3d.core import LVector3, BitMask32
+from direct.gui.OnscreenText import OnscreenText
+from direct.interval.MetaInterval import Sequence, Parallel
+from direct.interval.LerpInterval import LerpFunc
+from direct.interval.FunctionInterval import Func, Wait
+from direct.task.Task import Task
+import sys
+
+# Some constants for the program
+ACCEL = 70         # Acceleration in ft/sec/sec
+MAX_SPEED = 5      # Max speed in ft/sec
+MAX_SPEED_SQ = MAX_SPEED ** 2  # Squared to make it easier to use lengthSquared
+# Instead of length
+
+
+class BallInMazeDemo(ShowBase):
+
+    def __init__(self):
+        # Initialize the ShowBase class from which we inherit, which will
+        # create a window and set up everything we need for rendering into it.
+        ShowBase.__init__(self)
+
+        # This code puts the standard title and instruction text on screen
+        self.title = \
+            OnscreenText(text="Panda3D: Tutorial - Collision Detection",
+                         parent=base.a2dBottomRight, align=TextNode.ARight,
+                         fg=(1, 1, 1, 1), pos=(-0.1, 0.1), scale=.08,
+                         shadow=(0, 0, 0, 0.5))
+        self.instructions = \
+            OnscreenText(text="Mouse pointer tilts the board",
+                         parent=base.a2dTopLeft, align=TextNode.ALeft,
+                         pos=(0.05, -0.08), fg=(1, 1, 1, 1), scale=.06,
+                         shadow=(0, 0, 0, 0.5))
+
+        self.accept("escape", sys.exit)  # Escape quits
+
+        # Disable default mouse-based camera control.  This is a method on the
+        # ShowBase class from which we inherit.
+        self.disableMouse()
+        camera.setPosHpr(0, 0, 25, 0, -90, 0)  # Place the camera
+
+        # Load the maze and place it in the scene
+        self.maze = loader.loadModel("models/maze")
+        self.maze.reparentTo(render)
+
+        # Most times, you want collisions to be tested against invisible geometry
+        # rather than every polygon. This is because testing against every polygon
+        # in the scene is usually too slow. You can have simplified or approximate
+        # geometry for the solids and still get good results.
+        #
+        # Sometimes you'll want to create and position your own collision solids in
+        # code, but it's often easier to have them built automatically. This can be
+        # done by adding special tags into an egg file. Check maze.egg and ball.egg
+        # and look for lines starting with <Collide>. The part is brackets tells
+        # Panda exactly what to do. Polyset means to use the polygons in that group
+        # as solids, while Sphere tells panda to make a collision sphere around them
+        # Keep means to keep the polygons in the group as visable geometry (good
+        # for the ball, not for the triggers), and descend means to make sure that
+        # the settings are applied to any subgroups.
+        #
+        # Once we have the collision tags in the models, we can get to them using
+        # NodePath's find command
+
+        # Find the collision node named wall_collide
+        self.walls = self.maze.find("**/wall_collide")
+
+        # Collision objects are sorted using BitMasks. BitMasks are ordinary numbers
+        # with extra methods for working with them as binary bits. Every collision
+        # solid has both a from mask and an into mask. Before Panda tests two
+        # objects, it checks to make sure that the from and into collision masks
+        # have at least one bit in common. That way things that shouldn't interact
+        # won't. Normal model nodes have collision masks as well. By default they
+        # are set to bit 20. If you want to collide against actual visable polygons,
+        # set a from collide mask to include bit 20
+        #
+        # For this example, we will make everything we want the ball to collide with
+        # include bit 0
+        self.walls.node().setIntoCollideMask(BitMask32.bit(0))
+        # CollisionNodes are usually invisible but can be shown. Uncomment the next
+        # line to see the collision walls
+        #self.walls.show()
+
+        # We will now find the triggers for the holes and set their masks to 0 as
+        # well. We also set their names to make them easier to identify during
+        # collisions
+        self.loseTriggers = []
+        for i in range(6):
+            trigger = self.maze.find("**/hole_collide" + str(i))
+            trigger.node().setIntoCollideMask(BitMask32.bit(0))
+            trigger.node().setName("loseTrigger")
+            self.loseTriggers.append(trigger)
+            # Uncomment this line to see the triggers
+            # trigger.show()
+
+        # Ground_collide is a single polygon on the same plane as the ground in the
+        # maze. We will use a ray to collide with it so that we will know exactly
+        # what height to put the ball at every frame. Since this is not something
+        # that we want the ball itself to collide with, it has a different
+        # bitmask.
+        self.mazeGround = self.maze.find("**/ground_collide")
+        self.mazeGround.node().setIntoCollideMask(BitMask32.bit(1))
+
+        # Load the ball and attach it to the scene
+        # It is on a root dummy node so that we can rotate the ball itself without
+        # rotating the ray that will be attached to it
+        self.ballRoot = render.attachNewNode("ballRoot")
+        self.ball = loader.loadModel("models/ball")
+        self.ball.reparentTo(self.ballRoot)
+
+        # Find the collison sphere for the ball which was created in the egg file
+        # Notice that it has a from collision mask of bit 0, and an into collison
+        # mask of no bits. This means that the ball can only cause collisions, not
+        # be collided into
+        self.ballSphere = self.ball.find("**/ball")
+        self.ballSphere.node().setFromCollideMask(BitMask32.bit(0))
+        self.ballSphere.node().setIntoCollideMask(BitMask32.allOff())
+
+        # No we create a ray to start above the ball and cast down. This is to
+        # Determine the height the ball should be at and the angle the floor is
+        # tilting. We could have used the sphere around the ball itself, but it
+        # would not be as reliable
+        self.ballGroundRay = CollisionRay()     # Create the ray
+        self.ballGroundRay.setOrigin(0, 0, 10)    # Set its origin
+        self.ballGroundRay.setDirection(0, 0, -1)  # And its direction
+        # Collision solids go in CollisionNode
+        # Create and name the node
+        self.ballGroundCol = CollisionNode('groundRay')
+        self.ballGroundCol.addSolid(self.ballGroundRay)  # Add the ray
+        self.ballGroundCol.setFromCollideMask(
+            BitMask32.bit(1))  # Set its bitmasks
+        self.ballGroundCol.setIntoCollideMask(BitMask32.allOff())
+        # Attach the node to the ballRoot so that the ray is relative to the ball
+        # (it will always be 10 feet over the ball and point down)
+        self.ballGroundColNp = self.ballRoot.attachNewNode(self.ballGroundCol)
+        # Uncomment this line to see the ray
+        #self.ballGroundColNp.show()
+
+        # Finally, we create a CollisionTraverser. CollisionTraversers are what
+        # do the job of walking the scene graph and calculating collisions.
+        # For a traverser to actually do collisions, you need to call
+        # traverser.traverse() on a part of the scene. Fortunately, ShowBase
+        # has a task that does this for the entire scene once a frame.  By
+        # assigning it to self.cTrav, we designate that this is the one that
+        # it should call traverse() on each frame.
+        self.cTrav = CollisionTraverser()
+
+        # Collision traversers tell collision handlers about collisions, and then
+        # the handler decides what to do with the information. We are using a
+        # CollisionHandlerQueue, which simply creates a list of all of the
+        # collisions in a given pass. There are more sophisticated handlers like
+        # one that sends events and another that tries to keep collided objects
+        # apart, but the results are often better with a simple queue
+        self.cHandler = CollisionHandlerQueue()
+        # Now we add the collision nodes that can create a collision to the
+        # traverser. The traverser will compare these to all others nodes in the
+        # scene. There is a limit of 32 CollisionNodes per traverser
+        # We add the collider, and the handler to use as a pair
+        self.cTrav.addCollider(self.ballSphere, self.cHandler)
+        self.cTrav.addCollider(self.ballGroundColNp, self.cHandler)
+
+        # Collision traversers have a built in tool to help visualize collisions.
+        # Uncomment the next line to see it.
+        #self.cTrav.showCollisions(render)
+
+        # This section deals with lighting for the ball. Only the ball was lit
+        # because the maze has static lighting pregenerated by the modeler
+        ambientLight = AmbientLight("ambientLight")
+        ambientLight.setColor((.55, .55, .55, 1))
+        directionalLight = DirectionalLight("directionalLight")
+        directionalLight.setDirection(LVector3(0, 0, -1))
+        directionalLight.setColor((0.375, 0.375, 0.375, 1))
+        directionalLight.setSpecularColor((1, 1, 1, 1))
+        self.ballRoot.setLight(render.attachNewNode(ambientLight))
+        self.ballRoot.setLight(render.attachNewNode(directionalLight))
+
+        # This section deals with adding a specular highlight to the ball to make
+        # it look shiny.  Normally, this is specified in the .egg file.
+        m = Material()
+        m.setSpecular((1, 1, 1, 1))
+        m.setShininess(96)
+        self.ball.setMaterial(m, 1)
+
+        # Finally, we call start for more initialization
+        self.start()
+
+    def start(self):
+        # The maze model also has a locator in it for where to start the ball
+        # To access it we use the find command
+        startPos = self.maze.find("**/start").getPos()
+        # Set the ball in the starting position
+        self.ballRoot.setPos(startPos)
+        self.ballV = LVector3(0, 0, 0)         # Initial velocity is 0
+        self.accelV = LVector3(0, 0, 0)        # Initial acceleration is 0
+
+        # Create the movement task, but first make sure it is not already
+        # running
+        taskMgr.remove("rollTask")
+        self.mainLoop = taskMgr.add(self.rollTask, "rollTask")
+
+    # This function handles the collision between the ray and the ground
+    # Information about the interaction is passed in colEntry
+    def groundCollideHandler(self, colEntry):
+        # Set the ball to the appropriate Z value for it to be exactly on the
+        # ground
+        newZ = colEntry.getSurfacePoint(render).getZ()
+        self.ballRoot.setZ(newZ + .4)
+
+        # Find the acceleration direction. First the surface normal is crossed with
+        # the up vector to get a vector perpendicular to the slope
+        norm = colEntry.getSurfaceNormal(render)
+        accelSide = norm.cross(LVector3.up())
+        # Then that vector is crossed with the surface normal to get a vector that
+        # points down the slope. By getting the acceleration in 3D like this rather
+        # than in 2D, we reduce the amount of error per-frame, reducing jitter
+        self.accelV = norm.cross(accelSide)
+
+    # This function handles the collision between the ball and a wall
+    def wallCollideHandler(self, colEntry):
+        # First we calculate some numbers we need to do a reflection
+        norm = colEntry.getSurfaceNormal(render) * -1  # The normal of the wall
+        curSpeed = self.ballV.length()                # The current speed
+        inVec = self.ballV / curSpeed                 # The direction of travel
+        velAngle = norm.dot(inVec)                    # Angle of incidance
+        hitDir = colEntry.getSurfacePoint(render) - self.ballRoot.getPos()
+        hitDir.normalize()
+        # The angle between the ball and the normal
+        hitAngle = norm.dot(hitDir)
+
+        # Ignore the collision if the ball is either moving away from the wall
+        # already (so that we don't accidentally send it back into the wall)
+        # and ignore it if the collision isn't dead-on (to avoid getting caught on
+        # corners)
+        if velAngle > 0 and hitAngle > .995:
+            # Standard reflection equation
+            reflectVec = (norm * norm.dot(inVec * -1) * 2) + inVec
+
+            # This makes the velocity half of what it was if the hit was dead-on
+            # and nearly exactly what it was if this is a glancing blow
+            self.ballV = reflectVec * (curSpeed * (((1 - velAngle) * .5) + .5))
+            # Since we have a collision, the ball is already a little bit buried in
+            # the wall. This calculates a vector needed to move it so that it is
+            # exactly touching the wall
+            disp = (colEntry.getSurfacePoint(render) -
+                    colEntry.getInteriorPoint(render))
+            newPos = self.ballRoot.getPos() + disp
+            self.ballRoot.setPos(newPos)
+
+    # This is the task that deals with making everything interactive
+    def rollTask(self, task):
+        # Standard technique for finding the amount of time since the last
+        # frame
+        dt = globalClock.getDt()
+
+        # If dt is large, then there has been a # hiccup that could cause the ball
+        # to leave the field if this functions runs, so ignore the frame
+        if dt > .2:
+            return Task.cont
+
+        # The collision handler collects the collisions. We dispatch which function
+        # to handle the collision based on the name of what was collided into
+        for i in range(self.cHandler.getNumEntries()):
+            entry = self.cHandler.getEntry(i)
+            name = entry.getIntoNode().getName()
+            if name == "wall_collide":
+                self.wallCollideHandler(entry)
+            elif name == "ground_collide":
+                self.groundCollideHandler(entry)
+            elif name == "loseTrigger":
+                self.loseGame(entry)
+
+        # Read the mouse position and tilt the maze accordingly
+        if base.mouseWatcherNode.hasMouse():
+            mpos = base.mouseWatcherNode.getMouse()  # get the mouse position
+            self.maze.setP(mpos.getY() * -10)
+            self.maze.setR(mpos.getX() * 10)
+
+        # Finally, we move the ball
+        # Update the velocity based on acceleration
+        self.ballV += self.accelV * dt * ACCEL
+        # Clamp the velocity to the maximum speed
+        if self.ballV.lengthSquared() > MAX_SPEED_SQ:
+            self.ballV.normalize()
+            self.ballV *= MAX_SPEED
+        # Update the position based on the velocity
+        self.ballRoot.setPos(self.ballRoot.getPos() + (self.ballV * dt))
+
+        # This block of code rotates the ball. It uses something called a quaternion
+        # to rotate the ball around an arbitrary axis. That axis perpendicular to
+        # the balls rotation, and the amount has to do with the size of the ball
+        # This is multiplied on the previous rotation to incrimentally turn it.
+        prevRot = LRotationf(self.ball.getQuat())
+        axis = LVector3.up().cross(self.ballV)
+        newRot = LRotationf(axis, 45.5 * dt * self.ballV.length())
+        self.ball.setQuat(prevRot * newRot)
+
+        return Task.cont       # Continue the task indefinitely
+
+    # If the ball hits a hole trigger, then it should fall in the hole.
+    # This is faked rather than dealing with the actual physics of it.
+    def loseGame(self, entry):
+        # The triggers are set up so that the center of the ball should move to the
+        # collision point to be in the hole
+        toPos = entry.getInteriorPoint(render)
+        taskMgr.remove('rollTask')  # Stop the maze task
+
+        # Move the ball into the hole over a short sequence of time. Then wait a
+        # second and call start to reset the game
+        Sequence(
+            Parallel(
+                LerpFunc(self.ballRoot.setX, fromData=self.ballRoot.getX(),
+                         toData=toPos.getX(), duration=.1),
+                LerpFunc(self.ballRoot.setY, fromData=self.ballRoot.getY(),
+                         toData=toPos.getY(), duration=.1),
+                LerpFunc(self.ballRoot.setZ, fromData=self.ballRoot.getZ(),
+                         toData=self.ballRoot.getZ() - .9, duration=.2)),
+            Wait(1),
+            Func(self.start)).start()
+
+# Finally, create an instance of our class and start 3d rendering
+demo = BallInMazeDemo()
+demo.run()

BIN
samples/ball-in-maze/models/ball.egg.pz


BIN
samples/ball-in-maze/models/iron05.jpg


BIN
samples/ball-in-maze/models/limba.jpg


BIN
samples/ball-in-maze/models/maze.egg.pz


+ 199 - 0
samples/boxing-robots/main.py

@@ -0,0 +1,199 @@
+#!/usr/bin/env python
+
+# Author: Shao Zhang, Phil Saltzman, and Eddie Caanan
+# Last Updated: 2015-03-13
+#
+# This tutorial shows how to play animations on models aka "actors".
+# It is based on the popular game of "Rock 'em Sock 'em Robots".
+
+from direct.showbase.ShowBase import ShowBase
+from panda3d.core import AmbientLight, DirectionalLight
+from panda3d.core import TextNode
+from panda3d.core import LVector3
+from direct.gui.OnscreenText import OnscreenText
+from direct.interval.MetaInterval import Sequence
+from direct.interval.FunctionInterval import Func, Wait
+from direct.actor import Actor
+from random import random
+import sys
+
+
+class BoxingRobotDemo(ShowBase):
+    # Macro-like function used to reduce the amount to code needed to create the
+    # on screen instructions
+
+    def genLabelText(self, text, i):
+        return OnscreenText(text=text, parent=base.a2dTopLeft, scale=.05,
+                            pos=(0.1, - 0.1 -.07 * i), fg=(1, 1, 1, 1),
+                            align=TextNode.ALeft)
+
+    def __init__(self):
+        # Initialize the ShowBase class from which we inherit, which will
+        # create a window and set up everything we need for rendering into it.
+        ShowBase.__init__(self)
+
+        # This code puts the standard title and instruction text on screen
+        self.title = OnscreenText(text="Panda3D: Tutorial - Actors",
+                                  parent=base.a2dBottomRight, style=1,
+                                  fg=(0, 0, 0, 1), pos=(-0.2, 0.1),
+                                  align=TextNode.ARight, scale=.09)
+
+        self.escapeEventText = self.genLabelText("ESC: Quit", 0)
+        self.akeyEventText = self.genLabelText("[A]: Robot 1 Left Punch", 1)
+        self.skeyEventText = self.genLabelText("[S]: Robot 1 Right Punch", 2)
+        self.kkeyEventText = self.genLabelText("[K]: Robot 2 Left Punch", 3)
+        self.lkeyEventText = self.genLabelText("[L]: Robot 2 Right Punch", 4)
+
+        # Set the camera in a fixed position
+        self.disableMouse()
+        camera.setPosHpr(14.5, -15.4, 14, 45, -14, 0)
+        self.setBackgroundColor(0, 0, 0)
+
+        # Add lighting so that the objects are not drawn flat
+        self.setupLights()
+
+        # Load the ring
+        self.ring = loader.loadModel('models/ring')
+        self.ring.reparentTo(render)
+
+        # Models that use skeletal animation are known as Actors instead of models
+        # Instead of just one file, the have one file for the main model, and an
+        # additional file for each playable animation.
+        # They are loaded using Actor.Actor instead of loader.LoadModel.
+        # The constructor takes the location of the main object as with a normal model
+        # and a dictionary (A fancy python structure that is like a lookup table)
+        # that contains names for animations, and paths to the appropriate
+        # files
+        self.robot1 = Actor.Actor('models/robot',
+                                  {'leftPunch': 'models/robot_left_punch',
+                                   'rightPunch': 'models/robot_right_punch',
+                                   'headUp': 'models/robot_head_up',
+                                   'headDown': 'models/robot_head_down'})
+
+        # Actors need to be positioned and parented like normal objects
+        self.robot1.setPosHprScale(-1, -2.5, 4, 45, 0, 0, 1.25, 1.25, 1.25)
+        self.robot1.reparentTo(render)
+
+        # We'll repeat the process for the second robot. The only thing that changes
+        # here is the robot's color and position
+        self.robot2 = Actor.Actor('models/robot',
+                                  {'leftPunch': 'models/robot_left_punch',
+                                   'rightPunch': 'models/robot_right_punch',
+                                   'headUp': 'models/robot_head_up',
+                                   'headDown': 'models/robot_head_down'})
+
+        # Set the properties of this robot
+        self.robot2.setPosHprScale(1, 1.5, 4, 225, 0, 0, 1.25, 1.25, 1.25)
+        self.robot2.setColor((.7, 0, 0, 1))
+        self.robot2.reparentTo(render)
+
+        # Now we define how the animated models will move. Animations are played
+        # through special intervals. In this case we use actor intervals in a
+        # sequence to play the part of the punch animation where the arm extends,
+        # call a function to check if the punch landed, and then play the part of the
+        # animation where the arm retracts
+
+        # Punch sequence for robot 1's left arm
+        self.robot1.punchLeft = Sequence(
+            # Interval for the outstreched animation
+            self.robot1.actorInterval('leftPunch', startFrame=1, endFrame=10),
+            # Function to check if the punch was successful
+            Func(self.checkPunch, 2),
+            # Interval for the retract animation
+            self.robot1.actorInterval('leftPunch', startFrame=11, endFrame=32))
+
+        # Punch sequence for robot 1's right arm
+        self.robot1.punchRight = Sequence(
+            self.robot1.actorInterval('rightPunch', startFrame=1, endFrame=10),
+            Func(self.checkPunch, 2),
+            self.robot1.actorInterval('rightPunch', startFrame=11, endFrame=32))
+
+        # Punch sequence for robot 2's left arm
+        self.robot2.punchLeft = Sequence(
+            self.robot2.actorInterval('leftPunch', startFrame=1, endFrame=10),
+            Func(self.checkPunch, 1),
+            self.robot2.actorInterval('leftPunch', startFrame=11, endFrame=32))
+
+        # Punch sequence for robot 2's right arm
+        self.robot2.punchRight = Sequence(
+            self.robot2.actorInterval('rightPunch', startFrame=1, endFrame=10),
+            Func(self.checkPunch, 1),
+            self.robot2.actorInterval('rightPunch', startFrame=11, endFrame=32))
+
+        # We use the same techinique to create a sequence for when a robot is knocked
+        # out where the head pops up, waits a while, and then resets
+
+        # Head animation for robot 1
+        self.robot1.resetHead = Sequence(
+            # Interval for the head going up. Since no start or end frames were given,
+            # the entire animation is played.
+            self.robot1.actorInterval('headUp'),
+            Wait(1.5),
+            # The head down animation was animated a little too quickly, so this will
+            # play it at 75% of it's normal speed
+            self.robot1.actorInterval('headDown', playRate=.75))
+
+        # Head animation for robot 2
+        self.robot2.resetHead = Sequence(
+            self.robot2.actorInterval('headUp'),
+            Wait(1.5),
+            self.robot2.actorInterval('headDown', playRate=.75))
+
+        # Now that we have defined the motion, we can define our key input.
+        # Each fist is bound to a key. When a key is pressed, self.tryPunch checks to
+        # make sure that the both robots have their heads down, and if they do it
+        # plays the given interval
+        self.accept('escape', sys.exit)
+        self.accept('a', self.tryPunch, [self.robot1.punchLeft])
+        self.accept('s', self.tryPunch, [self.robot1.punchRight])
+        self.accept('k', self.tryPunch, [self.robot2.punchLeft])
+        self.accept('l', self.tryPunch, [self.robot2.punchRight])
+
+    # tryPunch will play the interval passed to it only if
+    # neither robot has 'resetHead' playing (a head is up) AND
+    # the punch interval passed to it is not already playing
+    def tryPunch(self, interval):
+        if (not self.robot1.resetHead.isPlaying() and
+                not self.robot2.resetHead.isPlaying() and
+                not interval.isPlaying()):
+            interval.start()
+
+    # checkPunch will determine if a successful punch has been thrown
+    def checkPunch(self, robot):
+        if robot == 1:
+            # punch is directed to robot 1
+            # if robot 1 is playing'resetHead', do nothing
+            if self.robot1.resetHead.isPlaying():
+                return
+            # if robot 1 is not punching...
+            if (not self.robot1.punchLeft.isPlaying() and
+                    not self.robot1.punchRight.isPlaying()):
+                # ...15% chance of successful hit
+                if random() > .85:
+                    self.robot1.resetHead.start()
+            # Otherwise, only 5% chance of sucessful hit
+            elif random() > .95:
+                self.robot1.resetHead.start()
+        else:
+            # punch is directed to robot 2, same as above
+            if self.robot2.resetHead.isPlaying():
+                return
+            if (not self.robot2.punchLeft.isPlaying() and
+                    not self.robot2.punchRight.isPlaying()):
+                if random() > .85:
+                    self.robot2.resetHead.start()
+            elif random() > .95:
+                self.robot2.resetHead.start()
+
+    # This function sets up the lighting
+    def setupLights(self):
+        ambientLight = AmbientLight("ambientLight")
+        ambientLight.setColor((.8, .8, .75, 1))
+        directionalLight = DirectionalLight("directionalLight")
+        directionalLight.setDirection(LVector3(0, 0, -2.5))
+        directionalLight.setColor((0.9, 0.8, 0.9, 1))
+        render.setLight(render.attachNewNode(ambientLight))
+        render.setLight(render.attachNewNode(directionalLight))
+
+demo = BoxingRobotDemo()
+demo.run()

BIN
samples/boxing-robots/models/ring.egg.pz


BIN
samples/boxing-robots/models/robot.egg.pz


BIN
samples/boxing-robots/models/robot_head_down.egg.pz


BIN
samples/boxing-robots/models/robot_head_up.egg.pz


BIN
samples/boxing-robots/models/robot_left_punch.egg.pz


BIN
samples/boxing-robots/models/robot_right_punch.egg.pz


+ 188 - 0
samples/bump-mapping/main.py

@@ -0,0 +1,188 @@
+#!/usr/bin/env python
+#
+# Bump mapping is a way of making polygonal surfaces look
+# less flat.  This sample uses normal mapping for all
+# surfaces, and also parallax mapping for the column.
+#
+# This is a tutorial to show how to do normal mapping
+# in panda3d using the Shader Generator.
+
+from direct.showbase.ShowBase import ShowBase
+from panda3d.core import loadPrcFileData
+from panda3d.core import WindowProperties
+from panda3d.core import Filename, Shader
+from panda3d.core import AmbientLight, PointLight
+from panda3d.core import TextNode
+from panda3d.core import LPoint3, LVector3
+from direct.task.Task import Task
+from direct.actor.Actor import Actor
+from direct.gui.OnscreenText import OnscreenText
+from direct.showbase.DirectObject import DirectObject
+from direct.filter.CommonFilters import *
+import sys
+import os
+
+
+# Function to put instructions on the screen.
+def addInstructions(pos, msg):
+    return OnscreenText(text=msg, style=1, fg=(1, 1, 1, 1), scale=.05,
+                        shadow=(0, 0, 0, 1), parent=base.a2dTopLeft,
+                        pos=(0.08, -pos - 0.04), align=TextNode.ALeft)
+
+# Function to put title on the screen.
+def addTitle(text):
+    return OnscreenText(text=text, style=1, fg=(1, 1, 1, 1), scale=.08,
+                        parent=base.a2dBottomRight, align=TextNode.ARight,
+                        pos=(-0.1, 0.09), shadow=(0, 0, 0, 1))
+
+
+class BumpMapDemo(ShowBase):
+
+    def __init__(self):
+        # Configure the parallax mapping settings (these are just the defaults)
+        loadPrcFileData("", "parallax-mapping-samples 3\n"
+                            "parallax-mapping-scale 0.1")
+
+        # Initialize the ShowBase class from which we inherit, which will
+        # create a window and set up everything we need for rendering into it.
+        ShowBase.__init__(self)
+
+        # Check video card capabilities.
+        if not self.win.getGsg().getSupportsBasicShaders():
+            addTitle("Bump Mapping: "
+                "Video driver reports that Cg shaders are not supported.")
+            return
+
+        # Post the instructions
+        self.title = addTitle("Panda3D: Tutorial - Bump Mapping")
+        self.inst1 = addInstructions(0.06, "Press ESC to exit")
+        self.inst2 = addInstructions(0.12, "Move mouse to rotate camera")
+        self.inst3 = addInstructions(0.18, "Left mouse button: Move forwards")
+        self.inst4 = addInstructions(0.24, "Right mouse button: Move backwards")
+        self.inst5 = addInstructions(0.30, "Enter: Turn bump maps Off")
+
+        # Load the 'abstract room' model.  This is a model of an
+        # empty room containing a pillar, a pyramid, and a bunch
+        # of exaggeratedly bumpy textures.
+
+        self.room = loader.loadModel("models/abstractroom")
+        self.room.reparentTo(render)
+
+        # Make the mouse invisible, turn off normal mouse controls
+        self.disableMouse()
+        props = WindowProperties()
+        props.setCursorHidden(True)
+        self.win.requestProperties(props)
+        self.camLens.setFov(60)
+
+        # Set the current viewing target
+        self.focus = LVector3(55, -55, 20)
+        self.heading = 180
+        self.pitch = 0
+        self.mousex = 0
+        self.mousey = 0
+        self.last = 0
+        self.mousebtn = [0, 0, 0]
+
+        # Start the camera control task:
+        taskMgr.add(self.controlCamera, "camera-task")
+        self.accept("escape", sys.exit, [0])
+        self.accept("mouse1", self.setMouseBtn, [0, 1])
+        self.accept("mouse1-up", self.setMouseBtn, [0, 0])
+        self.accept("mouse2", self.setMouseBtn, [1, 1])
+        self.accept("mouse2-up", self.setMouseBtn, [1, 0])
+        self.accept("mouse3", self.setMouseBtn, [2, 1])
+        self.accept("mouse3-up", self.setMouseBtn, [2, 0])
+        self.accept("enter", self.toggleShader)
+        self.accept("j", self.rotateLight, [-1])
+        self.accept("k", self.rotateLight, [1])
+        self.accept("arrow_left", self.rotateCam, [-1])
+        self.accept("arrow_right", self.rotateCam, [1])
+
+        # Add a light to the scene.
+        self.lightpivot = render.attachNewNode("lightpivot")
+        self.lightpivot.setPos(0, 0, 25)
+        self.lightpivot.hprInterval(10, LPoint3(360, 0, 0)).loop()
+        plight = PointLight('plight')
+        plight.setColor((1, 1, 1, 1))
+        plight.setAttenuation(LVector3(0.7, 0.05, 0))
+        plnp = self.lightpivot.attachNewNode(plight)
+        plnp.setPos(45, 0, 0)
+        self.room.setLight(plnp)
+
+        # Add an ambient light
+        alight = AmbientLight('alight')
+        alight.setColor((0.2, 0.2, 0.2, 1))
+        alnp = render.attachNewNode(alight)
+        self.room.setLight(alnp)
+
+        # Create a sphere to denote the light
+        sphere = loader.loadModel("models/icosphere")
+        sphere.reparentTo(plnp)
+
+        # Tell Panda that it should generate shaders performing per-pixel
+        # lighting for the room.
+        self.room.setShaderAuto()
+
+        self.shaderenable = 1
+
+    def setMouseBtn(self, btn, value):
+        self.mousebtn[btn] = value
+
+    def rotateLight(self, offset):
+        self.lightpivot.setH(self.lightpivot.getH() + offset * 20)
+
+    def rotateCam(self, offset):
+        self.heading = self.heading - offset * 10
+
+    def toggleShader(self):
+        self.inst5.destroy()
+        if (self.shaderenable):
+            self.inst5 = addInstructions(0.30, "Enter: Turn bump maps On")
+            self.shaderenable = 0
+            self.room.setShaderOff()
+        else:
+            self.inst5 = addInstructions(0.30, "Enter: Turn bump maps Off")
+            self.shaderenable = 1
+            self.room.setShaderAuto()
+
+    def controlCamera(self, task):
+        # figure out how much the mouse has moved (in pixels)
+        md = self.win.getPointer(0)
+        x = md.getX()
+        y = md.getY()
+        if self.win.movePointer(0, 100, 100):
+            self.heading = self.heading - (x - 100) * 0.2
+            self.pitch = self.pitch - (y - 100) * 0.2
+        if self.pitch < -45:
+            self.pitch = -45
+        if self.pitch > 45:
+            self.pitch = 45
+        self.camera.setHpr(self.heading, self.pitch, 0)
+        dir = self.camera.getMat().getRow3(1)
+        elapsed = task.time - self.last
+        if self.last == 0:
+            elapsed = 0
+        if self.mousebtn[0]:
+            self.focus = self.focus + dir * elapsed * 30
+        if self.mousebtn[1] or self.mousebtn[2]:
+            self.focus = self.focus - dir * elapsed * 30
+        self.camera.setPos(self.focus - (dir * 5))
+        if self.camera.getX() < -59.0:
+            self.camera.setX(-59)
+        if self.camera.getX() > 59.0:
+            self.camera.setX(59)
+        if self.camera.getY() < -59.0:
+            self.camera.setY(-59)
+        if self.camera.getY() > 59.0:
+            self.camera.setY(59)
+        if self.camera.getZ() < 5.0:
+            self.camera.setZ(5)
+        if self.camera.getZ() > 45.0:
+            self.camera.setZ(45)
+        self.focus = self.camera.getPos() + (dir * 5)
+        self.last = task.time
+        return Task.cont
+
+demo = BumpMapDemo()
+demo.run()

+ 1671 - 0
samples/bump-mapping/models/abstractroom.egg

@@ -0,0 +1,1671 @@
+<CoordinateSystem> { Y-Up }
+
+<Comment> {
+  "maya2egg85 -o room.egg room.mb"
+}
+<Texture> phong3SG.tref3 {
+  layingrock-n.jpg
+  <Scalar> format { rgba }
+  <Scalar> alpha-file { layingrock-h.jpg }
+  <Scalar> wrapu { repeat }
+  <Scalar> wrapv { repeat }
+  <Scalar> minfilter { linear_mipmap_linear }
+  <Scalar> magfilter { linear }
+  <Scalar> envtype { normal_height }
+}
+<Texture> phong3SG {
+  layingrock-c.jpg
+  <Scalar> format { rgb }
+  <Scalar> wrapu { repeat }
+  <Scalar> wrapv { repeat }
+  <Scalar> minfilter { linear_mipmap_linear }
+  <Scalar> magfilter { linear }
+}
+<Texture> phong2SG.tref1 {
+  brick-n.jpg
+  <Scalar> format { rgb }
+  <Scalar> wrapu { repeat }
+  <Scalar> wrapv { repeat }
+  <Scalar> minfilter { linear_mipmap_linear }
+  <Scalar> magfilter { linear }
+  <Scalar> envtype { normal }
+}
+<Texture> phong2SG {
+  brick-c.jpg
+  <Scalar> format { rgb }
+  <Scalar> wrapu { repeat }
+  <Scalar> wrapv { repeat }
+  <Scalar> minfilter { linear_mipmap_linear }
+  <Scalar> magfilter { linear }
+}
+<Texture> phong1SG.tref2 {
+  fieldstone-n.jpg
+  <Scalar> format { rgb }
+  <Scalar> wrapu { repeat }
+  <Scalar> wrapv { repeat }
+  <Scalar> minfilter { linear_mipmap_linear }
+  <Scalar> magfilter { linear }
+  <Scalar> envtype { normal }
+}
+<Texture> phong1SG {
+  fieldstone-c.jpg
+  <Scalar> format { rgb }
+  <Scalar> wrapu { repeat }
+  <Scalar> wrapv { repeat }
+  <Scalar> minfilter { linear_mipmap_linear }
+  <Scalar> magfilter { linear }
+}
+<Group> groundPlane_transform {
+}
+<Group> polySurface2 {
+  <VertexPool> polySurfaceShape2.verts {
+    <Vertex> 0 {
+      -60 0 -60
+      <UV> {
+        3 3
+        <Tangent> { 0 -3.83044e-009 -1 }
+        <Binormal> { -1 -3.83044e-009 0 }
+      }
+      <Normal> { -3.83044e-009 1 -3.83044e-009 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 1 {
+      -60 0 -60
+      <UV> {
+        -0.5 -0.5
+        <Tangent> { 1 0 0 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0 0 1 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 2 {
+      -60 0 -60
+      <UV> {
+        1.5 -0.5
+        <Tangent> { 0 0 -1 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 1 0 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 3 {
+      -60 0 60
+      <UV> {
+        1.5 -0.5
+        <Tangent> { -1 0 0 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0 0 -1 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 4 {
+      -60 0 60
+      <UV> {
+        -2 3
+        <Tangent> { -5.15653e-008 4.13254e-011 -1 }
+        <Binormal> { -1 4.13254e-011 5.15653e-008 }
+      }
+      <Normal> { 4.13254e-011 1 4.13254e-011 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 5 {
+      -60 0 60
+      <UV> {
+        -0.5 -0.5
+        <Tangent> { 0 0 -1 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 1 0 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 6 {
+      -60 50 -60
+      <UV> {
+        -0.5 1.5
+        <Tangent> { 1 0 0 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0 0 1 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 7 {
+      -60 50 -60
+      <UV> {
+        1.5 1.5
+        <Tangent> { 0 0 -1 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 1 0 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 8 {
+      -60 50 60
+      <UV> {
+        1.5 1.5
+        <Tangent> { -1 0 0 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0 0 -1 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 9 {
+      -60 50 60
+      <UV> {
+        -0.5 1.5
+        <Tangent> { 0 0 -1 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 1 0 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 10 {
+      -37.5 0 25
+      <UV> {
+        -1.49994 -1
+        <Tangent> { 0 0 1 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { -1 0 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 11 {
+      -37.5 0 25
+      <UV> {
+        2.50006 -1
+        <Tangent> { 0 0 1 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { -1 0 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 12 {
+      -37.5 50 25
+      <UV> {
+        -1.49994 2
+        <Tangent> { 0 0 1 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { -1 0 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 13 {
+      -37.5 50 25
+      <UV> {
+        2.50006 2
+        <Tangent> { 0 0 1 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { -1 0 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 14 {
+      -37.5 50 25
+      <UV> {
+        -0.541667 2.0625
+        <Tangent> { 0 0 -1 }
+        <Binormal> { -1 0 0 }
+      }
+      <Normal> { 0 -1 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 15 {
+      -36.8882 0 21.1373
+      <UV> {
+        2.30006 -1
+        <Tangent> { -0.309017 0 0.951057 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { -0.951057 0 -0.309017 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 16 {
+      -36.8882 0 28.8627
+      <UV> {
+        -1.29994 -1
+        <Tangent> { 0.309017 0 0.951057 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { -0.951057 0 0.309017 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 17 {
+      -36.8882 50 21.1373
+      <UV> {
+        2.30006 2
+        <Tangent> { -0.309017 0 0.951057 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { -0.951057 0 -0.309017 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 18 {
+      -36.8882 50 21.1373
+      <UV> {
+        -0.38072 2.03701
+        <Tangent> { 6.17012e-006 0 -1 }
+        <Binormal> { -1 0 -6.17012e-006 }
+      }
+      <Normal> { 0 -1 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 19 {
+      -36.8882 50 28.8627
+      <UV> {
+        -1.29994 2
+        <Tangent> { 0.309017 0 0.951057 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { -0.951057 0 0.309017 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 20 {
+      -36.8882 50 28.8627
+      <UV> {
+        -0.702613 2.03701
+        <Tangent> { -6.17012e-006 0 -1 }
+        <Binormal> { -1 0 6.17012e-006 }
+      }
+      <Normal> { 0 -1 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 21 {
+      -35.1127 0 17.6527
+      <UV> {
+        2.10006 -1
+        <Tangent> { -0.587785 0 0.809017 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { -0.809017 0 -0.587785 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 22 {
+      -35.1127 0 32.3473
+      <UV> {
+        -1.09994 -1
+        <Tangent> { 0.587785 0 0.809017 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { -0.809017 0 0.587785 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 23 {
+      -35.1127 50 17.6527
+      <UV> {
+        2.10006 2
+        <Tangent> { -0.587785 0 0.809017 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { -0.809017 0 -0.587785 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 24 {
+      -35.1127 50 17.6527
+      <UV> {
+        -0.235528 1.96303
+        <Tangent> { -1.03074e-007 0 -1 }
+        <Binormal> { -1 0 1.03074e-007 }
+      }
+      <Normal> { 0 -1 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 25 {
+      -35.1127 50 32.3473
+      <UV> {
+        -1.09994 2
+        <Tangent> { 0.587785 0 0.809017 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { -0.809017 0 0.587785 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 26 {
+      -35.1127 50 32.3473
+      <UV> {
+        -0.847805 1.96303
+        <Tangent> { 1.03075e-007 0 -1 }
+        <Binormal> { -1 0 -1.03075e-007 }
+      }
+      <Normal> { 0 -1 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 27 {
+      -32.3473 0 14.8873
+      <UV> {
+        1.90006 -1
+        <Tangent> { -0.809017 0 0.587786 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { -0.587786 0 -0.809017 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 28 {
+      -32.3473 0 35.1127
+      <UV> {
+        -0.899936 -1
+        <Tangent> { 0.809017 0 0.587785 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { -0.587785 0 0.809017 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 29 {
+      -32.3473 0 35.1127
+      <UV> {
+        -0.96303 1.84781
+        <Tangent> { 1.52608e-007 4.13254e-011 -1 }
+        <Binormal> { -1 4.13254e-011 -1.52608e-007 }
+      }
+      <Normal> { 4.13254e-011 1 4.13254e-011 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 30 {
+      -32.3473 50 14.8873
+      <UV> {
+        1.90006 2
+        <Tangent> { -0.809017 0 0.587786 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { -0.587786 0 -0.809017 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 31 {
+      -32.3473 50 14.8873
+      <UV> {
+        -0.120303 1.84781
+        <Tangent> { -8.0634e-006 0 -1 }
+        <Binormal> { -1 0 8.0634e-006 }
+      }
+      <Normal> { 0 -1 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 32 {
+      -32.3473 50 35.1127
+      <UV> {
+        -0.899936 2
+        <Tangent> { 0.809017 0 0.587785 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { -0.587785 0 0.809017 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 33 {
+      -28.8627 0 13.1118
+      <UV> {
+        1.70006 -1
+        <Tangent> { -0.951057 0 0.309017 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { -0.309017 0 -0.951057 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 34 {
+      -28.8627 0 36.8882
+      <UV> {
+        -0.699936 -1
+        <Tangent> { 0.951057 0 0.309016 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { -0.309016 0 0.951057 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 35 {
+      -28.8627 50 13.1118
+      <UV> {
+        1.70006 2
+        <Tangent> { -0.951057 0 0.309017 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { -0.309017 0 -0.951057 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 36 {
+      -28.8627 50 13.1118
+      <UV> {
+        -0.0463246 1.70261
+        <Tangent> { 3.81471e-007 0 -1 }
+        <Binormal> { -1 0 -3.81471e-007 }
+      }
+      <Normal> { 0 -1 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 37 {
+      -28.8627 50 36.8882
+      <UV> {
+        -0.699936 2
+        <Tangent> { 0.951057 0 0.309016 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { -0.309016 0 0.951057 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 38 {
+      -28.8627 50 36.8882
+      <UV> {
+        -1.03701 1.70261
+        <Tangent> { -3.81475e-007 0 -1 }
+        <Binormal> { -1 -4.89652e-008 3.81475e-007 }
+      }
+      <Normal> { 4.89652e-008 -1 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 39 {
+      -25 0 12.5
+      <UV> {
+        1.50006 -1
+        <Tangent> { -1 0 -6.03476e-007 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 6.03476e-007 0 -1 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 40 {
+      -25 0 37.5
+      <UV> {
+        -0.499936 -1
+        <Tangent> { 1 0 0 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0 0 1 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 41 {
+      -25 50 12.5
+      <UV> {
+        -0.0208334 1.54167
+        <Tangent> { 1.16912e-005 0 -1 }
+        <Binormal> { -1 0 -1.16912e-005 }
+      }
+      <Normal> { 0 -1 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 42 {
+      -25 50 12.5
+      <UV> {
+        1.50006 2
+        <Tangent> { -1 0 -6.03476e-007 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 6.03476e-007 0 -1 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 43 {
+      -25 50 37.5
+      <UV> {
+        -0.499936 2
+        <Tangent> { 1 0 0 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0 0 1 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 44 {
+      -25 50 37.5
+      <UV> {
+        -1.0625 1.54167
+        <Tangent> { -1.16911e-005 0 -1 }
+        <Binormal> { -1 -4.89652e-008 1.16911e-005 }
+      }
+      <Normal> { 4.89652e-008 -1 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 45 {
+      -21.1373 0 13.1118
+      <UV> {
+        1.30006 -1
+        <Tangent> { -0.951057 0 -0.309017 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0.309017 0 -0.951057 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 46 {
+      -21.1373 0 36.8882
+      <UV> {
+        -0.299936 -1
+        <Tangent> { 0.951057 0 -0.309016 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0.309016 0 0.951057 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 47 {
+      -21.1373 50 13.1118
+      <UV> {
+        -0.0463246 1.38072
+        <Tangent> { -1.09281e-005 0 -1 }
+        <Binormal> { -1 0 1.09281e-005 }
+      }
+      <Normal> { 0 -1 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 48 {
+      -21.1373 50 13.1118
+      <UV> {
+        1.30006 2
+        <Tangent> { -0.951057 0 -0.309017 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0.309017 0 -0.951057 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 49 {
+      -21.1373 50 36.8882
+      <UV> {
+        -1.03701 1.38072
+        <Tangent> { 1.09282e-005 0 -1 }
+        <Binormal> { -1 -4.89652e-008 -1.09282e-005 }
+      }
+      <Normal> { 4.89652e-008 -1 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 50 {
+      -21.1373 50 36.8882
+      <UV> {
+        -0.299936 2
+        <Tangent> { 0.951057 0 -0.309016 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0.309016 0 0.951057 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 51 {
+      -17.6527 0 14.8873
+      <UV> {
+        1.10006 -1
+        <Tangent> { -0.809017 0 -0.587785 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0.587785 0 -0.809017 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 52 {
+      -17.6527 0 35.1127
+      <UV> {
+        -0.0999364 -1
+        <Tangent> { 0.809017 0 -0.587785 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0.587785 0 0.809017 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 53 {
+      -17.6527 50 14.8873
+      <UV> {
+        -0.120304 1.23553
+        <Tangent> { -7.25597e-007 0 -1 }
+        <Binormal> { -1 0 7.25597e-007 }
+      }
+      <Normal> { 0 -1 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 54 {
+      -17.6527 50 14.8873
+      <UV> {
+        1.10006 2
+        <Tangent> { -0.809017 0 -0.587785 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0.587785 0 -0.809017 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 55 {
+      -17.6527 50 35.1127
+      <UV> {
+        -0.96303 1.23553
+        <Tangent> { 7.25593e-007 0 -1 }
+        <Binormal> { -1 -4.89652e-008 -7.25593e-007 }
+      }
+      <Normal> { 4.89652e-008 -1 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 56 {
+      -17.6527 50 35.1127
+      <UV> {
+        -0.0999364 2
+        <Tangent> { 0.809017 0 -0.587785 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0.587785 0 0.809017 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 57 {
+      -14.8873 0 17.6527
+      <UV> {
+        -0.235528 1.1203
+        <Tangent> { -5.45099e-007 4.13254e-011 -1 }
+        <Binormal> { -1 4.13254e-011 5.45099e-007 }
+      }
+      <Normal> { 4.13254e-011 1 4.13254e-011 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 58 {
+      -14.8873 0 17.6527
+      <UV> {
+        0.900064 -1
+        <Tangent> { -0.587785 0 -0.809017 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0.809017 0 -0.587785 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 59 {
+      -14.8873 0 32.3473
+      <UV> {
+        0.100064 -1
+        <Tangent> { 0.587785 0 -0.809017 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0.809017 0 0.587785 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 60 {
+      -14.8873 50 17.6527
+      <UV> {
+        0.900064 2
+        <Tangent> { -0.587785 0 -0.809017 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0.809017 0 -0.587785 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 61 {
+      -14.8873 50 32.3473
+      <UV> {
+        -0.847805 1.1203
+        <Tangent> { -1.79128e-006 0 -1 }
+        <Binormal> { -1 -4.89652e-008 1.79128e-006 }
+      }
+      <Normal> { 4.89652e-008 -1 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 62 {
+      -14.8873 50 32.3473
+      <UV> {
+        0.100064 2
+        <Tangent> { 0.587785 0 -0.809017 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0.809017 0 0.587785 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 63 {
+      -13.1118 0 21.1373
+      <UV> {
+        0.700064 -1
+        <Tangent> { -0.309017 0 -0.951057 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0.951057 0 -0.309017 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 64 {
+      -13.1118 0 28.8627
+      <UV> {
+        0.300064 -1
+        <Tangent> { 0.309017 0 -0.951057 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0.951057 0 0.309017 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 65 {
+      -13.1118 50 21.1373
+      <UV> {
+        -0.38072 1.04633
+        <Tangent> { 3.58256e-006 0 -1 }
+        <Binormal> { -1 -4.89652e-008 -3.58256e-006 }
+      }
+      <Normal> { 4.89652e-008 -1 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 66 {
+      -13.1118 50 21.1373
+      <UV> {
+        0.700064 2
+        <Tangent> { -0.309017 0 -0.951057 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0.951057 0 -0.309017 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 67 {
+      -13.1118 50 28.8627
+      <UV> {
+        -0.702613 1.04633
+        <Tangent> { -3.58256e-006 0 -1 }
+        <Binormal> { -1 -4.89652e-008 3.58256e-006 }
+      }
+      <Normal> { 4.89652e-008 -1 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 68 {
+      -13.1118 50 28.8627
+      <UV> {
+        0.300064 2
+        <Tangent> { 0.309017 0 -0.951057 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0.951057 0 0.309017 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 69 {
+      -12.5 0 25
+      <UV> {
+        0.500064 -1
+        <Tangent> { 0 0 -1 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 1 0 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 70 {
+      -12.5 50 25
+      <UV> {
+        -0.541667 1.02083
+        <Tangent> { 0 0 -1 }
+        <Binormal> { -1 -4.89652e-008 0 }
+      }
+      <Normal> { 4.89652e-008 -1 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 71 {
+      -12.5 50 25
+      <UV> {
+        0.500064 2
+        <Tangent> { 0 0 -1 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 1 0 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 72 {
+      5 0 -5
+      <UV> {
+        0.708333 0.291667
+        <Tangent> { -1.84039e-007 4.13254e-011 -1 }
+        <Binormal> { -1 4.13254e-011 1.84039e-007 }
+      }
+      <Normal> { 4.13254e-011 1 4.13254e-011 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 73 {
+      5 1.19209e-006 -45
+      <UV> {
+        1.5 -0.5
+        <Tangent> { -1 -1.49012e-008 0 }
+        <Binormal> { -1.49012e-008 1 0 }
+      }
+      <Normal> { 0 0 -1 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 74 {
+      5 10 -45
+      <UV> {
+        1.5 0.166667
+        <Tangent> { -1 0 0 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0 0 -1 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 75 {
+      5 10 -45
+      <UV> {
+        1.5 0.166667
+        <Tangent> { -1 0 0 }
+        <Binormal> { 0 0.707107 0.707107 }
+      }
+      <Normal> { 0 0.707107 -0.707107 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 76 {
+      25 30 -25
+      <UV> {
+        0.5 1.5
+        <Tangent> { -1 0 0 }
+        <Binormal> { 0 0.707107 0.707107 }
+      }
+      <Normal> { 0 0.707107 -0.707107 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 77 {
+      25 30 -25
+      <UV> {
+        0.5 1.5
+        <Tangent> { 0 0 -1 }
+        <Binormal> { -0.707107 0.707107 0 }
+      }
+      <Normal> { 0.707107 0.707107 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 78 {
+      45 0 -45
+      <UV> {
+        -0.5 -0.5
+        <Tangent> { -1 -1.49012e-008 0 }
+        <Binormal> { -1.49012e-008 1 0 }
+      }
+      <Normal> { 0 0 -1 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 79 {
+      45 0 -45
+      <UV> {
+        2.375 -1.375
+        <Tangent> { -2.98023e-008 4.13254e-011 -1 }
+        <Binormal> { -1 4.13254e-011 2.98023e-008 }
+      }
+      <Normal> { 4.13254e-011 1 4.13254e-011 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 80 {
+      45 0 -45
+      <UV> {
+        1.5 -0.5
+        <Tangent> { 0 1.49012e-008 -1 }
+        <Binormal> { 0 1 1.49012e-008 }
+      }
+      <Normal> { 1 0 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 81 {
+      45 1.19209e-006 -5
+      <UV> {
+        -0.5 -0.5
+        <Tangent> { 0 1.49012e-008 -1 }
+        <Binormal> { 0 1 1.49012e-008 }
+      }
+      <Normal> { 1 0 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 82 {
+      45 10 -45
+      <UV> {
+        -0.5 0.166667
+        <Tangent> { -1 0 0 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0 0 -1 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 83 {
+      45 10 -45
+      <UV> {
+        -0.5 0.166667
+        <Tangent> { -1 0 0 }
+        <Binormal> { 0 0.707107 0.707107 }
+      }
+      <Normal> { 0 0.707107 -0.707107 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 84 {
+      45 10 -45
+      <UV> {
+        1.5 0.166667
+        <Tangent> { 0 0 -1 }
+        <Binormal> { -0.707107 0.707107 0 }
+      }
+      <Normal> { 0.707107 0.707107 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 85 {
+      45 10 -45
+      <UV> {
+        1.5 0.166667
+        <Tangent> { 0 0 -1 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 1 0 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 86 {
+      45 10 -5
+      <UV> {
+        -0.5 0.166667
+        <Tangent> { 0 0 -1 }
+        <Binormal> { -0.707107 0.707107 0 }
+      }
+      <Normal> { 0.707107 0.707107 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 87 {
+      45 10 -5
+      <UV> {
+        -0.5 0.166667
+        <Tangent> { 0 0 -1 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 1 0 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 88 {
+      60 0 -60
+      <UV> {
+        1.5 1.5
+        <Tangent> { 0 0 -1 }
+        <Binormal> { 0 -1 0 }
+      }
+      <Normal> { -1 0 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 89 {
+      60 0 -60
+      <UV> {
+        1.5 -0.5
+        <Tangent> { 1 0 0 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0 0 1 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 90 {
+      60 0 -60
+      <UV> {
+        3 -2
+        <Tangent> { -1.19209e-008 4.13254e-011 -1 }
+        <Binormal> { -1 4.13254e-011 1.19209e-008 }
+      }
+      <Normal> { 4.13254e-011 1 4.13254e-011 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 91 {
+      60 0 60
+      <UV> {
+        -0.5 1.5
+        <Tangent> { 0 0 -1 }
+        <Binormal> { 0 -1 0 }
+      }
+      <Normal> { -1 0 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 92 {
+      60 0 60
+      <UV> {
+        -0.5 -0.5
+        <Tangent> { -1 0 0 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0 0 -1 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 93 {
+      60 0 60
+      <UV> {
+        -2 -2
+        <Tangent> { 0 3.91309e-009 -1 }
+        <Binormal> { -1 3.91309e-009 0 }
+      }
+      <Normal> { 3.91309e-009 1 3.91309e-009 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 94 {
+      60 50 -60
+      <UV> {
+        1.5 -0.5
+        <Tangent> { 0 0 -1 }
+        <Binormal> { 0 -1 0 }
+      }
+      <Normal> { -1 0 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 95 {
+      60 50 -60
+      <UV> {
+        1.5 1.5
+        <Tangent> { 1 0 0 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0 0 1 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 96 {
+      60 50 60
+      <UV> {
+        -0.5 -0.5
+        <Tangent> { 0 0 -1 }
+        <Binormal> { 0 -1 0 }
+      }
+      <Normal> { -1 0 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 97 {
+      60 50 60
+      <UV> {
+        -0.5 1.5
+        <Tangent> { -1 0 0 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0 0 -1 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 98 {
+      -60 50 -60
+      <UV> {
+        3 3
+        <Tangent> { 0 0 -1 }
+        <Binormal> { -1 0 0 }
+      }
+      <Normal> { 0 -1 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 99 {
+      -60 50 60
+      <UV> {
+        -2 3
+        <Tangent> { -1.18287e-008 0 -1 }
+        <Binormal> { -1 -2.44826e-008 1.18287e-008 }
+      }
+      <Normal> { 2.44826e-008 -1 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 100 {
+      -37.5 0 25
+      <UV> {
+        -0.541667 2.0625
+        <Tangent> { 0 -3.83044e-009 -1 }
+        <Binormal> { -1 -3.83044e-009 0 }
+      }
+      <Normal> { -3.83044e-009 1 -3.83044e-009 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 101 {
+      -36.8882 0 21.1373
+      <UV> {
+        -0.38072 2.03701
+        <Tangent> { -2.784e-007 -3.83044e-009 -1 }
+        <Binormal> { -1 -3.83044e-009 2.784e-007 }
+      }
+      <Normal> { -3.83044e-009 1 -3.83044e-009 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 102 {
+      -36.8882 0 28.8627
+      <UV> {
+        -0.702613 2.03701
+        <Tangent> { 2.784e-007 -3.83044e-009 -1 }
+        <Binormal> { -1 -3.83044e-009 -2.784e-007 }
+      }
+      <Normal> { -3.83044e-009 1 -3.83044e-009 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 103 {
+      -35.1127 0 17.6527
+      <UV> {
+        -0.235528 1.96303
+        <Tangent> { -1.03074e-007 -3.83044e-009 -1 }
+        <Binormal> { -1 -3.83044e-009 1.03074e-007 }
+      }
+      <Normal> { -3.83044e-009 1 -3.83044e-009 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 104 {
+      -35.1127 0 32.3473
+      <UV> {
+        -0.847805 1.96303
+        <Tangent> { 1.03075e-007 -3.83044e-009 -1 }
+        <Binormal> { -1 -3.83044e-009 -1.03075e-007 }
+      }
+      <Normal> { -3.83044e-009 1 -3.83044e-009 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 105 {
+      -32.3473 0 14.8873
+      <UV> {
+        -0.120303 1.84781
+        <Tangent> { -8.0634e-006 -3.83047e-009 -1 }
+        <Binormal> { -1 -3.83041e-009 8.0634e-006 }
+      }
+      <Normal> { -3.83044e-009 1 -3.83044e-009 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 106 {
+      -32.3473 50 35.1127
+      <UV> {
+        -0.96303 1.84781
+        <Tangent> { 1.52608e-007 0 -1 }
+        <Binormal> { -1 -2.44826e-008 -1.52608e-007 }
+      }
+      <Normal> { 2.44826e-008 -1 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 107 {
+      -28.8627 0 13.1118
+      <UV> {
+        -0.0463246 1.70261
+        <Tangent> { 3.81471e-007 -3.83044e-009 -1 }
+        <Binormal> { -1 -3.83044e-009 -3.81471e-007 }
+      }
+      <Normal> { -3.83044e-009 1 -3.83044e-009 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 108 {
+      -28.8627 0 36.8882
+      <UV> {
+        -1.03701 1.70261
+        <Tangent> { -3.81475e-007 3.91309e-009 -1 }
+        <Binormal> { -1 3.91309e-009 3.81475e-007 }
+      }
+      <Normal> { 3.91309e-009 1 3.91309e-009 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 109 {
+      -25 0 12.5
+      <UV> {
+        -0.0208334 1.54167
+        <Tangent> { 1.16912e-005 -3.83039e-009 -1 }
+        <Binormal> { -1 -3.83048e-009 -1.16912e-005 }
+      }
+      <Normal> { -3.83044e-009 1 -3.83044e-009 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 110 {
+      -25 0 37.5
+      <UV> {
+        -1.0625 1.54167
+        <Tangent> { -1.16911e-005 3.91314e-009 -1 }
+        <Binormal> { -1 3.91304e-009 1.16911e-005 }
+      }
+      <Normal> { 3.91309e-009 1 3.91309e-009 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 111 {
+      -21.1373 0 13.1118
+      <UV> {
+        -0.0463246 1.38072
+        <Tangent> { -1.09281e-005 -3.83048e-009 -1 }
+        <Binormal> { -1 -3.8304e-009 1.09281e-005 }
+      }
+      <Normal> { -3.83044e-009 1 -3.83044e-009 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 112 {
+      -21.1373 0 36.8882
+      <UV> {
+        -1.03701 1.38072
+        <Tangent> { 1.09282e-005 3.91305e-009 -1 }
+        <Binormal> { -1 3.91313e-009 -1.09282e-005 }
+      }
+      <Normal> { 3.91309e-009 1 3.91309e-009 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 113 {
+      -17.6527 0 14.8873
+      <UV> {
+        -0.120304 1.23553
+        <Tangent> { -7.25597e-007 -3.83044e-009 -1 }
+        <Binormal> { -1 -3.83044e-009 7.25597e-007 }
+      }
+      <Normal> { -3.83044e-009 1 -3.83044e-009 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 114 {
+      -17.6527 0 35.1127
+      <UV> {
+        -0.96303 1.23553
+        <Tangent> { 7.25593e-007 3.91309e-009 -1 }
+        <Binormal> { -1 3.91309e-009 -7.25593e-007 }
+      }
+      <Normal> { 3.91309e-009 1 3.91309e-009 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 115 {
+      -14.8873 0 32.3473
+      <UV> {
+        -0.847805 1.1203
+        <Tangent> { -1.79128e-006 3.9131e-009 -1 }
+        <Binormal> { -1 3.91308e-009 1.79128e-006 }
+      }
+      <Normal> { 3.91309e-009 1 3.91309e-009 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 116 {
+      -14.8873 50 17.6527
+      <UV> {
+        -0.235528 1.1203
+        <Tangent> { -4.96743e-007 0 -1 }
+        <Binormal> { -1 -2.44826e-008 4.96743e-007 }
+      }
+      <Normal> { 2.44826e-008 -1 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 117 {
+      -13.1118 0 21.1373
+      <UV> {
+        -0.38072 1.04633
+        <Tangent> { 3.58256e-006 3.91308e-009 -1 }
+        <Binormal> { -1 3.9131e-009 -3.58256e-006 }
+      }
+      <Normal> { 3.91309e-009 1 3.91309e-009 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 118 {
+      -13.1118 0 28.8627
+      <UV> {
+        -0.702613 1.04633
+        <Tangent> { -3.58256e-006 3.9131e-009 -1 }
+        <Binormal> { -1 3.91308e-009 3.58256e-006 }
+      }
+      <Normal> { 3.91309e-009 1 3.91309e-009 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 119 {
+      -12.5 0 25
+      <UV> {
+        -0.541667 1.02083
+        <Tangent> { 0 3.91309e-009 -1 }
+        <Binormal> { -1 3.91309e-009 0 }
+      }
+      <Normal> { 3.91309e-009 1 3.91309e-009 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 120 {
+      5 0 -5
+      <UV> {
+        -0.5 -0.5
+        <Tangent> { 0 -1.49012e-008 -1 }
+        <Binormal> { 0 1 -1.49012e-008 }
+      }
+      <Normal> { -1 0 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 121 {
+      5 0 -5
+      <UV> {
+        1.5 -0.5
+        <Tangent> { -1 1.49012e-008 0 }
+        <Binormal> { 1.49012e-008 1 0 }
+      }
+      <Normal> { 0 0 1 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 122 {
+      5 1.19209e-006 -45
+      <UV> {
+        1.5 -0.5
+        <Tangent> { 0 -1.49012e-008 -1 }
+        <Binormal> { 0 1 -1.49012e-008 }
+      }
+      <Normal> { -1 0 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 123 {
+      5 1.19209e-006 -45
+      <UV> {
+        2.375 0.291667
+        <Tangent> { 0 -3.83044e-009 -1 }
+        <Binormal> { -1 -3.83044e-009 0 }
+      }
+      <Normal> { -3.83044e-009 1 -3.83044e-009 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 124 {
+      5 10 -45
+      <UV> {
+        1.5 0.166667
+        <Tangent> { 0 0 -1 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { -1 0 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 125 {
+      5 10 -45
+      <UV> {
+        1.5 0.166667
+        <Tangent> { 0 0 -1 }
+        <Binormal> { 0.707107 0.707107 0 }
+      }
+      <Normal> { -0.707107 0.707107 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 126 {
+      5 10 -5
+      <UV> {
+        -0.5 0.166667
+        <Tangent> { 0 0 -1 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { -1 0 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 127 {
+      5 10 -5
+      <UV> {
+        -0.5 0.166667
+        <Tangent> { 0 0 -1 }
+        <Binormal> { 0.707107 0.707107 0 }
+      }
+      <Normal> { -0.707107 0.707107 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 128 {
+      5 10 -5
+      <UV> {
+        1.5 0.166667
+        <Tangent> { -1 0 0 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0 0 1 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 129 {
+      5 10 -5
+      <UV> {
+        1.5 0.166667
+        <Tangent> { -1 0 0 }
+        <Binormal> { 0 0.707107 -0.707107 }
+      }
+      <Normal> { 0 0.707107 0.707107 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 130 {
+      25 30 -25
+      <UV> {
+        0.5 1.5
+        <Tangent> { 0 0 -1 }
+        <Binormal> { 0.707107 0.707107 0 }
+      }
+      <Normal> { -0.707107 0.707107 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 131 {
+      25 30 -25
+      <UV> {
+        0.5 1.5
+        <Tangent> { -1 0 0 }
+        <Binormal> { 0 0.707107 -0.707107 }
+      }
+      <Normal> { 0 0.707107 0.707107 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 132 {
+      45 1.19209e-006 -5
+      <UV> {
+        -0.5 -0.5
+        <Tangent> { -1 1.49012e-008 0 }
+        <Binormal> { 1.49012e-008 1 0 }
+      }
+      <Normal> { 0 0 1 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 133 {
+      45 1.19209e-006 -5
+      <UV> {
+        0.708333 -1.375
+        <Tangent> { 0 3.91309e-009 -1 }
+        <Binormal> { -1 3.91309e-009 0 }
+      }
+      <Normal> { 3.91309e-009 1 3.91309e-009 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 134 {
+      45 10 -5
+      <UV> {
+        -0.5 0.166667
+        <Tangent> { -1 0 0 }
+        <Binormal> { 0 1 0 }
+      }
+      <Normal> { 0 0 1 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 135 {
+      45 10 -5
+      <UV> {
+        -0.5 0.166667
+        <Tangent> { -1 0 0 }
+        <Binormal> { 0 0.707107 -0.707107 }
+      }
+      <Normal> { 0 0.707107 0.707107 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 136 {
+      60 50 -60
+      <UV> {
+        3 -2
+        <Tangent> { -6.29762e-008 0 -1 }
+        <Binormal> { -1 -2.44826e-008 6.29762e-008 }
+      }
+      <Normal> { 2.44826e-008 -1 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+    <Vertex> 137 {
+      60 50 60
+      <UV> {
+        -2 -2
+        <Tangent> { 0 0 -1 }
+        <Binormal> { -1 -4.89652e-008 0 }
+      }
+      <Normal> { 4.89652e-008 -1 0 }
+      <RGBA> { 1 1 1 1 }
+    }
+  }
+  <Polygon> {
+    <Normal> { 0 0.707107 -0.707107 }
+    <TRef> { phong2SG }
+    <TRef> { phong2SG.tref1 }
+    <VertexRef> { 75 76 83 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { -0.707107 0.707107 0 }
+    <TRef> { phong2SG }
+    <TRef> { phong2SG.tref1 }
+    <VertexRef> { 127 130 125 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { 0 0.707107 0.707107 }
+    <TRef> { phong2SG }
+    <TRef> { phong2SG.tref1 }
+    <VertexRef> { 135 131 129 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { 0.707107 0.707107 0 }
+    <TRef> { phong2SG }
+    <TRef> { phong2SG.tref1 }
+    <VertexRef> { 84 77 86 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { 0 0 -1 }
+    <TRef> { phong2SG }
+    <TRef> { phong2SG.tref1 }
+    <VertexRef> { 78 73 74 82 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { -1 0 0 }
+    <TRef> { phong2SG }
+    <TRef> { phong2SG.tref1 }
+    <VertexRef> { 122 120 126 124 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { 0 0 1 }
+    <TRef> { phong2SG }
+    <TRef> { phong2SG.tref1 }
+    <VertexRef> { 121 132 134 128 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { 1 0 0 }
+    <TRef> { phong2SG }
+    <TRef> { phong2SG.tref1 }
+    <VertexRef> { 81 80 85 87 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { -1 0 0 }
+    <TRef> { phong1SG }
+    <TRef> { phong1SG.tref2 }
+    <VertexRef> { 91 96 94 88 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { 4.89652e-008 -1 0 }
+    <TRef> { phong1SG }
+    <TRef> { phong1SG.tref2 }
+    <VertexRef> {
+      49 55 61 67 70 65 116 136 137 99 106 38 44
+      <Ref> { polySurfaceShape2.verts }
+    }
+  }
+  <Polygon> {
+    <Normal> { 0 -1 0 }
+    <TRef> { phong1SG }
+    <TRef> { phong1SG.tref2 }
+    <VertexRef> {
+      99 98 136 116 53 47 41 36 31 24 18 14 20 26 106
+      <Ref> { polySurfaceShape2.verts }
+    }
+  }
+  <Polygon> {
+    <Normal> { 1 0 0 }
+    <TRef> { phong1SG }
+    <TRef> { phong1SG.tref2 }
+    <VertexRef> { 9 5 2 7 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { 3.91309e-009 1 3.91309e-009 }
+    <TRef> { phong1SG }
+    <TRef> { phong1SG.tref2 }
+    <VertexRef> {
+      93 90 79 133 72 57 117 119 118 115 114 112 110 108 29 4
+      <Ref> { polySurfaceShape2.verts }
+    }
+  }
+  <Polygon> {
+    <Normal> { -3.83044e-009 1 -3.83044e-009 }
+    <TRef> { phong1SG }
+    <TRef> { phong1SG.tref2 }
+    <VertexRef> {
+      123 79 90 0 4 29 104 102 100 101 103 105 107 109 111 113 57 72
+      <Ref> { polySurfaceShape2.verts }
+    }
+  }
+  <Polygon> {
+    <Normal> { 0 0 1 }
+    <TRef> { phong1SG }
+    <TRef> { phong1SG.tref2 }
+    <VertexRef> { 89 95 6 1 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { 0 0 -1 }
+    <TRef> { phong1SG }
+    <TRef> { phong1SG.tref2 }
+    <VertexRef> { 3 8 97 92 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { -0.987688 0 0.156435 }
+    <TRef> { phong3SG }
+    <TRef> { phong3SG.tref3 }
+    <VertexRef> { 10 16 19 12 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { -0.987688 0 -0.156435 }
+    <TRef> { phong3SG }
+    <TRef> { phong3SG.tref3 }
+    <VertexRef> { 15 11 13 17 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { -0.891007 0 -0.45399 }
+    <TRef> { phong3SG }
+    <TRef> { phong3SG.tref3 }
+    <VertexRef> { 21 15 17 23 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { -0.707107 0 -0.707107 }
+    <TRef> { phong3SG }
+    <TRef> { phong3SG.tref3 }
+    <VertexRef> { 27 21 23 30 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { -0.453991 0 -0.891006 }
+    <TRef> { phong3SG }
+    <TRef> { phong3SG.tref3 }
+    <VertexRef> { 33 27 30 35 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { -0.156433 0 -0.987689 }
+    <TRef> { phong3SG }
+    <TRef> { phong3SG.tref3 }
+    <VertexRef> { 39 33 35 42 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { 0.156434 0 -0.987688 }
+    <TRef> { phong3SG }
+    <TRef> { phong3SG.tref3 }
+    <VertexRef> { 45 39 42 48 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { 0.453991 0 -0.891007 }
+    <TRef> { phong3SG }
+    <TRef> { phong3SG.tref3 }
+    <VertexRef> { 51 45 48 54 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { 0.707107 0 -0.707107 }
+    <TRef> { phong3SG }
+    <TRef> { phong3SG.tref3 }
+    <VertexRef> { 58 51 54 60 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { 0.891007 0 -0.453991 }
+    <TRef> { phong3SG }
+    <TRef> { phong3SG.tref3 }
+    <VertexRef> { 63 58 60 66 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { 0.987688 0 -0.156434 }
+    <TRef> { phong3SG }
+    <TRef> { phong3SG.tref3 }
+    <VertexRef> { 69 63 66 71 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { 0.987688 0 0.156434 }
+    <TRef> { phong3SG }
+    <TRef> { phong3SG.tref3 }
+    <VertexRef> { 64 69 71 68 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { 0.891007 0 0.453991 }
+    <TRef> { phong3SG }
+    <TRef> { phong3SG.tref3 }
+    <VertexRef> { 59 64 68 62 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { 0.707107 0 0.707106 }
+    <TRef> { phong3SG }
+    <TRef> { phong3SG.tref3 }
+    <VertexRef> { 52 59 62 56 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { 0.45399 0 0.891007 }
+    <TRef> { phong3SG }
+    <TRef> { phong3SG.tref3 }
+    <VertexRef> { 46 52 56 50 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { 0.156434 0 0.987688 }
+    <TRef> { phong3SG }
+    <TRef> { phong3SG.tref3 }
+    <VertexRef> { 40 46 50 43 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { -0.156434 0 0.987688 }
+    <TRef> { phong3SG }
+    <TRef> { phong3SG.tref3 }
+    <VertexRef> { 34 40 43 37 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { -0.45399 0 0.891007 }
+    <TRef> { phong3SG }
+    <TRef> { phong3SG.tref3 }
+    <VertexRef> { 28 34 37 32 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { -0.707107 0 0.707107 }
+    <TRef> { phong3SG }
+    <TRef> { phong3SG.tref3 }
+    <VertexRef> { 22 28 32 25 <Ref> { polySurfaceShape2.verts } }
+  }
+  <Polygon> {
+    <Normal> { -0.891007 0 0.45399 }
+    <TRef> { phong3SG }
+    <TRef> { phong3SG.tref3 }
+    <VertexRef> { 16 22 25 19 <Ref> { polySurfaceShape2.verts } }
+  }
+}

BIN
samples/bump-mapping/models/abstractroom.mb


BIN
samples/bump-mapping/models/brick-c.jpg


BIN
samples/bump-mapping/models/brick-n.jpg


BIN
samples/bump-mapping/models/fieldstone-c.jpg


BIN
samples/bump-mapping/models/fieldstone-n.jpg


+ 497 - 0
samples/bump-mapping/models/icosphere.egg

@@ -0,0 +1,497 @@
+<CoordinateSystem> { Z-Up }
+
+<Comment> {
+  "egg-trans -F icosphere.egg -o icosphere.egg"
+}
+<Group> Icosphere {
+  <VertexPool> Icosphere {
+    <Vertex> 0 {
+      0 0 -1
+      <Normal> { 0 0 -1 }
+    }
+    <Vertex> 1 {
+      0.425323 -0.309011 -0.850654
+      <Normal> { 0.425306 -0.309 -0.850642 }
+    }
+    <Vertex> 2 {
+      -0.162456 -0.499995 -0.850654
+      <Normal> { -0.16245 -0.499985 -0.850642 }
+    }
+    <Vertex> 3 {
+      0.723607 -0.525725 -0.44722
+      <Normal> { 0.723594 -0.525712 -0.447188 }
+    }
+    <Vertex> 4 {
+      0.850648 0 -0.525736
+      <Normal> { 0.850642 0 -0.525712 }
+    }
+    <Vertex> 5 {
+      -0.52573 0 -0.850652
+      <Normal> { -0.525712 0 -0.850642 }
+    }
+    <Vertex> 6 {
+      -0.162456 0.499995 -0.850654
+      <Normal> { -0.16245 0.499985 -0.850642 }
+    }
+    <Vertex> 7 {
+      0.425323 0.309011 -0.850654
+      <Normal> { 0.425306 0.309 -0.850642 }
+    }
+    <Vertex> 8 {
+      0.951058 -0.309013 0
+      <Normal> { 0.951048 -0.309 0 }
+    }
+    <Vertex> 9 {
+      -0.276388 -0.850649 -0.44722
+      <Normal> { -0.276376 -0.850642 -0.447218 }
+    }
+    <Vertex> 10 {
+      0.262869 -0.809012 -0.525738
+      <Normal> { 0.262856 -0.808985 -0.525712 }
+    }
+    <Vertex> 11 {
+      0 -1 0
+      <Normal> { 0 -1 0 }
+    }
+    <Vertex> 12 {
+      -0.894426 0 -0.447216
+      <Normal> { -0.894406 0 -0.447188 }
+    }
+    <Vertex> 13 {
+      -0.688189 -0.499997 -0.525736
+      <Normal> { -0.688162 -0.499985 -0.525712 }
+    }
+    <Vertex> 14 {
+      -0.951058 -0.309013 0
+      <Normal> { -0.951048 -0.309 0 }
+    }
+    <Vertex> 15 {
+      -0.276388 0.850649 -0.44722
+      <Normal> { -0.276376 0.850642 -0.447218 }
+    }
+    <Vertex> 16 {
+      -0.688189 0.499997 -0.525736
+      <Normal> { -0.688162 0.499985 -0.525712 }
+    }
+    <Vertex> 17 {
+      -0.587786 0.809017 0
+      <Normal> { -0.587756 0.809015 0 }
+    }
+    <Vertex> 18 {
+      0.723607 0.525725 -0.44722
+      <Normal> { 0.723594 0.525712 -0.447188 }
+    }
+    <Vertex> 19 {
+      0.262869 0.809012 -0.525738
+      <Normal> { 0.262856 0.808985 -0.525712 }
+    }
+    <Vertex> 20 {
+      0.587786 0.809017 0
+      <Normal> { 0.587756 0.809015 0 }
+    }
+    <Vertex> 21 {
+      0.587786 -0.809017 0
+      <Normal> { 0.587756 -0.809015 0 }
+    }
+    <Vertex> 22 {
+      -0.587786 -0.809017 0
+      <Normal> { -0.587756 -0.809015 0 }
+    }
+    <Vertex> 23 {
+      -0.951058 0.309013 0
+      <Normal> { -0.951048 0.309 0 }
+    }
+    <Vertex> 24 {
+      0 1 0
+      <Normal> { 0 1 0 }
+    }
+    <Vertex> 25 {
+      0.951058 0.309013 0
+      <Normal> { 0.951048 0.309 0 }
+    }
+    <Vertex> 26 {
+      0.276388 -0.850649 0.44722
+      <Normal> { 0.276376 -0.850642 0.447218 }
+    }
+    <Vertex> 27 {
+      0.688189 -0.499997 0.525736
+      <Normal> { 0.688162 -0.499985 0.525712 }
+    }
+    <Vertex> 28 {
+      0.162456 -0.499995 0.850654
+      <Normal> { 0.16245 -0.499985 0.850642 }
+    }
+    <Vertex> 29 {
+      -0.723607 -0.525725 0.44722
+      <Normal> { -0.723594 -0.525712 0.447188 }
+    }
+    <Vertex> 30 {
+      -0.262869 -0.809012 0.525738
+      <Normal> { -0.262856 -0.808985 0.525712 }
+    }
+    <Vertex> 31 {
+      -0.425323 -0.309011 0.850654
+      <Normal> { -0.425306 -0.309 0.850642 }
+    }
+    <Vertex> 32 {
+      -0.723607 0.525725 0.44722
+      <Normal> { -0.723594 0.525712 0.447188 }
+    }
+    <Vertex> 33 {
+      -0.850648 0 0.525736
+      <Normal> { -0.850642 0 0.525712 }
+    }
+    <Vertex> 34 {
+      -0.425323 0.309011 0.850654
+      <Normal> { -0.425306 0.309 0.850642 }
+    }
+    <Vertex> 35 {
+      0.276388 0.850649 0.44722
+      <Normal> { 0.276376 0.850642 0.447218 }
+    }
+    <Vertex> 36 {
+      -0.262869 0.809012 0.525738
+      <Normal> { -0.262856 0.808985 0.525712 }
+    }
+    <Vertex> 37 {
+      0.162456 0.499995 0.850654
+      <Normal> { 0.16245 0.499985 0.850642 }
+    }
+    <Vertex> 38 {
+      0.894426 0 0.447216
+      <Normal> { 0.894406 0 0.447188 }
+    }
+    <Vertex> 39 {
+      0.688189 0.499997 0.525736
+      <Normal> { 0.688162 0.499985 0.525712 }
+    }
+    <Vertex> 40 {
+      0.52573 0 0.850652
+      <Normal> { 0.525712 0 0.850642 }
+    }
+    <Vertex> 41 {
+      0 0 1
+      <Normal> { 0 0 1 }
+    }
+  }
+  <Polygon> {
+    <Normal> { 0.102381 -0.31509 -0.943523 }
+    <VertexRef> { 0 1 2 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.700224 -0.268032 -0.661699 }
+    <VertexRef> { 3 1 4 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.268034 -0.194736 -0.943523 }
+    <VertexRef> { 0 2 5 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.268034 0.194737 -0.943523 }
+    <VertexRef> { 0 5 6 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.102381 0.31509 -0.943523 }
+    <VertexRef> { 0 6 7 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.904989 -0.268032 -0.330385 }
+    <VertexRef> { 3 4 8 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.024747 -0.943521 -0.330386 }
+    <VertexRef> { 9 10 11 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.889697 -0.315095 -0.330385 }
+    <VertexRef> { 12 13 14 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.574602 0.748784 -0.330388 }
+    <VertexRef> { 15 16 17 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.534576 0.777865 -0.330387 }
+    <VertexRef> { 18 19 20 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.802609 -0.583126 -0.125627 }
+    <VertexRef> { 3 8 21 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.306569 -0.943522 -0.125629 }
+    <VertexRef> { 9 11 22 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.992077 0 -0.125628 }
+    <VertexRef> { 12 14 23 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.306569 0.943522 -0.125629 }
+    <VertexRef> { 15 17 24 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.802609 0.583126 -0.125627 }
+    <VertexRef> { 18 20 25 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.408946 -0.628425 0.661698 }
+    <VertexRef> { 26 27 28 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.4713 -0.583122 0.661699 }
+    <VertexRef> { 29 30 31 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.700224 0.268032 0.661699 }
+    <VertexRef> { 32 33 34 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.03853 0.748779 0.661699 }
+    <VertexRef> { 35 36 37 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.724042 0.194736 0.661695 }
+    <VertexRef> { 38 39 40 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.268034 0.194737 0.943523 }
+    <VertexRef> { 40 37 41 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.491119 0.356821 0.794657 }
+    <VertexRef> { 40 39 37 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.408946 0.628425 0.661699 }
+    <VertexRef> { 39 35 37 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.102381 0.31509 0.943523 }
+    <VertexRef> { 37 34 41 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.187594 0.577345 0.794658 }
+    <VertexRef> { 37 36 34 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.4713 0.583122 0.661699 }
+    <VertexRef> { 36 32 34 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.331305 0 0.943524 }
+    <VertexRef> { 34 31 41 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.60706 0 0.794656 }
+    <VertexRef> { 34 33 31 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.700224 -0.268032 0.661699 }
+    <VertexRef> { 33 29 31 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.102381 -0.31509 0.943523 }
+    <VertexRef> { 31 28 41 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.187594 -0.577345 0.794658 }
+    <VertexRef> { 31 30 28 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.03853 -0.748779 0.661699 }
+    <VertexRef> { 30 26 28 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.268034 -0.194737 0.943523 }
+    <VertexRef> { 28 40 41 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.491119 -0.356821 0.794657 }
+    <VertexRef> { 28 27 40 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.724042 -0.194736 0.661695 }
+    <VertexRef> { 27 38 40 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.889697 0.315095 0.330385 }
+    <VertexRef> { 25 39 38 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.794656 0.577348 0.187595 }
+    <VertexRef> { 25 20 39 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.574602 0.748784 0.330388 }
+    <VertexRef> { 20 35 39 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.024747 0.943521 0.330386 }
+    <VertexRef> { 24 36 35 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.303531 0.934171 0.187597 }
+    <VertexRef> { 24 17 36 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.534576 0.777865 0.330387 }
+    <VertexRef> { 17 32 36 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.904989 0.268032 0.330385 }
+    <VertexRef> { 23 33 32 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.982246 0 0.187599 }
+    <VertexRef> { 23 14 33 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.904989 -0.268031 0.330385 }
+    <VertexRef> { 14 29 33 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.534576 -0.777865 0.330387 }
+    <VertexRef> { 22 30 29 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.303531 -0.934171 0.187597 }
+    <VertexRef> { 22 11 30 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.024747 -0.943521 0.330386 }
+    <VertexRef> { 11 26 30 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.574602 -0.748784 0.330388 }
+    <VertexRef> { 21 27 26 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.794656 -0.577348 0.187595 }
+    <VertexRef> { 21 8 27 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.889697 -0.315095 0.330385 }
+    <VertexRef> { 8 38 27 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.306569 0.943522 0.125629 }
+    <VertexRef> { 20 24 35 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.303531 0.934171 -0.187597 }
+    <VertexRef> { 20 19 24 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.024747 0.943521 -0.330386 }
+    <VertexRef> { 19 15 24 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.802609 0.583126 0.125627 }
+    <VertexRef> { 17 23 32 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.794656 0.577348 -0.187595 }
+    <VertexRef> { 17 16 23 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.889697 0.315095 -0.330385 }
+    <VertexRef> { 16 12 23 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.802609 -0.583126 0.125627 }
+    <VertexRef> { 14 22 29 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.794656 -0.577348 -0.187595 }
+    <VertexRef> { 14 13 22 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.574602 -0.748784 -0.330388 }
+    <VertexRef> { 13 9 22 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.306569 -0.943522 0.125629 }
+    <VertexRef> { 11 21 26 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.303531 -0.934171 -0.187597 }
+    <VertexRef> { 11 10 21 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.534576 -0.777865 -0.330387 }
+    <VertexRef> { 10 3 21 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.992077 0 0.125628 }
+    <VertexRef> { 8 25 38 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.982246 0 -0.187599 }
+    <VertexRef> { 8 4 25 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.904989 0.268031 -0.330385 }
+    <VertexRef> { 4 18 25 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.4713 0.583122 -0.661699 }
+    <VertexRef> { 7 19 18 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.187594 0.577345 -0.794658 }
+    <VertexRef> { 7 6 19 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.03853 0.748779 -0.661699 }
+    <VertexRef> { 6 15 19 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.408946 0.628425 -0.661698 }
+    <VertexRef> { 6 16 15 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.491119 0.356821 -0.794657 }
+    <VertexRef> { 6 5 16 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.724042 0.194736 -0.661695 }
+    <VertexRef> { 5 12 16 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.724042 -0.194736 -0.661695 }
+    <VertexRef> { 5 13 12 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.491119 -0.356821 -0.794657 }
+    <VertexRef> { 5 2 13 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.408946 -0.628425 -0.661698 }
+    <VertexRef> { 2 9 13 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.700224 0.268032 -0.661699 }
+    <VertexRef> { 4 7 18 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.60706 0 -0.794656 }
+    <VertexRef> { 4 1 7 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.331305 0 -0.943524 }
+    <VertexRef> { 1 0 7 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { -0.03853 -0.748779 -0.661699 }
+    <VertexRef> { 2 10 9 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.187594 -0.577345 -0.794658 }
+    <VertexRef> { 2 1 10 <Ref> { Icosphere } }
+  }
+  <Polygon> {
+    <Normal> { 0.4713 -0.583122 -0.661699 }
+    <VertexRef> { 1 3 10 <Ref> { Icosphere } }
+  }
+}

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