Browse Source

Merge branch 'master' of ssh://github.com/kestred/panda3d into cmake

rdb 12 years ago
parent
commit
abec123074
46 changed files with 734 additions and 398 deletions
  1. 5 0
      direct/src/actor/Actor.py
  2. 0 3
      dtool/LocalSetup.pp
  3. 1 0
      dtool/src/cppparser/cppFunctionType.h
  4. 9 5
      dtool/src/cppparser/cppInstanceIdentifier.cxx
  5. 55 61
      dtool/src/interrogate/interfaceMaker.cxx
  6. 4 3
      dtool/src/interrogate/interfaceMaker.h
  7. 1 1
      dtool/src/interrogate/interfaceMakerPythonObj.cxx
  8. 92 6
      dtool/src/interrogate/typeManager.cxx
  9. 4 1
      dtool/src/interrogate/typeManager.h
  10. 47 5
      panda/src/bullet/bulletAllHitsRayResult.cxx
  11. 10 0
      panda/src/bullet/bulletAllHitsRayResult.h
  12. 42 5
      panda/src/bullet/bulletClosestHitRayResult.cxx
  13. 7 0
      panda/src/bullet/bulletClosestHitRayResult.h
  14. 9 4
      panda/src/bullet/bulletWorld.cxx
  15. 2 2
      panda/src/bullet/bulletWorld.h
  16. 9 0
      panda/src/bullet/bullet_utils.cxx
  17. 1 0
      panda/src/bullet/bullet_utils.h
  18. 50 13
      panda/src/display/displayRegion.I
  19. 20 11
      panda/src/display/displayRegion.cxx
  20. 8 4
      panda/src/display/displayRegion.h
  21. 5 3
      panda/src/display/graphicsOutput.I
  22. 47 72
      panda/src/display/graphicsOutput.cxx
  23. 4 5
      panda/src/display/graphicsOutput.h
  24. 1 1
      panda/src/display/graphicsStateGuardian.cxx
  25. 6 6
      panda/src/display/stereoDisplayRegion.cxx
  26. 1 1
      panda/src/display/stereoDisplayRegion.h
  27. 3 3
      panda/src/dxgsg8/wdxGraphicsBuffer8.cxx
  28. 1 1
      panda/src/dxgsg8/wdxGraphicsBuffer8.h
  29. 1 1
      panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx
  30. 3 3
      panda/src/dxgsg9/wdxGraphicsBuffer9.cxx
  31. 1 1
      panda/src/dxgsg9/wdxGraphicsBuffer9.h
  32. 70 80
      panda/src/glstuff/glGraphicsBuffer_src.cxx
  33. 2 3
      panda/src/glstuff/glGraphicsBuffer_src.h
  34. 19 11
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  35. 49 19
      panda/src/gobj/texture.I
  36. 58 54
      panda/src/gobj/texture.cxx
  37. 3 0
      panda/src/gobj/texture.h
  38. 36 0
      panda/src/gobj/textureContext.I
  39. 4 0
      panda/src/gobj/textureContext.h
  40. 11 1
      panda/src/pgraph/renderState.I
  41. 11 0
      panda/src/putil/updateSeq.I
  42. 2 0
      panda/src/putil/updateSeq.h
  43. 15 4
      panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx
  44. 3 3
      panda/src/wgldisplay/wglGraphicsBuffer.cxx
  45. 1 1
      panda/src/wgldisplay/wglGraphicsBuffer.h
  46. 1 1
      pandatool/src/maxegg/maxEggLoader.cxx

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

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

+ 0 - 3
dtool/LocalSetup.pp

@@ -602,9 +602,6 @@ $[cdefine HAVE_DINKUM]
 /* Define if we have STL hash_map etc. available  */
 $[cdefine HAVE_STL_HASH]
 
-/* Define if we have a gettimeofday() function. */
-$[cdefine HAVE_GETTIMEOFDAY]
-
 /* Define if gettimeofday() takes only one parameter. */
 $[cdefine GETTIMEOFDAY_ONE_PARAM]
 

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

@@ -35,6 +35,7 @@ public:
     F_destructor        = 0x08,
     F_method_pointer    = 0x10,
     F_unary_op          = 0x20,
+    F_operator          = 0x40,
   };
 
   CPPFunctionType(CPPType *return_type, CPPParameterList *parameters,

+ 9 - 5
dtool/src/cppparser/cppInstanceIdentifier.cxx

@@ -134,12 +134,16 @@ add_func_modifier(CPPParameterList *params, int flags) {
   // is really a unary operator, so set the unary_op flag.  Operators
   // () and [] are never considered unary operators.
   if (_ident != NULL && 
-      _ident->get_simple_name().substr(0, 9) == "operator " &&
-      _ident->get_simple_name() != string("operator ()") &&
-      _ident->get_simple_name() != string("operator []")) {
-    if (params->_parameters.empty()) {
-      flags |= CPPFunctionType::F_unary_op;
+      _ident->get_simple_name().substr(0, 9) == "operator ") {
+
+    if (_ident->get_simple_name() != string("operator ()") &&
+        _ident->get_simple_name() != string("operator []")) {
+      if (params->_parameters.empty()) {
+        flags |= CPPFunctionType::F_unary_op;
+      }
     }
+
+    flags |= CPPFunctionType::F_operator;
   }
 
   _modifiers.push_back(Modifier::func_type(params, flags));

+ 55 - 61
dtool/src/interrogate/interfaceMaker.cxx

@@ -156,22 +156,24 @@ check_protocols() {
   }
 
   // Now are there any make_seq requests within this class?
-  CPPStructType *stype = _itype._cpptype->as_struct_type();
-  if (stype != (CPPStructType *)NULL) {
-    CPPScope *scope = stype->get_scope();
-    if (scope != (CPPScope *)NULL) {
-      CPPScope::Declarations::iterator di;
-      for (di = scope->_declarations.begin(); di != scope->_declarations.end(); ++di) {
-        CPPMakeSeq *cpp_make_seq = (*di)->as_make_seq();
-        if (cpp_make_seq != (CPPMakeSeq *)NULL) {
-          string class_name = _itype.get_scoped_name();
-          string clean_name = InterrogateBuilder::clean_identifier(class_name);
-          string wrapper_name = "MakeSeq_" + clean_name + "_" + cpp_make_seq->_seq_name;
-          MakeSeq *make_seq = new MakeSeq(wrapper_name, cpp_make_seq);
-          _make_seqs.push_back(make_seq);
-
-          // Also add to the interrogate database.
-          builder.get_make_seq(cpp_make_seq, stype);
+  if (_itype._cpptype != NULL) {
+    CPPStructType *stype = _itype._cpptype->as_struct_type();
+    if (stype != (CPPStructType *)NULL) {
+      CPPScope *scope = stype->get_scope();
+      if (scope != (CPPScope *)NULL) {
+        CPPScope::Declarations::iterator di;
+        for (di = scope->_declarations.begin(); di != scope->_declarations.end(); ++di) {
+          CPPMakeSeq *cpp_make_seq = (*di)->as_make_seq();
+          if (cpp_make_seq != (CPPMakeSeq *)NULL) {
+            string class_name = _itype.get_scoped_name();
+            string clean_name = InterrogateBuilder::clean_identifier(class_name);
+            string wrapper_name = "MakeSeq_" + clean_name + "_" + cpp_make_seq->_seq_name;
+            MakeSeq *make_seq = new MakeSeq(wrapper_name, cpp_make_seq);
+            _make_seqs.push_back(make_seq);
+
+            // Also add to the interrogate database.
+            builder.get_make_seq(cpp_make_seq, stype);
+          }
         }
       }
     }
@@ -246,26 +248,20 @@ void InterfaceMaker::
 generate_wrappers() {
   InterrogateDatabase *idb = InterrogateDatabase::get_ptr();
 
-
   // We use a while loop rather than a simple for loop, because we
   // might increase the number of types recursively during the
   // traversal.
   int ti = 0;
-  while (ti < idb->get_num_all_types())
-  {
-        TypeIndex type_index = idb->get_all_type(ti);
-        record_object(type_index);
-
-
-         if(interrogate_type_is_enum(ti))
-         {
-             int enum_count = interrogate_type_number_of_enum_values(ti);
-             for(int xx = 0; xx< enum_count; xx++)
-             {
-//                 printf("   PyModule_AddIntConstant(module,\"%s\",%d)\n",interrogate_type_enum_value_name(ti,xx),interrogate_type_enum_value(ti,xx));
-             }
-         }
+  while (ti < idb->get_num_all_types()) {
+    TypeIndex type_index = idb->get_all_type(ti);
+    record_object(type_index);
 
+    if (interrogate_type_is_enum(ti)) {
+      int enum_count = interrogate_type_number_of_enum_values(ti);
+      for (int xx = 0; xx < enum_count; ++xx) {
+//        printf("   PyModule_AddIntConstant(module,\"%s\",%d)\n",interrogate_type_enum_value_name(ti,xx),interrogate_type_enum_value(ti,xx));
+      }
+    }
 
     ++ti;
 //    printf(" New Type %d\n",ti);
@@ -273,54 +269,43 @@ generate_wrappers() {
 
   int num_global_elements = idb->get_num_global_elements();
   for (int gi = 0; gi < num_global_elements; ++gi) {
-    printf(" Global Type = %d",gi);
+    printf(" Global Type = %d", gi);
     TypeIndex type_index = idb->get_global_element(gi);
     record_object(type_index);
   }
 
   int num_functions = idb->get_num_global_functions();
-  for (int fi = 0; fi < num_functions; fi++) 
-  {
+  for (int fi = 0; fi < num_functions; fi++) {
     FunctionIndex func_index = idb->get_global_function(fi);
     record_function(dummy_type, func_index);
-  }    
-
-
+  }
 
   int num_manifests = idb->get_num_global_manifests();
-  for (int mi = 0; mi < num_manifests; mi++) 
-  {
+  for (int mi = 0; mi < num_manifests; mi++) {
     ManifestIndex manifest_index = idb->get_global_manifest(mi);
     const InterrogateManifest &iman = idb->get_manifest(manifest_index);
-    if (iman.has_getter()) 
-    {
+    if (iman.has_getter()) {
       FunctionIndex func_index = iman.get_getter();
       record_function(dummy_type, func_index);
     }
-    printf(" Manafests %d\n",mi);
-  }    
-
-
+    printf(" Manifests %d\n", mi);
+  }
 
   int num_elements = idb->get_num_global_elements();
-  for (int ei = 0; ei < num_elements; ei++) 
-  {
-    printf(" Element %d\n",ei);
+  for (int ei = 0; ei < num_elements; ei++) {
+    printf(" Element %d\n", ei);
 
     ElementIndex element_index = idb->get_global_element(ei);
     const InterrogateElement &ielement = idb->get_element(element_index);
-    if (ielement.has_getter()) 
-    {
+    if (ielement.has_getter()) {
       FunctionIndex func_index = ielement.get_getter();
       record_function(dummy_type, func_index);
     }
-    if (ielement.has_setter()) 
-    {
+    if (ielement.has_setter()) {
       FunctionIndex func_index = ielement.get_setter();
       record_function(dummy_type, func_index);
     }
   }    
-
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -491,6 +476,19 @@ separate_overloading() {
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::wrap_global_functions
+//       Access: Public, Virtual
+//  Description: This method should be overridden and redefined to
+//               return false for interfaces that don't support
+//               global functions and should therefore will only
+//               accept function remaps that have a class associated.
+////////////////////////////////////////////////////////////////////
+bool InterfaceMaker::
+wrap_global_functions() {
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: InterfaceMaker::get_function_remaps
 //       Access: Public
@@ -625,21 +623,17 @@ record_function(const InterrogateType &itype, FunctionIndex func_index) {
   Function *func = new Function(wrapper_name, itype, ifunc);
   _functions.push_back(func);
 
-
-//  printf(" Function Name = %s\n",ifunc.get_name().c_str());
+//  printf(" Function Name = %s\n", ifunc.get_name().c_str());
 
   // Now get all the valid FunctionRemaps for the function.
-  if (ifunc._instances != (InterrogateFunction::Instances *)NULL) 
-  {
+  if (ifunc._instances != (InterrogateFunction::Instances *)NULL) {
     InterrogateFunction::Instances::const_iterator ii;
-    for (ii = ifunc._instances->begin();ii != ifunc._instances->end();++ii) 
-    {
+    for (ii = ifunc._instances->begin(); ii != ifunc._instances->end(); ++ii) {
       CPPInstance *cppfunc = (*ii).second;
       CPPFunctionType *ftype = cppfunc->_type->as_function_type();
       int max_default_parameters = 0;
       
-      if (separate_overloading()) 
-      {
+      if (separate_overloading()) {
         // Count up the number of default parameters this function might
         // take.
         CPPParameterList *parameters = ftype->_parameters;

+ 4 - 3
dtool/src/interrogate/interfaceMaker.h

@@ -56,14 +56,15 @@ public:
   virtual void write_includes(ostream &out);
   virtual void write_prototypes(ostream &out, ostream *out_h);
   virtual void write_functions(ostream &out);
-  virtual void write_module_support(ostream &out,ostream *out_h,InterrogateModuleDef *moduledefdef) {};
+  virtual void write_module_support(ostream &out, ostream *out_h, InterrogateModuleDef *def) {};
 
-  virtual void write_module(ostream &out, ostream *out_h,InterrogateModuleDef *def);
+  virtual void write_module(ostream &out, ostream *out_h, InterrogateModuleDef *def);
 
   virtual ParameterRemap *remap_parameter(CPPType *struct_type, CPPType *param_type);
 
   virtual bool synthesize_this_parameter();
   virtual bool separate_overloading();
+  virtual bool wrap_global_functions();
 
   void get_function_remaps(vector<FunctionRemap *> &remaps);
 
@@ -146,7 +147,7 @@ public:
   record_function_wrapper(InterrogateFunction &ifunc, 
                           FunctionWrapperIndex wrapper_index);
 
-  virtual Object *  record_object(TypeIndex type_index);
+  virtual Object *record_object(TypeIndex type_index);
 
   void hash_function_signature(FunctionRemap *remap);
   

+ 1 - 1
dtool/src/interrogate/interfaceMakerPythonObj.cxx

@@ -54,7 +54,7 @@ InterfaceMakerPythonObj::
 //               write_functions().
 ////////////////////////////////////////////////////////////////////
 void InterfaceMakerPythonObj::
-write_prototypes(ostream &out,ostream *out_h) {
+write_prototypes(ostream &out, ostream *out_h) {
   Functions::iterator fi;
   for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
     Function *func = (*fi);

+ 92 - 6
dtool/src/interrogate/typeManager.cxx

@@ -807,24 +807,52 @@ is_unsigned_integer(CPPType *type) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: TypeManager::is_unsigned_longlong
+//     Function: TypeManager::is_short
+//       Access: Public, Static
+//  Description: Returns true if the indicated type is the "short"
+//               type, whether signed or unsigned.
+////////////////////////////////////////////////////////////////////
+bool TypeManager::
+is_short(CPPType *type) {
+  switch (type->get_subtype()) {
+  case CPPDeclaration::ST_const:
+    return is_short(type->as_const_type()->_wrapped_around);
+
+  case CPPDeclaration::ST_simple:
+    {
+      CPPSimpleType *simple_type = type->as_simple_type();
+      if (simple_type != (CPPSimpleType *)NULL) {
+        return (simple_type->_type == CPPSimpleType::T_int && 
+                (simple_type->_flags & CPPSimpleType::F_short) != 0);
+      }
+    }
+    break;
+
+  default:
+    break;
+  }
+
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeManager::is_unsigned_short
 //       Access: Public, Static
 //  Description: Returns true if the indicated type is an unsigned
-//               "long long" type or larger, or at least a 64-bit
-//               unsigned integer.
+//               "short" type.
 ////////////////////////////////////////////////////////////////////
 bool TypeManager::
-is_unsigned_longlong(CPPType *type) {
+is_unsigned_short(CPPType *type) {
   switch (type->get_subtype()) {
   case CPPDeclaration::ST_const:
-    return is_unsigned_longlong(type->as_const_type()->_wrapped_around);
+    return is_unsigned_short(type->as_const_type()->_wrapped_around);
 
   case CPPDeclaration::ST_simple:
     {
       CPPSimpleType *simple_type = type->as_simple_type();
       if (simple_type != (CPPSimpleType *)NULL) {
         return (simple_type->_type == CPPSimpleType::T_int && 
-                (simple_type->_flags & (CPPSimpleType::F_longlong | CPPSimpleType::F_unsigned)) == (CPPSimpleType::F_longlong | CPPSimpleType::F_unsigned));
+                (simple_type->_flags & (CPPSimpleType::F_short | CPPSimpleType::F_unsigned)) == (CPPSimpleType::F_short | CPPSimpleType::F_unsigned));
       }
     }
     break;
@@ -866,6 +894,64 @@ is_longlong(CPPType *type) {
   return false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TypeManager::is_unsigned_longlong
+//       Access: Public, Static
+//  Description: Returns true if the indicated type is an unsigned
+//               "long long" type or larger, or at least a 64-bit
+//               unsigned integer.
+////////////////////////////////////////////////////////////////////
+bool TypeManager::
+is_unsigned_longlong(CPPType *type) {
+  switch (type->get_subtype()) {
+  case CPPDeclaration::ST_const:
+    return is_unsigned_longlong(type->as_const_type()->_wrapped_around);
+
+  case CPPDeclaration::ST_simple:
+    {
+      CPPSimpleType *simple_type = type->as_simple_type();
+      if (simple_type != (CPPSimpleType *)NULL) {
+        return (simple_type->_type == CPPSimpleType::T_int && 
+                (simple_type->_flags & (CPPSimpleType::F_longlong | CPPSimpleType::F_unsigned)) == (CPPSimpleType::F_longlong | CPPSimpleType::F_unsigned));
+      }
+    }
+    break;
+
+  default:
+    break;
+  }
+
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeManager::is_double
+//       Access: Public, Static
+//  Description: Returns true if the indicated type is the "double"
+//               type.
+////////////////////////////////////////////////////////////////////
+bool TypeManager::
+is_double(CPPType *type) {
+  switch (type->get_subtype()) {
+  case CPPDeclaration::ST_const:
+    return is_float(type->as_const_type()->_wrapped_around);
+
+  case CPPDeclaration::ST_simple:
+    {
+      CPPSimpleType *simple_type = type->as_simple_type();
+      if (simple_type != (CPPSimpleType *)NULL) {
+        return (simple_type->_type == CPPSimpleType::T_double);
+      }
+    }
+    break;
+
+  default:
+    break;
+  }
+
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TypeManager::is_float
 //       Access: Public, Static

+ 4 - 1
dtool/src/interrogate/typeManager.h

@@ -80,8 +80,11 @@ public:
   static bool is_bool(CPPType *type);
   static bool is_integer(CPPType *type);
   static bool is_unsigned_integer(CPPType *type);
-  static bool is_unsigned_longlong(CPPType *type);
+  static bool is_short(CPPType *type);
+  static bool is_unsigned_short(CPPType *type);
   static bool is_longlong(CPPType *type);
+  static bool is_unsigned_longlong(CPPType *type);
+  static bool is_double(CPPType *type);
   static bool is_float(CPPType *type);
   static bool is_void(CPPType *type);
   static bool is_reference_count(CPPType *type);

+ 47 - 5
panda/src/bullet/bulletAllHitsRayResult.cxx

@@ -33,11 +33,6 @@ BulletAllHitsRayResult(const btVector3 &from_pos, const btVector3 &to_pos, const
 bool BulletAllHitsRayResult::
 needsCollision(btBroadphaseProxy* proxy0) const {
 
-  // Original implementation:
-  //bool collides = (proxy0->m_collisionFilterGroup & m_collisionFilterMask) != 0;
-  //collides = collides && (m_collisionFilterGroup & proxy0->m_collisionFilterMask);
-  //return collides;
-
   btCollisionObject *obj0 = (btCollisionObject *) proxy0->m_clientObject;
   PandaNode *node0 = (PandaNode *) obj0->getUserPointer();
   CollideMask mask0 = node0->get_into_collide_mask();
@@ -45,6 +40,28 @@ needsCollision(btBroadphaseProxy* proxy0) const {
   return (_mask & mask0) != 0;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BulletAllHitsRayResult::addSingleResult
+//       Access: Protected
+//  Description: Override default implementation.
+////////////////////////////////////////////////////////////////////
+btScalar BulletAllHitsRayResult::
+addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace) {
+
+  // Store part/index information
+  if (rayResult.m_localShapeInfo) {
+    _shapePart.push_back(rayResult.m_localShapeInfo->m_shapePart);
+    _triangleIndex.push_back(rayResult.m_localShapeInfo->m_triangleIndex);
+  }
+  else {
+    _shapePart.push_back(-1);
+    _triangleIndex.push_back(-1);
+  }
+
+  // Call the default implementation
+  return btCollisionWorld::AllHitsRayResultCallback::addSingleResult(rayResult, normalInWorldSpace);
+};
+
 ////////////////////////////////////////////////////////////////////
 //     Function: BulletAllHitsRayResult::get_from_pos
 //       Access: Published
@@ -117,6 +134,9 @@ get_hit(int idx) const {
   hit._pos = m_hitPointWorld[idx];
   hit._fraction = m_hitFractions[idx];
 
+  hit._shapePart = _shapePart[idx];
+  hit._triangleIndex = _triangleIndex[idx];
+
   return hit;
 }
 
@@ -164,3 +184,25 @@ get_hit_normal() const {
   return btVector3_to_LVector3(_normal);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BulletRayHit::get_shape_part
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+int BulletRayHit::
+get_shape_part() const {
+
+  return _shapePart;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletRayHit::get_triangle_index
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+int BulletRayHit::
+get_triangle_index() const {
+
+  return _triangleIndex;
+}
+

+ 10 - 0
panda/src/bullet/bulletAllHitsRayResult.h

@@ -38,12 +38,18 @@ PUBLISHED:
   LVector3 get_hit_normal() const;
   PN_stdfloat get_hit_fraction() const;
 
+  int get_shape_part() const;
+  int get_triangle_index() const;
+
 private:
   const btCollisionObject *_object; 
   btVector3 _normal;
   btVector3 _pos;
   btScalar _fraction;
 
+  int _shapePart;
+  int _triangleIndex;
+
   friend struct BulletAllHitsRayResult;
 };
 
@@ -68,12 +74,16 @@ PUBLISHED:
 
 public:
   virtual bool needsCollision(btBroadphaseProxy* proxy0) const;
+  virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace);
 
 private:
   BulletAllHitsRayResult(const btVector3 &from_pos, const btVector3 &to_pos, const CollideMask &mask);
 
   CollideMask _mask;
 
+  btAlignedObjectArray<int> _shapePart;
+  btAlignedObjectArray<int> _triangleIndex;
+
   friend class BulletWorld;
 };
 

+ 42 - 5
panda/src/bullet/bulletClosestHitRayResult.cxx

@@ -23,6 +23,8 @@ BulletClosestHitRayResult::
 BulletClosestHitRayResult(const btVector3 &from_pos, const btVector3 &to_pos, const CollideMask &mask) 
  : btCollisionWorld::ClosestRayResultCallback(from_pos, to_pos), _mask(mask) {
 
+  _shapePart = -1;
+  _triangleIndex = -1;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -33,11 +35,6 @@ BulletClosestHitRayResult(const btVector3 &from_pos, const btVector3 &to_pos, co
 bool BulletClosestHitRayResult::
 needsCollision(btBroadphaseProxy* proxy0) const {
 
-  // Original implementation:
-  //bool collides = (proxy0->m_collisionFilterGroup & m_collisionFilterMask) != 0;
-  //collides = collides && (m_collisionFilterGroup & proxy0->m_collisionFilterMask);
-  //return collides;
-
   btCollisionObject *obj0 = (btCollisionObject *) proxy0->m_clientObject;
   PandaNode *node0 = (PandaNode *) obj0->getUserPointer();
   CollideMask mask0 = node0->get_into_collide_mask();
@@ -45,6 +42,24 @@ needsCollision(btBroadphaseProxy* proxy0) const {
   return (_mask & mask0) != 0;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BulletAllHitsRayResult::addSingleResult
+//       Access: Protected
+//  Description: Override default implementation.
+////////////////////////////////////////////////////////////////////
+btScalar BulletClosestHitRayResult::
+addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace) {
+
+  // Store part/index information
+  if (rayResult.m_localShapeInfo) {
+    _shapePart = rayResult.m_localShapeInfo->m_shapePart;
+    _triangleIndex = rayResult.m_localShapeInfo->m_triangleIndex;
+  }
+
+  // Call the default implementation
+  return btCollisionWorld::ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace);
+};
+
 ////////////////////////////////////////////////////////////////////
 //     Function: BulletClosestHitRayResult::has_hit
 //       Access: Published
@@ -123,3 +138,25 @@ get_to_pos() const {
   return btVector3_to_LPoint3(m_rayToWorld);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BulletClosestHitRayResult::get_shape_part
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+int BulletClosestHitRayResult::
+get_shape_part() const {
+
+  return _shapePart;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletClosestHitRayResult::get_triangle_index
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+int BulletClosestHitRayResult::
+get_triangle_index() const {
+
+  return _triangleIndex;
+}
+

+ 7 - 0
panda/src/bullet/bulletClosestHitRayResult.h

@@ -43,14 +43,21 @@ PUBLISHED:
   LVector3 get_hit_normal() const;
   PN_stdfloat get_hit_fraction() const;
 
+  int get_shape_part() const;
+  int get_triangle_index() const;
+
 public:
   virtual bool needsCollision(btBroadphaseProxy* proxy0) const;
+  virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace);
 
 private:
   BulletClosestHitRayResult(const btVector3 &from_pos, const btVector3 &to_pos, const CollideMask &mask);
 
   CollideMask _mask;
 
+  int _shapePart;
+  int _triangleIndex;
+
   friend class BulletWorld;
 };
 

+ 9 - 4
panda/src/bullet/bulletWorld.cxx

@@ -852,10 +852,11 @@ clear_contact_added_callback() {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void BulletWorld::
-set_tick_callback(CallbackObject *obj) {
+set_tick_callback(CallbackObject *obj, bool is_pretick) {
 
   nassertv(obj != NULL);
   _tick_callback_obj = obj;
+  _world->setInternalTickCallback(&BulletWorld::tick_callback, this, is_pretick);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -867,6 +868,7 @@ void BulletWorld::
 clear_tick_callback() {
 
   _tick_callback_obj = NULL;
+  _world->setInternalTickCallback(NULL);
 }
 
 ///////////////////////////////////////////////////////////////////
@@ -880,8 +882,11 @@ tick_callback(btDynamicsWorld *world, btScalar timestep) {
   nassertv(world->getWorldUserInfo());
 
   BulletWorld *w = static_cast<BulletWorld *>(world->getWorldUserInfo());
-  BulletTickCallbackData cbdata(timestep);
-  w->_tick_callback_obj->do_callback(&cbdata);
+  CallbackObject *obj = w->_tick_callback_obj;
+  if (obj) {
+    BulletTickCallbackData cbdata(timestep);
+    obj->do_callback(&cbdata);
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -895,7 +900,7 @@ set_filter_callback(CallbackObject *obj) {
   nassertv(obj != NULL);
 
   if (bullet_filter_algorithm != FA_callback) {
-    bullet_cat.warning() << "filter algorithm is not 'python-callback'" << endl;
+    bullet_cat.warning() << "filter algorithm is not 'callback'" << endl;
   }
 
   _filter_cb3._filter_callback_obj = obj;

+ 2 - 2
panda/src/bullet/bulletWorld.h

@@ -139,7 +139,7 @@ PUBLISHED:
   void set_contact_added_callback(CallbackObject *obj);
   void clear_contact_added_callback();
 
-  void set_tick_callback(CallbackObject *obj);
+  void set_tick_callback(CallbackObject *obj, bool is_pretick=false);
   void clear_tick_callback();
 
   void set_filter_callback(CallbackObject *obj);
@@ -184,7 +184,7 @@ private:
   void sync_p2b(PN_stdfloat dt, int num_substeps);
   void sync_b2p();
 
-  void tick_callback(btDynamicsWorld *world, btScalar timestep);
+  static void tick_callback(btDynamicsWorld *world, btScalar timestep);
 
   typedef PTA(PT(BulletRigidBodyNode)) BulletRigidBodies;
   typedef PTA(PT(BulletSoftBodyNode)) BulletSoftBodies;

+ 9 - 0
panda/src/bullet/bullet_utils.cxx

@@ -219,3 +219,12 @@ void get_node_transform(btTransform &trans, PandaNode *node) {
   trans.setOrigin(btv);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: get_bullet_version
+//  Description: Returns the version of the linked Bullet library.
+////////////////////////////////////////////////////////////////////
+int get_bullet_version() {
+
+  return BT_BULLET_VERSION;
+}
+

+ 1 - 0
panda/src/bullet/bullet_utils.h

@@ -55,6 +55,7 @@ enum BulletUpAxis {
 };
 
 EXPCL_PANDABULLET BulletUpAxis get_default_up_axis();
+EXPCL_PANDABULLET int get_bullet_version();
 
 END_PUBLISH
 

+ 50 - 13
panda/src/display/displayRegion.I

@@ -239,17 +239,41 @@ get_texture_reload_priority() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: DisplayRegion::get_cube_map_index
+//     Function: DisplayRegion::set_cube_map_index
 //       Access: Published
-//  Description: Returns the cube map face index associated with this
+//  Description: Deprecated; replaced by set_target_tex_page().
+////////////////////////////////////////////////////////////////////
+INLINE void DisplayRegion::
+set_cube_map_index(int cube_map_index) {
+  set_target_tex_page(cube_map_index, 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DisplayRegion::get_target_tex_page
+//       Access: Published
+//  Description: Returns the target page number associated with this
 //               particular DisplayRegion, or -1 if it is not
-//               associated with a cube map.  See
-//               set_cube_map_index().
+//               associated with a page.  See
+//               set_target_tex_page().
 ////////////////////////////////////////////////////////////////////
 INLINE int DisplayRegion::
-get_cube_map_index() const {
+get_target_tex_page() const {
   CDReader cdata(_cycler);
-  return cdata->_cube_map_index;
+  return cdata->_target_tex_page;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DisplayRegion::get_target_tex_view
+//       Access: Published
+//  Description: Returns the target view number associated with this
+//               particular DisplayRegion, or -1 if it is not
+//               associated with a view.  See
+//               set_target_tex_page().
+////////////////////////////////////////////////////////////////////
+INLINE int DisplayRegion::
+get_target_tex_view() const {
+  CDReader cdata(_cycler);
+  return cdata->_target_tex_view;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -776,16 +800,29 @@ get_tex_view_offset() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: DisplayRegionPipelineReader::get_cube_map_index
-//       Access: Public
-//  Description: Returns the cube map face index associated with this
+//     Function: DisplayRegionPipelineReader::get_target_tex_page
+//       Access: Published
+//  Description: Returns the target page number associated with this
+//               particular DisplayRegion, or -1 if it is not
+//               associated with a page.  See
+//               set_target_tex_page().
+////////////////////////////////////////////////////////////////////
+INLINE int DisplayRegionPipelineReader::
+get_target_tex_page() const {
+  return _cdata->_target_tex_page;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DisplayRegionPipelineReader::get_target_tex_view
+//       Access: Published
+//  Description: Returns the target view number associated with this
 //               particular DisplayRegion, or -1 if it is not
-//               associated with a cube map.  See
-//               set_cube_map_index().
+//               associated with a view.  See
+//               set_target_tex_page().
 ////////////////////////////////////////////////////////////////////
 INLINE int DisplayRegionPipelineReader::
-get_cube_map_index() const {
-  return _cdata->_cube_map_index;
+get_target_tex_view() const {
+  return _cdata->_target_tex_view;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 20 - 11
panda/src/display/displayRegion.cxx

@@ -387,22 +387,29 @@ get_cull_traverser() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: DisplayRegion::set_cube_map_index
+//     Function: DisplayRegion::set_target_tex_page
 //       Access: Published, Virtual
 //  Description: This is a special parameter that is only used when
-//               rendering the faces of a cube map.  Normally you
-//               should not need to set it directly.  This sets up the
-//               DisplayRegion to render to the nth cube map face; the
-//               value must be between 0 and 5, inclusive.  A normal
-//               DisplayRegion that is not associated with any
-//               particular cube map should be set to -1.
+//               rendering the faces of a cube map or multipage and/or
+//               multiview texture.  
+//
+//               This sets up the DisplayRegion to render to the ith
+//               page and jth view of its associated texture(s); the
+//               value must be consistent with the range of values
+//               availble to the texture.  A normal DisplayRegion that
+//               is not associated with any particular page should be
+//               set to page -1 and view 0.
+//
+//               This is particularly useful when rendering cube maps
+//               and/or stereo textures.
 ////////////////////////////////////////////////////////////////////
 void DisplayRegion::
-set_cube_map_index(int cube_map_index) {
+set_target_tex_page(int page, int view) {
   int pipeline_stage = Thread::get_current_pipeline_stage();
   nassertv(pipeline_stage == 0);
   CDWriter cdata(_cycler);
-  cdata->_cube_map_index = cube_map_index;
+  cdata->_target_tex_page = page;
+  cdata->_target_tex_view = view;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -816,7 +823,8 @@ CData() :
   _sort(0),
   _stereo_channel(Lens::SC_mono),
   _tex_view_offset(0),
-  _cube_map_index(-1)
+  _target_tex_page(-1),
+  _target_tex_view(-1)
 {
 }
 
@@ -841,7 +849,8 @@ CData(const DisplayRegion::CData &copy) :
   _sort(copy._sort),
   _stereo_channel(copy._stereo_channel),
   _tex_view_offset(copy._tex_view_offset),
-  _cube_map_index(copy._cube_map_index)
+  _target_tex_page(copy._target_tex_page),
+  _target_tex_view(copy._target_tex_view)
 {
 }
 

+ 8 - 4
panda/src/display/displayRegion.h

@@ -111,8 +111,10 @@ PUBLISHED:
   virtual void set_cull_traverser(CullTraverser *trav);
   CullTraverser *get_cull_traverser();
 
-  virtual void set_cube_map_index(int cube_map_index);
-  INLINE int get_cube_map_index() const;
+  INLINE void set_cube_map_index(int cube_map_index);
+  virtual void set_target_tex_page(int page, int view);
+  INLINE int get_target_tex_page() const;
+  INLINE int get_target_tex_view() const;
 
   INLINE void set_cull_callback(CallbackObject *object);
   INLINE void clear_cull_callback();
@@ -210,7 +212,8 @@ private:
     int _sort;
     Lens::StereoChannel _stereo_channel;
     int _tex_view_offset;
-    int _cube_map_index;
+    int _target_tex_page;
+    int _target_tex_view;
 
     PT(CallbackObject) _cull_callback;
     PT(CallbackObject) _draw_callback;
@@ -308,7 +311,8 @@ public:
   INLINE Lens::StereoChannel get_stereo_channel() const;
   INLINE int get_tex_view_offset();
   INLINE bool get_clear_depth_between_eyes() const;
-  INLINE int get_cube_map_index() const;
+  INLINE int get_target_tex_page() const;
+  INLINE int get_target_tex_view() const;
   INLINE CallbackObject *get_draw_callback() const;
 
   INLINE void get_pixels(int &pl, int &pr, int &pb, int &pt) const;

+ 5 - 3
panda/src/display/graphicsOutput.I

@@ -862,12 +862,14 @@ end_frame_spam(FrameMode mode) {
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsOutput::clear_cube_map_selection
 //       Access: Public
-//  Description: Clear the variables that select a cube-map face.
+//  Description: Clear the variables that select a cube-map face (or
+//               other multipage or multiview texture face).
 ////////////////////////////////////////////////////////////////////
 INLINE void GraphicsOutput::
 clear_cube_map_selection() {
-  _cube_map_index = -1;
-  _cube_map_dr = NULL;
+  _target_tex_page = -1;
+  _target_tex_view = -1;
+  _prev_page_dr = NULL;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 47 - 72
panda/src/display/graphicsOutput.cxx

@@ -106,9 +106,9 @@ GraphicsOutput(GraphicsEngine *engine, GraphicsPipe *pipe,
 
   _is_valid = false;
   _flip_ready = false;
-  _cube_map_index = -1;
-  _cube_map_dr = NULL;
-  _tex_view_offset = -1;
+  _target_tex_page = -1;
+  _target_tex_view = -1;
+  _prev_page_dr = NULL;
   _sort = 0;
   _child_sort = 0;
   _got_child_sort = false;
@@ -1069,7 +1069,7 @@ make_cube_map(const string &name, int size, NodePath &camera_rig,
     DisplayRegion *dr;
     dr = buffer->make_display_region();
 
-    dr->set_cube_map_index(i);
+    dr->set_target_tex_page(i, 0);
     dr->copy_clear_settings(*this);
     dr->set_camera(camera_np);
   }
@@ -1341,13 +1341,16 @@ end_frame(FrameMode mode, Thread *current_thread) {
 ////////////////////////////////////////////////////////////////////
 void GraphicsOutput::
 change_scenes(DisplayRegionPipelineReader *new_dr) {
-  int new_cube_map_index = new_dr->get_cube_map_index();
-  if (new_cube_map_index != -1 &&
-      new_cube_map_index != _cube_map_index) {
-    int old_cube_map_index = _cube_map_index;
-    DisplayRegion *old_cube_map_dr = _cube_map_dr;
-    _cube_map_index = new_cube_map_index;
-    _cube_map_dr = new_dr->get_object();
+  int new_target_tex_page = new_dr->get_target_tex_page();
+  int new_target_tex_view = new_dr->get_target_tex_view();
+  if ((new_target_tex_page != -1 && new_target_tex_page != _target_tex_page) ||
+      new_target_tex_view != _target_tex_view) {
+    int old_target_tex_page = _target_tex_page;
+    int old_target_tex_view = _target_tex_view;
+    DisplayRegion *old_page_dr = _prev_page_dr;
+    _target_tex_page = new_target_tex_page;
+    _target_tex_view = new_target_tex_view;
+    _prev_page_dr = new_dr->get_object();
 
     CDReader cdata(_cycler);
     RenderTextures::const_iterator ri;
@@ -1356,83 +1359,55 @@ change_scenes(DisplayRegionPipelineReader *new_dr) {
       Texture *texture = (*ri)._texture;
       if (rtm_mode != RTM_none) {
         if (rtm_mode == RTM_bind_or_copy || rtm_mode == RTM_bind_layered) {
-          // In render-to-texture mode, switch the rendering backend to
-          // the new cube map face, so that the subsequent frame will be
-          // rendered to the new face.
+          // In render-to-texture mode, switch the rendering backend
+          // to the new page, so that the subsequent frame will be
+          // rendered to the correct page.
+          select_target_tex_page(_target_tex_page, _target_tex_view);
 
-          select_cube_map(new_cube_map_index);
-
-        } else if (old_cube_map_index != -1) {
+        } else if (old_target_tex_page != -1) {
           // In copy-to-texture mode, copy the just-rendered framebuffer
-          // to the old cube map face.
-          nassertv(old_cube_map_dr != (DisplayRegion *)NULL);
+          // to the old texture page.
+
+          // TODO: we should probably pass the view parameter into
+          // framebuffer_copy_to_xxx(), as we do the page parameter.
+          // Instead these methods draw the view parameter from
+          // dr->get_target_tex_view(), which is not altogether wrong
+          // but is a strange approach.
+
+          nassertv(old_page_dr != (DisplayRegion *)NULL);
           if (display_cat.is_debug()) {
             display_cat.debug()
               << "Copying texture for " << get_name() << " at scene change.\n";
             display_cat.debug()
-              << "cube_map_index = " << old_cube_map_index << "\n";
+              << "target_tex_page = " << old_target_tex_page << "\n";
           }
           RenderBuffer buffer = _gsg->get_render_buffer(get_draw_buffer_type(),
                                                         get_fb_properties());
           if (rtm_mode == RTM_copy_ram) {
-            _gsg->framebuffer_copy_to_ram(texture, old_cube_map_index,
-                                          old_cube_map_dr, buffer);
+            _gsg->framebuffer_copy_to_ram(texture, old_target_tex_page,
+                                          old_page_dr, buffer);
           } else {
-            _gsg->framebuffer_copy_to_texture(texture, old_cube_map_index,
-                                              old_cube_map_dr, buffer);
+            _gsg->framebuffer_copy_to_texture(texture, old_target_tex_page,
+                                              old_page_dr, buffer);
           }
         }
       }
     }
   }
-
-  int new_tex_view_offset = new_dr->get_tex_view_offset();
-  if (new_tex_view_offset != _tex_view_offset) {
-    int old_tex_view_offset = _tex_view_offset;
-    //DisplayRegion *old_cube_map_dr = _cube_map_dr;
-    _tex_view_offset = new_tex_view_offset;
-    //_cube_map_dr = new_dr->get_object();
-
-    CDReader cdata(_cycler);
-    RenderTextures::const_iterator ri;
-    for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) {
-      RenderTextureMode rtm_mode = (*ri)._rtm_mode;
-      Texture *texture = (*ri)._texture;
-      if (rtm_mode == RTM_bind_or_copy || rtm_mode == RTM_bind_layered) {
-        // In render-to-texture mode, switch the rendering backend to
-        // the new view, so that the subsequent frame will be
-        // rendered to the new view.
-
-        select_tex_view(new_tex_view_offset);
-        break;
-      }
-    }
-  }
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GraphicsOutput::select_cube_map
+//     Function: GraphicsOutput::select_target_tex_page
 //       Access: Public, Virtual
 //  Description: Called internally when the window is in
 //               render-to-a-texture mode and we are in the process of
-//               rendering the six faces of a cube map.  This should
-//               do whatever needs to be done to switch the buffer to
-//               the indicated face.
-////////////////////////////////////////////////////////////////////
-void GraphicsOutput::
-select_cube_map(int) {
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsOutput::select_tex_view
-//       Access: Public, Virtual
-//  Description: Called internally when the window is in
-//               render-to-a-texture mode and the DisplayRegion
-//               requests that we switch rendering to a different
-//               texture view.
+//               rendering the six faces of a cube map, or any other
+//               multi-page and/or multi-view texture.  This should do
+//               whatever needs to be done to switch the buffer to the
+//               indicated page and view.
 ////////////////////////////////////////////////////////////////////
 void GraphicsOutput::
-select_tex_view(int) {
+select_target_tex_page(int, int) {
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1603,7 +1578,7 @@ copy_to_textures() {
         display_cat.debug()
           << "Copying texture for " << get_name() << " at frame end.\n";
         display_cat.debug()
-          << "cube_map_index = " << _cube_map_index << "\n";
+          << "target_tex_page = " << _target_tex_page << "\n";
       }
       RenderTexturePlane plane = (*ri)._plane;
       RenderBuffer buffer(_gsg, DrawableRegion::get_renderbuffer_type(plane));
@@ -1613,24 +1588,24 @@ copy_to_textures() {
       }
 
       bool copied = false;
-      if (_cube_map_dr != (DisplayRegion *)NULL) {
+      if (_prev_page_dr != (DisplayRegion *)NULL) {
         if ((rtm_mode == RTM_copy_ram)||(rtm_mode == RTM_triggered_copy_ram)) {
           copied =
-            _gsg->framebuffer_copy_to_ram(texture, _cube_map_index,
-                                          _cube_map_dr, buffer);
+            _gsg->framebuffer_copy_to_ram(texture, _target_tex_page,
+                                          _prev_page_dr, buffer);
         } else {
           copied =
-            _gsg->framebuffer_copy_to_texture(texture, _cube_map_index,
-                                              _cube_map_dr, buffer);
+            _gsg->framebuffer_copy_to_texture(texture, _target_tex_page,
+                                              _prev_page_dr, buffer);
         }
       } else {
         if ((rtm_mode == RTM_copy_ram)||(rtm_mode == RTM_triggered_copy_ram)) {
           copied =
-            _gsg->framebuffer_copy_to_ram(texture, _cube_map_index,
+            _gsg->framebuffer_copy_to_ram(texture, _target_tex_page,
                                           _overlay_display_region, buffer);
         } else {
           copied =
-            _gsg->framebuffer_copy_to_texture(texture, _cube_map_index,
+            _gsg->framebuffer_copy_to_texture(texture, _target_tex_page,
                                               _overlay_display_region, buffer);
         }
       }

+ 4 - 5
panda/src/display/graphicsOutput.h

@@ -260,8 +260,7 @@ public:
   virtual void end_frame(FrameMode mode, Thread *current_thread);
 
   void change_scenes(DisplayRegionPipelineReader *new_dr);
-  virtual void select_cube_map(int cube_map_index);
-  virtual void select_tex_view(int tex_view_offset);
+  virtual void select_target_tex_page(int page, int view);
 
   // These methods will be called within the app (main) thread.
   virtual void begin_flip();
@@ -311,9 +310,9 @@ protected:
   bool _stereo;
   string _name;
   bool _flip_ready;
-  int _cube_map_index;
-  DisplayRegion *_cube_map_dr;
-  int _tex_view_offset;
+  int _target_tex_page;
+  int _target_tex_view;
+  DisplayRegion *_prev_page_dr;
   PT(Geom) _texture_card;
   bool _trigger_copy;
 

+ 1 - 1
panda/src/display/graphicsStateGuardian.cxx

@@ -2754,7 +2754,7 @@ make_shadow_buffer(const NodePath &light_np, GraphicsOutputBase *host) {
     for (int i = 0; i < 6; ++i) {
       PT(DisplayRegion) dr = sbuffer->make_mono_display_region(0, 1, 0, 1);
       dr->set_lens_index(i);
-      dr->set_cube_map_index(i);
+      dr->set_target_tex_page(i, 0);
       dr->set_camera(light_np);
       dr->set_clear_depth_active(true);
     }

+ 6 - 6
panda/src/display/stereoDisplayRegion.cxx

@@ -284,16 +284,16 @@ set_cull_traverser(CullTraverser *trav) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: StereoDisplayRegion::set_cube_map_index
+//     Function: StereoDisplayRegion::set_target_tex_page
 //       Access: Published, Virtual
-//  Description: Sets the cube_map_index on both the left and
+//  Description: Sets the page and view on both the left and
 //               right DisplayRegions to the indicated value.
 ////////////////////////////////////////////////////////////////////
 void StereoDisplayRegion::
-set_cube_map_index(int cube_map_index) {
-  DisplayRegion::set_cube_map_index(cube_map_index);
-  _left_eye->set_cube_map_index(cube_map_index);
-  _right_eye->set_cube_map_index(cube_map_index);
+set_target_tex_page(int page, int view) {
+  DisplayRegion::set_target_tex_page(page, view);
+  _left_eye->set_target_tex_page(page, view);
+  _right_eye->set_target_tex_page(page, view);
 }
 
 ////////////////////////////////////////////////////////////////////

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

@@ -61,7 +61,7 @@ PUBLISHED:
   virtual void set_incomplete_render(bool incomplete_render);
   virtual void set_texture_reload_priority(int texture_reload_priority);
   virtual void set_cull_traverser(CullTraverser *trav);
-  virtual void set_cube_map_index(int cube_map_index);
+  virtual void set_target_tex_page(int page, int view);
 
   virtual void output(ostream &out) const;
   virtual PT(PandaNode) make_cull_result_graph();

+ 3 - 3
panda/src/dxgsg8/wdxGraphicsBuffer8.cxx

@@ -394,7 +394,7 @@ rebuild_bitplanes() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: wdxGraphicsBuffer8::select_cube_map
+//     Function: wdxGraphicsBuffer8::select_target_tex_page
 //       Access: Public, Virtual
 //  Description: Called internally when the window is in
 //               render-to-a-texture mode and we are in the process of
@@ -403,8 +403,8 @@ rebuild_bitplanes() {
 //               the indicated face.
 ////////////////////////////////////////////////////////////////////
 void wdxGraphicsBuffer8::
-select_cube_map(int cube_map_index) {
-  _cube_map_index = cube_map_index;
+select_target_tex_page(int page, int view) {
+  _cube_map_index = page;
 
   HRESULT hr;
   Texture *color_tex = 0;

+ 1 - 1
panda/src/dxgsg8/wdxGraphicsBuffer8.h

@@ -46,7 +46,7 @@ public:
   virtual bool begin_frame(FrameMode mode, Thread *current_thread);
   virtual void end_frame(FrameMode mode, Thread *current_thread);
   
-  virtual void select_cube_map(int cube_map_index);
+  virtual void select_target_tex_page(int page, int view);
 
   virtual void process_events();
 

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

@@ -1902,7 +1902,7 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
   // must use a render target type texture for StretchRect
   tex->set_render_to_texture(true);
 
-  int view = dr->get_tex_view_offset();
+  int view = dr->get_target_tex_view();
   TextureContext *tc = tex->prepare_now(view, get_prepared_objects(), this);
   if (tc == (TextureContext *)NULL) {
     return false;

+ 3 - 3
panda/src/dxgsg9/wdxGraphicsBuffer9.cxx

@@ -582,7 +582,7 @@ rebuild_bitplanes() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: wdxGraphicsBuffer9::select_cube_map
+//     Function: wdxGraphicsBuffer9::select_target_tex_page
 //       Access: Public, Virtual
 //  Description: Called internally when the window is in
 //               render-to-a-texture mode and we are in the process of
@@ -591,13 +591,13 @@ rebuild_bitplanes() {
 //               the indicated face.
 ////////////////////////////////////////////////////////////////////
 void wdxGraphicsBuffer9::
-select_cube_map(int cube_map_index) {
+select_target_tex_page(int page, int view) {
 
   DWORD render_target_index;
   
   render_target_index = 0;
 
-  _cube_map_index = cube_map_index;
+  _cube_map_index = page;
 
   HRESULT hr;
   Texture *color_tex = 0;

+ 1 - 1
panda/src/dxgsg9/wdxGraphicsBuffer9.h

@@ -46,7 +46,7 @@ public:
   virtual bool begin_frame(FrameMode mode, Thread *current_thread);
   virtual void end_frame(FrameMode mode, Thread *current_thread);
 
-  virtual void select_cube_map(int cube_map_index);
+  virtual void select_target_tex_page(int page, int view);
   
   virtual void process_events();
 

+ 70 - 80
panda/src/glstuff/glGraphicsBuffer_src.cxx

@@ -80,7 +80,7 @@ CLP(GraphicsBuffer)(GraphicsEngine *engine, GraphicsPipe *pipe,
   }
 
   _shared_depth_buffer = 0;
-  _active_cube_map_index = -1;
+  _bound_tex_page = -1;
   _bound_tex_view = 0;
 }
 
@@ -125,7 +125,7 @@ begin_frame(FrameMode mode, Thread *current_thread) {
   begin_frame_spam(mode);
 
   check_host_valid();
-  _active_cube_map_index = -1;
+  _bound_tex_page = -1;
 
   if (!_is_valid) {
     if (GLCAT.is_debug()) {
@@ -1056,7 +1056,7 @@ end_frame(FrameMode mode, Thread *current_thread) {
   CLP(GraphicsStateGuardian) *glgsg;
   DCAST_INTO_V(glgsg, _gsg);
   glgsg->bind_fbo(0);
-  _active_cube_map_index = -1;
+  _bound_tex_page = -1;
 
   if (mode == FM_render) {
     generate_mipmaps();
@@ -1086,105 +1086,95 @@ set_size(int x, int y) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: glGraphicsBuffer::select_cube_map
+//     Function: glGraphicsBuffer::select_target_tex_page
 //       Access: Public, Virtual
 //  Description: Called internally when the window is in
 //               render-to-a-texture mode and we are in the process of
-//               rendering the six layers of a cube map.  This should
-//               do whatever needs to be done to switch the buffer to
-//               the indicated face.
+//               rendering the six faces of a cube map, or any other
+//               multi-page and/or multi-view texture.  This should do
+//               whatever needs to be done to switch the buffer to the
+//               indicated page and view.
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsBuffer)::
-select_cube_map(int cube_map_index) {
-  nassertv(cube_map_index >= 0 && cube_map_index < _fbo.size());
-
-  if (_active_cube_map_index != -1) {
-    // Resolve the multisample rendering for the previous face.
-    if (_requested_multisamples && _fbo_multisample) {
-      resolve_multisamples();
-    }
-  }
+select_target_tex_page(int page, int view) {
+  nassertv(page >= 0 && page < _fbo.size());
 
   CLP(GraphicsStateGuardian) *glgsg;
   DCAST_INTO_V(glgsg, _gsg);
 
-  glgsg->bind_fbo(_fbo[cube_map_index]);
-  _active_cube_map_index = cube_map_index;
-
-  report_my_gl_errors();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: glGraphicsBuffer::select_tex_view
-//       Access: Public, Virtual
-//  Description: Called internally when the window is in
-//               render-to-a-texture mode and the DisplayRegion
-//               requests that we switch rendering to a different
-//               texture view.
-//
-//               In the FBO case, we do this by re-binding the
-//               texture that is attached to the color plane.
-////////////////////////////////////////////////////////////////////
-void CLP(GraphicsBuffer)::
-select_tex_view(int view) {
-  CLP(GraphicsStateGuardian) *glgsg;
-  DCAST_INTO_V(glgsg, _gsg);
+  bool switched_page = (_bound_tex_page != page);
+  bool switched_view = (_bound_tex_view != view);
 
-  if (view == _bound_tex_view) {
-    return;
+  if (switched_page) {
+    if (_bound_tex_page != -1) {
+      // Resolve the multisample rendering for the previous face.
+      if (_requested_multisamples && _fbo_multisample) {
+        resolve_multisamples();
+      }
+    }
+    
+    glgsg->bind_fbo(_fbo[page]);
+    _bound_tex_page = page;
   }
 
-  // We assume that we've already configured the texture earlier
-  // in bind_bitplanes.  Therefore, since we can safely assume that
-  // all texture views have the same format, we can just bind the
-  // new view here.
+  if (switched_view || switched_page) {
+    // We assume that we've already configured the texture earlier
+    // in bind_bitplanes.  Therefore, since we can safely assume that
+    // all texture views have the same format, we can just bind the
+    // new view here.
 
-  Texture *tex = _tex[RTP_color];
-  if (tex != NULL) {
-    if (view >= tex->get_num_views()) {
-      tex->set_num_views(view + 1);
-    }
+    Texture *tex = _tex[RTP_color];
+    if (tex != NULL) {
+      if (view >= tex->get_num_views()) {
+        tex->set_num_views(view + 1);
+      }
 
-    GLenum target = glgsg->get_texture_target(tex->get_texture_type());
-    if (target == GL_TEXTURE_CUBE_MAP) {
-      target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + _active_cube_map_index;
-    }
+      GLenum target = glgsg->get_texture_target(tex->get_texture_type());
+      if (target == GL_TEXTURE_CUBE_MAP) {
+        target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + _bound_tex_page;
+      }
 
-    // Create the OpenGL texture object.
-    TextureContext *tc = tex->prepare_now(view, glgsg->get_prepared_objects(), glgsg);
-    nassertv(tc != (TextureContext *)NULL);
-    CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
-    glgsg->update_texture(tc, true);
+      // Create the OpenGL texture object.
+      TextureContext *tc = tex->prepare_now(view, glgsg->get_prepared_objects(), glgsg);
+      nassertv(tc != (TextureContext *)NULL);
+      CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
+      glgsg->update_texture(tc, true);
 
-    GLCAT.spam() << "Binding texture " << *tex
-      << " view " << view << " to color attachment.\n";
+      if (GLCAT.is_spam()) {
+        GLCAT.spam()
+          << "Binding texture " << *tex
+          << " view " << view << " to color attachment.\n";
+      }
 
-  #ifndef OPENGLES
-    GLclampf priority = 1.0f;
-    glPrioritizeTextures(1, &gtc->_index, &priority);
-  #endif
-    glgsg->update_texture(tc, true);
+#ifndef OPENGLES
+      GLclampf priority = 1.0f;
+      glPrioritizeTextures(1, &gtc->_index, &priority);
+#endif
+      glgsg->update_texture(tc, true);
 
-    if (_rb_size_z == 1) {
-      if (target == GL_TEXTURE_3D) {
-        glgsg->_glFramebufferTexture3D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
-                                       target, gtc->_index, 0, _active_cube_map_index);
-      } else if (target == GL_TEXTURE_2D_ARRAY_EXT) {
-        glgsg->_glFramebufferTextureLayer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
-                                          gtc->_index, 0, _active_cube_map_index);
+      if (_rb_size_z == 1) {
+        if (target == GL_TEXTURE_3D) {
+          glgsg->_glFramebufferTexture3D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+                                         target, gtc->_index, 0, _bound_tex_page);
+        } else if (target == GL_TEXTURE_2D_ARRAY_EXT) {
+          glgsg->_glFramebufferTextureLayer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+                                            gtc->_index, 0, _bound_tex_page);
+        } else {
+          glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+                                         target, gtc->_index, 0);
+        }
       } else {
-        glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
-                                       target, gtc->_index, 0);
+        glgsg->_glFramebufferTexture(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+                                     gtc->_index, 0);
       }
-    } else {
-      glgsg->_glFramebufferTexture(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
-                                   gtc->_index, 0);
+
+      report_my_gl_errors();
     }
 
-    report_my_gl_errors();
+    _bound_tex_view = view;
   }
 
-  _bound_tex_view = view;
+  report_my_gl_errors();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1528,8 +1518,8 @@ resolve_multisamples() {
 
   glgsg->report_my_gl_errors();
   GLuint fbo = _fbo[0];
-  if (_active_cube_map_index != -1) {
-    fbo = _fbo[_active_cube_map_index];
+  if (_bound_tex_page != -1) {
+    fbo = _fbo[_bound_tex_page];
   }
   glgsg->_glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, fbo);
   glgsg->_glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, _fbo_multisample);

+ 2 - 3
panda/src/glstuff/glGraphicsBuffer_src.h

@@ -74,8 +74,7 @@ public:
 
   virtual void set_size(int x, int y);
 
-  virtual void select_cube_map(int cube_map_index);
-  virtual void select_tex_view(int tex_view_offset);
+  virtual void select_target_tex_page(int page, int view);
 
   virtual bool share_depth_buffer(GraphicsOutput *graphics_output);
   virtual void unshare_depth_buffer();
@@ -129,7 +128,7 @@ private:
 
   // The cube map face we are currently drawing to or have just
   // finished drawing to, or -1 if we are not drawing to a cube map.
-  int _active_cube_map_index;
+  int _bound_tex_page;
   int _bound_tex_view;
 
   bool _initial_clear;

+ 19 - 11
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -3543,12 +3543,6 @@ update_texture(TextureContext *tc, bool force) {
 
   CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
 
-  if (GLCAT.is_debug() && gtc->get_texture()->get_name() != string("buf")) {
-    GLCAT.debug()
-      << "Considering update " << gtc->get_texture()->get_name()
-      << ": " << gtc->was_image_modified() << ", modified = " << gtc->get_texture()->get_image_modified() << "\n";
-  }
-
   if (gtc->was_image_modified()) {
     // If the texture image was modified, reload the texture.  This
     // means we also re-specify the properties for good measure.
@@ -4288,7 +4282,7 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
     }
   }
 
-  int view = dr->get_tex_view_offset();
+  int view = dr->get_target_tex_view();
   TextureContext *tc = tex->prepare_now(view, get_prepared_objects(), this);
   nassertr(tc != (TextureContext *)NULL, false);
   CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
@@ -4469,6 +4463,13 @@ framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr,
                        component_type, format);
   }
 
+  nassertr(z < tex->get_z_size(), false);
+
+  int view = dr->get_target_tex_view();
+  if (view >= tex->get_num_views()) {
+    tex->set_num_views(view + 1);
+  }
+
   GLenum external_format = get_external_image_format(tex);
 
   if (GLCAT.is_spam()) {
@@ -4519,10 +4520,14 @@ framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr,
 
   unsigned char *image_ptr = tex->modify_ram_image();
   size_t image_size = tex->get_ram_image_size();
-  if (z >= 0) {
-    nassertr(z < tex->get_z_size(), false);
+  if (z >= 0 || view > 0) {
     image_size = tex->get_expected_ram_page_size();
-    image_ptr += z * image_size;
+    if (z >= 0) {
+      image_ptr += z * image_size;
+    }
+    if (view > 0) {
+      image_ptr += (view * tex->get_z_size()) * image_size;
+    }
   }
 
   GLP(ReadPixels)(xo, yo, w, h,
@@ -9040,7 +9045,7 @@ upload_texture(CLP(TextureContext) *gtc, bool force) {
 //               in the case of cube mapping, in which case
 //               texture_target will be target for the overall
 //               texture, e.g. GL_TEXTURE_CUBE_MAP, and page_target
-//               will the target for this particular page,
+//               will be the target for this particular page,
 //               e.g. GL_TEXTURE_CUBE_MAP_POSITIVE_X.
 ////////////////////////////////////////////////////////////////////
 bool CLP(GraphicsStateGuardian)::
@@ -9082,6 +9087,8 @@ upload_texture_image(CLP(TextureContext) *gtc,
       GLCAT.debug()
         << "loading uncompressed texture " << tex->get_name() << "\n";
     }
+    GLCAT.debug()
+      << "page_target " << hex << page_target << dec << "\n";
   }
 
   int num_ram_mipmap_levels = 0;
@@ -9104,6 +9111,7 @@ upload_texture_image(CLP(TextureContext) *gtc,
         uses_mipmaps = false;
       }
     }
+
   } else {
     num_ram_mipmap_levels = 1;
     if (uses_mipmaps) {

+ 49 - 19
panda/src/gobj/texture.I

@@ -31,9 +31,9 @@ INLINE PT(Texture) Texture::
 make_copy() const {
   PT(Texture) tex = make_copy_impl();
   CDWriter cdata_tex(tex->_cycler, true);
-  ++(cdata_tex->_properties_modified);
-  ++(cdata_tex->_image_modified);
-  ++(cdata_tex->_simple_image_modified);
+  cdata_tex->inc_properties_modified();
+  cdata_tex->inc_image_modified();
+  cdata_tex->inc_simple_image_modified();
   return tex;
 }
 
@@ -288,8 +288,8 @@ INLINE bool Texture::
 load(const PNMImage &pnmimage, const LoaderOptions &options) {
   CDWriter cdata(_cycler, true);
   do_clear(cdata);
-  ++(cdata->_properties_modified);
-  ++(cdata->_image_modified);
+  cdata->inc_properties_modified();
+  cdata->inc_image_modified();
   if (do_load_one(cdata, pnmimage, get_name(), 0, 0, options)) {
     bool generate_mipmaps = ((options.get_texture_flags() & LoaderOptions::TF_generate_mipmaps) != 0);
     consider_auto_process_ram_image(generate_mipmaps || uses_mipmaps(), true);
@@ -307,8 +307,8 @@ load(const PNMImage &pnmimage, const LoaderOptions &options) {
 INLINE bool Texture::
 load(const PNMImage &pnmimage, int z, int n, const LoaderOptions &options) {
   CDWriter cdata(_cycler, true);
-  ++(cdata->_properties_modified);
-  ++(cdata->_image_modified);
+  cdata->inc_properties_modified();
+  cdata->inc_image_modified();
   if (do_load_one(cdata, pnmimage, get_name(), z, n, options)) {
     return true;
   }
@@ -324,8 +324,8 @@ INLINE bool Texture::
 load(const PfmFile &pfm, const LoaderOptions &options) {
   CDWriter cdata(_cycler, true);
   do_clear(cdata);
-  ++(cdata->_properties_modified);
-  ++(cdata->_image_modified);
+  cdata->inc_properties_modified();
+  cdata->inc_image_modified();
   if (do_load_one(cdata, pfm, get_name(), 0, 0, options)) {
     bool generate_mipmaps = ((options.get_texture_flags() & LoaderOptions::TF_generate_mipmaps) != 0);
     consider_auto_process_ram_image(generate_mipmaps || uses_mipmaps(), true);
@@ -343,8 +343,8 @@ load(const PfmFile &pfm, const LoaderOptions &options) {
 INLINE bool Texture::
 load(const PfmFile &pfm, int z, int n, const LoaderOptions &options) {
   CDWriter cdata(_cycler, true);
-  ++(cdata->_properties_modified);
-  ++(cdata->_image_modified);
+  cdata->inc_properties_modified();
+  cdata->inc_image_modified();
   if (do_load_one(cdata, pfm, get_name(), z, n, options)) {
     return true;
   }
@@ -1412,7 +1412,7 @@ get_ram_image_compression() const {
 INLINE PTA_uchar Texture::
 modify_ram_image() {
   CDWriter cdata(_cycler, true);
-  ++(cdata->_image_modified);
+  cdata->inc_image_modified();
   return do_modify_ram_image(cdata);
 }
 
@@ -1453,7 +1453,7 @@ get_uncompressed_ram_image() {
 INLINE PTA_uchar Texture::
 make_ram_image() {
   CDWriter cdata(_cycler, true);
-  ++(cdata->_image_modified);
+  cdata->inc_image_modified();
   return do_make_ram_image(cdata);
 }
 
@@ -1537,7 +1537,7 @@ compress_ram_image(Texture::CompressionMode compression,
                    GraphicsStateGuardianBase *gsg) {
   CDWriter cdata(_cycler, false);
   if (do_compress_ram_image(cdata, compression, quality_level, gsg)) {
-    ++(cdata->_image_modified);
+    cdata->inc_image_modified();
     return true;
   }
   return false;
@@ -1558,7 +1558,7 @@ INLINE bool Texture::
 uncompress_ram_image() {
   CDWriter cdata(_cycler, false);
   if (do_uncompress_ram_image(cdata)) {
-    ++(cdata->_image_modified);
+    cdata->inc_image_modified();
     return true;
   }
   return false;
@@ -1723,7 +1723,7 @@ get_expected_ram_mipmap_page_size(int n) const {
 INLINE PTA_uchar Texture::
 modify_ram_mipmap_image(int n) {
   CDWriter cdata(_cycler, false);
-  ++(cdata->_image_modified);
+  cdata->inc_image_modified();
   return do_modify_ram_mipmap_image(cdata, n);
 }
 
@@ -1739,7 +1739,7 @@ modify_ram_mipmap_image(int n) {
 INLINE PTA_uchar Texture::
 make_ram_mipmap_image(int n) {
   CDWriter cdata(_cycler, false);
-  ++(cdata->_image_modified);
+  cdata->inc_image_modified();
   return do_make_ram_mipmap_image(cdata, n);
 }
 
@@ -1769,7 +1769,7 @@ set_ram_mipmap_image(int n, CPTA_uchar image, size_t page_size) {
 INLINE void Texture::
 clear_ram_mipmap_images() {
   CDWriter cdata(_cycler, false);
-  ++(cdata->_image_modified);
+  cdata->inc_image_modified();
   do_clear_ram_mipmap_images(cdata);
 }
 
@@ -1790,7 +1790,7 @@ clear_ram_mipmap_images() {
 INLINE void Texture::
 generate_ram_mipmap_images() {
   CDWriter cdata(_cycler, unlocked_ensure_ram_image(false));
-  ++(cdata->_image_modified);
+  cdata->inc_image_modified();
   do_generate_ram_mipmap_images(cdata);
 }
 
@@ -2627,6 +2627,36 @@ is_dds_filename(const Filename &fullpath) {
   return (downcase(extension) == "dds");
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::CData::inc_properties_modified
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void Texture::CData::
+inc_properties_modified() {
+  ++_properties_modified;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::CData::inc_image_modified
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void Texture::CData::
+inc_image_modified() {
+  ++_image_modified;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::CData::inc_simple_image_modified
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void Texture::CData::
+inc_simple_image_modified() {
+  ++_simple_image_modified;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::RamImage::Constructor
 //       Access: Public

+ 58 - 54
panda/src/gobj/texture.cxx

@@ -238,8 +238,8 @@ generate_normalization_cube_map(int size) {
   PTA_uchar image = do_make_ram_image(cdata);
   cdata->_keep_ram_image = true;
 
-  ++(cdata->_image_modified);
-  ++(cdata->_properties_modified);
+  cdata->inc_image_modified();
+  cdata->inc_properties_modified();
 
   PN_stdfloat half_size = (PN_stdfloat)size * 0.5f;
   PN_stdfloat center = half_size - 0.5f;
@@ -345,8 +345,8 @@ generate_alpha_scale_map() {
   cdata->_magfilter = FT_nearest;
   cdata->_compression = CM_off;
 
-  ++(cdata->_image_modified);
-  ++(cdata->_properties_modified);
+  cdata->inc_image_modified();
+  cdata->inc_properties_modified();
 
   PTA_uchar image = do_make_ram_image(cdata);
   cdata->_keep_ram_image = true;
@@ -366,8 +366,8 @@ bool Texture::
 read(const Filename &fullpath, const LoaderOptions &options) {
   CDWriter cdata(_cycler, true);
   do_clear(cdata);
-  ++(cdata->_properties_modified);
-  ++(cdata->_image_modified);
+  cdata->inc_properties_modified();
+  cdata->inc_image_modified();
   return do_read(cdata, fullpath, Filename(), 0, 0, 0, 0, false, false,
                  options, NULL);
 }
@@ -389,8 +389,8 @@ read(const Filename &fullpath, const Filename &alpha_fullpath,
      const LoaderOptions &options) {
   CDWriter cdata(_cycler, true);
   do_clear(cdata);
-  ++(cdata->_properties_modified);
-  ++(cdata->_image_modified);
+  cdata->inc_properties_modified();
+  cdata->inc_image_modified();
   return do_read(cdata, fullpath, alpha_fullpath, primary_file_num_channels,
                  alpha_file_channel, 0, 0, false, false,
                  options, NULL);
@@ -411,8 +411,8 @@ read(const Filename &fullpath, int z, int n,
      bool read_pages, bool read_mipmaps,
      const LoaderOptions &options) {
   CDWriter cdata(_cycler, true);
-  ++(cdata->_properties_modified);
-  ++(cdata->_image_modified);
+  cdata->inc_properties_modified();
+  cdata->inc_image_modified();
   return do_read(cdata, fullpath, Filename(), 0, 0, z, n, read_pages, read_mipmaps,
                  options, NULL);
 }
@@ -493,8 +493,8 @@ read(const Filename &fullpath, const Filename &alpha_fullpath,
      BamCacheRecord *record,
      const LoaderOptions &options) {
   CDWriter cdata(_cycler, true);
-  ++(cdata->_properties_modified);
-  ++(cdata->_image_modified);
+  cdata->inc_properties_modified();
+  cdata->inc_image_modified();
   return do_read(cdata, fullpath, alpha_fullpath, primary_file_num_channels,
                  alpha_file_channel, z, n, read_pages, read_mipmaps,
                  options, record);
@@ -652,8 +652,8 @@ get_aux_data(const string &key) const {
 bool Texture::
 read_txo(istream &in, const string &filename) {
   CDWriter cdata(_cycler, true);
-  ++(cdata->_properties_modified);
-  ++(cdata->_image_modified);
+  cdata->inc_properties_modified();
+  cdata->inc_image_modified();
   return do_read_txo(cdata, in, filename);
 }
 
@@ -760,8 +760,8 @@ write_txo(ostream &out, const string &filename) const {
 bool Texture::
 read_dds(istream &in, const string &filename, bool header_only) {
   CDWriter cdata(_cycler, true);
-  ++(cdata->_properties_modified);
-  ++(cdata->_image_modified);
+  cdata->inc_properties_modified();
+  cdata->inc_image_modified();
   return do_read_dds(cdata, in, filename, header_only);
 }
 
@@ -1122,7 +1122,7 @@ set_ram_mipmap_pointer(int n, void *image, size_t page_size) {
   cdata->_ram_images[n]._page_size = page_size;
   //_ram_images[n]._image.clear(); wtf is going on?!
   cdata->_ram_images[n]._pointer_image = image;
-  ++(cdata->_image_modified);
+  cdata->inc_image_modified();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1189,7 +1189,7 @@ new_simple_ram_image(int x_size, int y_size) {
   cdata->_simple_ram_image._image = PTA_uchar::empty_array(expected_page_size);
   cdata->_simple_ram_image._page_size = expected_page_size;
   cdata->_simple_image_date_generated = (PN_int32)time(NULL);
-  ++(cdata->_simple_image_modified);
+  cdata->inc_simple_image_modified();
 
   return cdata->_simple_ram_image._image;
 }
@@ -4127,8 +4127,8 @@ unlocked_ensure_ram_image(bool allow_compression) {
     cdataw->_format = cdata_tex->_format;
     cdataw->_component_type = cdata_tex->_component_type;
     
-    ++(cdataw->_properties_modified);
-    ++(cdataw->_image_modified);
+    cdataw->inc_properties_modified();
+    cdataw->inc_image_modified();
   }
   
   cdataw->_keep_ram_image = cdata_tex->_keep_ram_image;
@@ -4343,7 +4343,7 @@ do_set_ram_image(CData *cdata, CPTA_uchar image, Texture::CompressionMode compre
     cdata->_ram_images[0]._page_size = page_size;
     cdata->_ram_images[0]._pointer_image = NULL;
     cdata->_ram_image_compression = compression;
-    ++(cdata->_image_modified);
+    cdata->inc_image_modified();
   }
 }
 
@@ -4404,7 +4404,7 @@ do_set_ram_mipmap_image(CData *cdata, int n, CPTA_uchar image, size_t page_size)
     cdata->_ram_images[n]._image = image.cast_non_const();
     cdata->_ram_images[n]._pointer_image = NULL;
     cdata->_ram_images[n]._page_size = page_size;
-    ++(cdata->_image_modified);
+    cdata->inc_image_modified();
   }
 }
 
@@ -4839,7 +4839,7 @@ do_rescale_texture(CData *cdata) {
     new_image.quick_filter_from(orig_image);
 
     do_clear_ram_image(cdata);
-    ++(cdata->_image_modified);
+    cdata->inc_image_modified();
     cdata->_x_size = new_x_size;
     cdata->_y_size = new_y_size;
     if (!do_load_one(cdata, new_image, get_name(), 0, 0, LoaderOptions())) {
@@ -4871,7 +4871,7 @@ do_rescale_texture(CData *cdata) {
 
       do_clear_ram_image(cdata);
       cdata->_loaded_from_image = false;
-      ++(cdata->_image_modified);
+      cdata->inc_image_modified();
       if (!do_load_one(cdata, new_image, get_name(), 0, 0, LoaderOptions())) {
         return false;
       }
@@ -4933,9 +4933,9 @@ do_clear(CData *cdata) {
   CDReader cdata_tex(tex._cycler);
   do_assign(cdata, &tex, cdata_tex);
 
-  ++(cdata->_properties_modified);
-  ++(cdata->_image_modified);
-  ++(cdata->_simple_image_modified);
+  cdata->inc_properties_modified();
+  cdata->inc_image_modified();
+  cdata->inc_simple_image_modified();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -5008,7 +5008,7 @@ do_set_format(CData *cdata, Texture::Format format) {
     return;
   }
   cdata->_format = format;
-  ++(cdata->_properties_modified);
+  cdata->inc_properties_modified();
 
   switch (cdata->_format) {
   case F_color_index:
@@ -5091,7 +5091,7 @@ void Texture::
 do_set_x_size(CData *cdata, int x_size) {
   if (cdata->_x_size != x_size) {
     cdata->_x_size = x_size;
-    ++(cdata->_image_modified);
+    cdata->inc_image_modified();
     do_clear_ram_image(cdata);
     do_set_pad_size(cdata, 0, 0, 0);
   }
@@ -5107,7 +5107,7 @@ do_set_y_size(CData *cdata, int y_size) {
   if (cdata->_y_size != y_size) {
     nassertv(cdata->_texture_type != Texture::TT_1d_texture || y_size == 1);
     cdata->_y_size = y_size;
-    ++(cdata->_image_modified);
+    cdata->inc_image_modified();
     do_clear_ram_image(cdata);
     do_set_pad_size(cdata, 0, 0, 0);
   }
@@ -5127,7 +5127,7 @@ do_set_z_size(CData *cdata, int z_size) {
              (cdata->_texture_type == Texture::TT_cube_map && z_size == 6) ||
              (cdata->_texture_type == Texture::TT_2d_texture_array) || (z_size == 1));
     cdata->_z_size = z_size;
-    ++(cdata->_image_modified);
+    cdata->inc_image_modified();
     do_clear_ram_image(cdata);
     do_set_pad_size(cdata, 0, 0, 0);
   }
@@ -5143,8 +5143,10 @@ do_set_num_views(CData *cdata, int num_views) {
   nassertv(num_views >= 1);
   if (cdata->_num_views != num_views) {
     cdata->_num_views = num_views;
-    ++(cdata->_image_modified);
-    do_clear_ram_image(cdata);
+    if (do_has_ram_image(cdata)) {
+      cdata->inc_image_modified();
+      do_clear_ram_image(cdata);
+    }
     do_set_pad_size(cdata, 0, 0, 0);
   }
 }
@@ -5157,7 +5159,7 @@ do_set_num_views(CData *cdata, int num_views) {
 void Texture::
 do_set_wrap_u(CData *cdata, Texture::WrapMode wrap) {
   if (cdata->_wrap_u != wrap) {
-    ++(cdata->_properties_modified);
+    cdata->inc_properties_modified();
     cdata->_wrap_u = wrap;
   }
 }
@@ -5170,7 +5172,7 @@ do_set_wrap_u(CData *cdata, Texture::WrapMode wrap) {
 void Texture::
 do_set_wrap_v(CData *cdata, Texture::WrapMode wrap) {
   if (cdata->_wrap_v != wrap) {
-    ++(cdata->_properties_modified);
+    cdata->inc_properties_modified();
     cdata->_wrap_v = wrap;
   }
 }
@@ -5183,7 +5185,7 @@ do_set_wrap_v(CData *cdata, Texture::WrapMode wrap) {
 void Texture::
 do_set_wrap_w(CData *cdata, Texture::WrapMode wrap) {
   if (cdata->_wrap_w != wrap) {
-    ++(cdata->_properties_modified);
+    cdata->inc_properties_modified();
     cdata->_wrap_w = wrap;
   }
 }
@@ -5196,7 +5198,7 @@ do_set_wrap_w(CData *cdata, Texture::WrapMode wrap) {
 void Texture::
 do_set_minfilter(CData *cdata, Texture::FilterType filter) {
   if (cdata->_minfilter != filter) {
-    ++(cdata->_properties_modified);
+    cdata->inc_properties_modified();
     cdata->_minfilter = filter;
   }
 }
@@ -5209,7 +5211,7 @@ do_set_minfilter(CData *cdata, Texture::FilterType filter) {
 void Texture::
 do_set_magfilter(CData *cdata, Texture::FilterType filter) {
   if (cdata->_magfilter != filter) {
-    ++(cdata->_properties_modified);
+    cdata->inc_properties_modified();
     cdata->_magfilter = filter;
   }
 }
@@ -5222,7 +5224,7 @@ do_set_magfilter(CData *cdata, Texture::FilterType filter) {
 void Texture::
 do_set_anisotropic_degree(CData *cdata, int anisotropic_degree) {
   if (cdata->_anisotropic_degree != anisotropic_degree) {
-    ++(cdata->_properties_modified);
+    cdata->inc_properties_modified();
     cdata->_anisotropic_degree = anisotropic_degree;
   }
 }
@@ -5235,7 +5237,7 @@ do_set_anisotropic_degree(CData *cdata, int anisotropic_degree) {
 void Texture::
 do_set_border_color(CData *cdata, const LColor &color) {
   if (cdata->_border_color != color) {
-    ++(cdata->_properties_modified);
+    cdata->inc_properties_modified();
     cdata->_border_color = color;
   }
 }
@@ -5248,7 +5250,7 @@ do_set_border_color(CData *cdata, const LColor &color) {
 void Texture::
 do_set_compression(CData *cdata, Texture::CompressionMode compression) {
   if (cdata->_compression != compression) {
-    ++(cdata->_properties_modified);
+    cdata->inc_properties_modified();
     cdata->_compression = compression;
 
     if (do_has_ram_image(cdata)) {
@@ -5273,7 +5275,7 @@ do_set_compression(CData *cdata, Texture::CompressionMode compression) {
 void Texture::
 do_set_quality_level(CData *cdata, Texture::QualityLevel quality_level) {
   if (cdata->_quality_level != quality_level) {
-    ++(cdata->_properties_modified);
+    cdata->inc_properties_modified();
     cdata->_quality_level = quality_level;
   }
 }
@@ -5325,12 +5327,14 @@ do_get_ram_image(CData *cdata) {
   if (!do_has_ram_image(cdata) && do_can_reload(cdata)) {
     do_reload_ram_image(cdata, true);
 
-    // Normally, we don't update the cdata->_modified semaphores in a do_blah
-    // method, but we'll make an exception in this case, because it's
-    // easiest to modify these here, and only when we know it's
-    // needed.
-    ++(cdata->_image_modified);
-    ++(cdata->_properties_modified);
+    if (do_has_ram_image(cdata)) {
+      // Normally, we don't update the cdata->_modified semaphores in a do_blah
+      // method, but we'll make an exception in this case, because it's
+      // easiest to modify these here, and only when we know it's
+      // needed.
+      cdata->inc_image_modified();
+      cdata->inc_properties_modified();
+    }
   }
 
   if (cdata->_ram_images.empty()) {
@@ -5539,7 +5543,7 @@ do_set_simple_ram_image(CData *cdata, CPTA_uchar image, int x_size, int y_size)
   cdata->_simple_ram_image._image = image.cast_non_const();
   cdata->_simple_ram_image._page_size = image.size();
   cdata->_simple_image_date_generated = (PN_int32)time(NULL);
-  ++(cdata->_simple_image_modified);
+  cdata->inc_simple_image_modified();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -5644,7 +5648,7 @@ do_clear_simple_ram_image(CData *cdata) {
   // We allow this exception: we update the _simple_image_modified
   // here, since no one really cares much about that anyway, and it's
   // convenient to do it here.
-  ++(cdata->_simple_image_modified);
+  cdata->inc_simple_image_modified();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -5804,7 +5808,7 @@ do_reload(CData *cdata) {
     do_reload_ram_image(cdata, true);
     if (do_has_ram_image(cdata)) {
       // An explicit call to reload() should increment image_modified.
-      ++(cdata->_image_modified);
+      cdata->inc_image_modified();
       return true;
     }
     return false;
@@ -7769,7 +7773,7 @@ do_fillin_body(CData *cdata, DatagramIterator &scan, BamReader *manager) {
   cdata->_format = (Format)scan.get_uint8();
   cdata->_num_components = scan.get_uint8();
 
-  ++(cdata->_properties_modified);
+  cdata->inc_properties_modified();
 
   cdata->_auto_texture_scale = ATS_unspecified;
   if (manager->get_file_minor_ver() >= 28) {
@@ -7797,7 +7801,7 @@ do_fillin_body(CData *cdata, DatagramIterator &scan, BamReader *manager) {
 
     cdata->_simple_ram_image._image = image;
     cdata->_simple_ram_image._page_size = u_size;
-    ++(cdata->_simple_image_modified);
+    cdata->inc_simple_image_modified();
   }
 }
 
@@ -7856,7 +7860,7 @@ do_fillin_rawdata(CData *cdata, DatagramIterator &scan, BamReader *manager) {
     cdata->_ram_images[n]._image = image;
   }
   cdata->_loaded_from_image = true;
-  ++(cdata->_image_modified);
+  cdata->inc_image_modified();
 }
 
 ////////////////////////////////////////////////////////////////////

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

@@ -776,6 +776,9 @@ protected:
     }
 
     void do_assign(const CData *copy);
+    INLINE void inc_properties_modified();
+    INLINE void inc_image_modified();
+    INLINE void inc_simple_image_modified();
 
     Filename _filename;
     Filename _alpha_filename;

+ 36 - 0
panda/src/gobj/textureContext.I

@@ -98,6 +98,42 @@ was_simple_image_modified() const {
   return _simple_image_modified != _texture->get_simple_image_modified();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TextureContext::get_properties_modified
+//       Access: Published
+//  Description: Returns a sequence number which is guaranteed to
+//               change at least every time the texture properties
+//               (unrelated to the image) are modified.
+////////////////////////////////////////////////////////////////////
+INLINE UpdateSeq TextureContext::
+get_properties_modified() const {
+  return _properties_modified;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureContext::get_image_modified
+//       Access: Published
+//  Description: Returns a sequence number which is guaranteed to
+//               change at least every time the texture image data
+//               (including mipmap levels) are modified.
+////////////////////////////////////////////////////////////////////
+INLINE UpdateSeq TextureContext::
+get_image_modified() const {
+  return _image_modified;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureContext::get_simple_image_modified
+//       Access: Published
+//  Description: Returns a sequence number which is guaranteed to
+//               change at least every time the texture's "simple"
+//               image data is modified.
+////////////////////////////////////////////////////////////////////
+INLINE UpdateSeq TextureContext::
+get_simple_image_modified() const {
+  return _simple_image_modified;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TextureContext::update_data_size_bytes
 //       Access: Public

+ 4 - 0
panda/src/gobj/textureContext.h

@@ -48,6 +48,10 @@ PUBLISHED:
   INLINE bool was_image_modified() const;
   INLINE bool was_simple_image_modified() const;
 
+  INLINE UpdateSeq get_properties_modified() const;
+  INLINE UpdateSeq get_image_modified() const;
+  INLINE UpdateSeq get_simple_image_modified() const;
+
 public:
   INLINE void update_data_size_bytes(size_t new_data_size_bytes);
   INLINE void mark_loaded();

+ 11 - 1
panda/src/pgraph/renderState.I

@@ -551,8 +551,18 @@ operator = (const Attribute &copy) {
 INLINE int RenderState::Attribute::
 compare_to(const Attribute &other) const {
   if (_attrib != other._attrib) {
-    return _attrib < other._attrib ? -1 : 1;
+    if (_attrib == NULL) {
+      return -1;
+    } else if (other._attrib == NULL) {
+      return 1;
+    }
+
+    int c = _attrib->compare_to(*other._attrib);
+    if (c != 0) {
+      return c;
+    }
   }
+
   return _override - other._override;
 }
 

+ 11 - 0
panda/src/putil/updateSeq.I

@@ -264,6 +264,17 @@ operator ++ (int) {
   return temp;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: UpdateSeq::get_seq
+//       Access: Published
+//  Description: Returns the internal integer value associated with
+//               the UpdateSeq.  Useful for debugging only.
+////////////////////////////////////////////////////////////////////
+INLINE AtomicAdjust::Integer UpdateSeq::
+get_seq() const {
+  return _seq;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: UpdateSeq::output
 //       Access: Published

+ 2 - 0
panda/src/putil/updateSeq.h

@@ -67,6 +67,8 @@ PUBLISHED:
   INLINE UpdateSeq operator ++ ();
   INLINE UpdateSeq operator ++ (int);
 
+  INLINE AtomicAdjust::Integer get_seq() const;
+
   INLINE void output(ostream &out) const;
 
 private:

+ 15 - 4
panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx

@@ -1359,7 +1359,7 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
 
   tex->setup_2d_texture(w, h, Texture::T_unsigned_byte, Texture::F_rgba);
 
-  int view = dr->get_tex_view_offset();
+  int view = dr->get_target_tex_view();
   TextureContext *tc = tex->prepare_now(view, get_prepared_objects(), this);
   nassertr(tc != (TextureContext *)NULL, false);
   TinyTextureContext *gtc = DCAST(TinyTextureContext, tc);
@@ -1431,12 +1431,23 @@ framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr,
                        component_type, format);
   }
 
+  nassertr(z < tex->get_z_size(), false);
+
+  int view = dr->get_target_tex_view();
+  if (view >= tex->get_num_views()) {
+    tex->set_num_views(view + 1);
+  }
+
   unsigned char *image_ptr = tex->modify_ram_image();
   size_t image_size = tex->get_ram_image_size();
-  if (z >= 0) {
-    nassertr(z < tex->get_z_size(), false);
+  if (z >= 0 || view > 0) {
     image_size = tex->get_expected_ram_page_size();
-    image_ptr += z * image_size;
+    if (z >= 0) {
+      image_ptr += z * image_size;
+    }
+    if (view > 0) {
+      image_ptr += (view * tex->get_z_size()) * image_size;
+    }
   }
 
   PIXEL *ip = (PIXEL *)(image_ptr + image_size);

+ 3 - 3
panda/src/wgldisplay/wglGraphicsBuffer.cxx

@@ -205,7 +205,7 @@ bind_texture_to_pbuffer() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: wglGraphicsBuffer::select_cube_map
+//     Function: wglGraphicsBuffer::select_target_tex_page
 //       Access: Public, Virtual
 //  Description: Called internally when the window is in
 //               render-to-a-texture mode and we are in the process of
@@ -214,7 +214,7 @@ bind_texture_to_pbuffer() {
 //               the indicated face.
 ////////////////////////////////////////////////////////////////////
 void wglGraphicsBuffer::
-select_cube_map(int cube_map_index) {
+select_target_tex_page(int page, int view) {
   wglGraphicsStateGuardian *wglgsg;
   DCAST_INTO_V(wglgsg, _gsg);
 
@@ -225,7 +225,7 @@ select_cube_map(int cube_map_index) {
   int ni = 0;
 
   iattrib_list[ni++] = WGL_CUBE_MAP_FACE_ARB;
-  iattrib_list[ni++] = WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + cube_map_index;
+  iattrib_list[ni++] = WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + page;
 
   // Terminate the list.
   nassertv(ni <= max_attrib_list);

+ 1 - 1
panda/src/wgldisplay/wglGraphicsBuffer.h

@@ -49,7 +49,7 @@ public:
   virtual bool begin_frame(FrameMode mode, Thread *current_thread);
   virtual void end_frame(FrameMode mode, Thread *current_thread);
 
-  virtual void select_cube_map(int cube_map_index);
+  virtual void select_target_tex_page(int page, int view);
 
   virtual void process_events();
 

+ 1 - 1
pandatool/src/maxegg/maxEggLoader.cxx

@@ -296,7 +296,7 @@ void MaxEggJoint::CreateMaxBone(void)
   mbstowcs(wname, _egg_joint->get_name().c_str(), 1023);
   _node->SetName(wname);
 #else
-  _node->SetName(_egg_joint->get_name().c_str());
+  _node->SetName((char*) _egg_joint->get_name().c_str());
 #endif
 
   _node->SetObjOffsetRot(ooquat);