Browse Source

Merge branch 'master' into webgl-port

Conflicts:
	panda/src/glstuff/glShaderContext_src.cxx
rdb 10 years ago
parent
commit
5afcbfc48e
100 changed files with 4129 additions and 1990 deletions
  1. 2 1
      direct/src/actor/Actor.py
  2. 11 2
      direct/src/directscripts/extract_docs.py
  3. 8 0
      direct/src/plugin/p3dCert.cxx
  4. 4 3
      direct/src/showbase/PythonUtil.py
  5. 10 1
      doc/man/pview.1
  6. 237 236
      dtool/metalibs/dtoolconfig/pydtool.cxx
  7. 13 5
      dtool/src/cppparser/cppExpression.cxx
  8. 1 1
      dtool/src/cppparser/cppInstance.cxx
  9. 13 0
      dtool/src/cppparser/cppTypedefType.cxx
  10. 1 1
      dtool/src/dtoolbase/atomicAdjustGccImpl.h
  11. 1 1
      dtool/src/dtoolbase/p3dtoolbase_composite2.cxx
  12. 2 2
      dtool/src/dtoolbase/pallocator.T
  13. 0 0
      dtool/src/dtoolbase/pdtoa.cxx
  14. 2 2
      dtool/src/dtoolbase/typeHandle.cxx
  15. 4 4
      dtool/src/dtoolbase/typeHandle.h
  16. 5 0
      dtool/src/dtoolutil/string_utils.I
  17. 1 0
      dtool/src/dtoolutil/string_utils.h
  18. 13 19
      dtool/src/interrogate/interfaceMakerPythonNative.cxx
  19. 1 1
      dtool/src/interrogate/interfaceMakerPythonNative.h
  20. 170 21
      panda/src/bullet/bulletBodyNode.cxx
  21. 13 3
      panda/src/bullet/bulletBodyNode.h
  22. 64 1
      panda/src/bullet/bulletBoxShape.cxx
  23. 11 1
      panda/src/bullet/bulletBoxShape.h
  24. 100 4
      panda/src/bullet/bulletConvexHullShape.cxx
  25. 8 2
      panda/src/bullet/bulletConvexHullShape.h
  26. 67 0
      panda/src/bullet/bulletDebugNode.cxx
  27. 8 1
      panda/src/bullet/bulletDebugNode.h
  28. 68 1
      panda/src/bullet/bulletPlaneShape.cxx
  29. 11 1
      panda/src/bullet/bulletPlaneShape.h
  30. 99 0
      panda/src/bullet/bulletRigidBodyNode.cxx
  31. 11 2
      panda/src/bullet/bulletRigidBodyNode.h
  32. 5 3
      panda/src/bullet/bulletShape.h
  33. 61 1
      panda/src/bullet/bulletSphereShape.cxx
  34. 11 1
      panda/src/bullet/bulletSphereShape.h
  35. 122 0
      panda/src/bullet/bulletTriangleMesh.cxx
  36. 12 5
      panda/src/bullet/bulletTriangleMesh.h
  37. 116 1
      panda/src/bullet/bulletTriangleMeshShape.cxx
  38. 16 1
      panda/src/bullet/bulletTriangleMeshShape.h
  39. 10 0
      panda/src/bullet/config_bullet.cxx
  40. 18 10
      panda/src/display/get_x11.h
  41. 48 0
      panda/src/display/graphicsOutput.I
  42. 3 0
      panda/src/display/graphicsOutput.h
  43. 26 0
      panda/src/display/graphicsStateGuardian.I
  44. 15 0
      panda/src/display/graphicsStateGuardian.cxx
  45. 4 0
      panda/src/display/graphicsStateGuardian.h
  46. 4 18
      panda/src/display/graphicsWindow.cxx
  47. 3 3
      panda/src/display/pStatGPUTimer.I
  48. 23 12
      panda/src/display/windowProperties.I
  49. 4 0
      panda/src/display/windowProperties.cxx
  50. 1 0
      panda/src/display/windowProperties.h
  51. 136 0
      panda/src/egg/eggTexture.I
  52. 20 0
      panda/src/egg/eggTexture.h
  53. 9 0
      panda/src/egg/parser.yxx
  54. 39 23
      panda/src/egg2pg/eggLoader.cxx
  55. 1 3
      panda/src/glstuff/glCgShaderContext_src.cxx
  56. 77 13
      panda/src/glstuff/glGeomMunger_src.cxx
  57. 35 7
      panda/src/glstuff/glGraphicsBuffer_src.cxx
  58. 4 1
      panda/src/glstuff/glGraphicsBuffer_src.h
  59. 211 41
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  60. 15 0
      panda/src/glstuff/glGraphicsStateGuardian_src.h
  61. 1074 700
      panda/src/glstuff/glShaderContext_src.cxx
  62. 17 3
      panda/src/glstuff/glShaderContext_src.h
  63. 1 0
      panda/src/glstuff/glTextureContext_src.I
  64. 10 0
      panda/src/glstuff/glTextureContext_src.cxx
  65. 3 0
      panda/src/glstuff/glTextureContext_src.h
  66. 15 0
      panda/src/glstuff/glmisc_src.cxx
  67. 3 0
      panda/src/glstuff/glmisc_src.h
  68. 6 1
      panda/src/gobj/config_gobj.cxx
  69. 1 0
      panda/src/gobj/config_gobj.h
  70. 12 0
      panda/src/gobj/geomEnums.cxx
  71. 8 4
      panda/src/gobj/geomEnums.h
  72. 2 0
      panda/src/gobj/geomPrimitive.cxx
  73. 17 0
      panda/src/gobj/geomVertexArrayFormat.cxx
  74. 12 293
      panda/src/gobj/geomVertexColumn.I
  75. 375 129
      panda/src/gobj/geomVertexColumn.cxx
  76. 25 34
      panda/src/gobj/geomVertexColumn.h
  77. 144 0
      panda/src/gobj/geomVertexData.I
  78. 16 4
      panda/src/gobj/geomVertexData.cxx
  79. 6 1
      panda/src/gobj/geomVertexData.h
  80. 0 84
      panda/src/gobj/geomVertexWriter.I
  81. 0 6
      panda/src/gobj/geomVertexWriter.h
  82. 1 1
      panda/src/gobj/shader.I
  83. 69 14
      panda/src/gobj/shader.cxx
  84. 5 0
      panda/src/gobj/shader.h
  85. 54 0
      panda/src/gobj/texture.I
  86. 39 6
      panda/src/gobj/texture.cxx
  87. 7 0
      panda/src/gobj/texture.h
  88. 4 0
      panda/src/grutil/frameRateMeter.cxx
  89. 45 0
      panda/src/linmath/lcast_to_src.I
  90. 27 0
      panda/src/linmath/lcast_to_src.h
  91. 2 0
      panda/src/mathutil/boundingVolume.h
  92. 2 0
      panda/src/mathutil/geometricBoundingVolume.h
  93. 7 28
      panda/src/pgraph/shaderAttrib.cxx
  94. 1 2
      panda/src/pgraph/shaderAttrib.h
  95. 32 197
      panda/src/pgraph/shaderInput.I
  96. 64 4
      panda/src/pgraph/shaderInput.cxx
  97. 8 13
      panda/src/pgraph/shaderInput.h
  98. 1 1
      panda/src/pgraphnodes/shaderGenerator.cxx
  99. 3 3
      panda/src/pnmimage/convert_srgb.I
  100. 3 3
      panda/src/pnmimage/convert_srgb.h

+ 2 - 1
direct/src/actor/Actor.py

@@ -4,6 +4,7 @@ __all__ = ['Actor']
 
 from pandac.PandaModules import *
 from direct.showbase.DirectObject import DirectObject
+from direct.directnotify import DirectNotifyGlobal
 from pandac.PandaModules import LODNode
 import types, copy
 
@@ -12,7 +13,7 @@ class Actor(DirectObject, NodePath):
     Actor class: Contains methods for creating, manipulating
     and playing animations on characters
     """
-    notify = directNotify.newCategory("Actor")
+    notify = DirectNotifyGlobal.directNotify.newCategory("Actor")
     partPrefix = "__Actor_"
 
     modelLoaderOptions = LoaderOptions(LoaderOptions.LFSearch |

+ 11 - 2
direct/src/directscripts/extract_docs.py

@@ -135,6 +135,8 @@ def translated_type_name(type, scoped=True):
     typename = interrogate_type_name(type)
     if typename in ("PyObject", "_object"):
         return "object"
+    elif typename == "PN_stdfloat":
+        return "float"
 
     if interrogate_type_is_atomic(type):
         token = interrogate_type_atomic_token(type)
@@ -143,7 +145,9 @@ def translated_type_name(type, scoped=True):
         else:
             return typename
 
-    typename = translateTypeName(typename)
+    if not typename.endswith('_t'):
+        # Hack: don't mangle size_t etc.
+        typename = translateTypeName(typename)
 
     if scoped and interrogate_type_is_nested(type):
         return translated_type_name(interrogate_type_outer_class(type)) + '::' + typename
@@ -203,6 +207,11 @@ def processType(handle, type):
             if docstring:
                 print >>handle, docstring
             print >>handle, interrogate_type_enum_value_name(type, i_value), "=", interrogate_type_enum_value(type, i_value), ","
+
+    elif interrogate_type_is_typedef(type):
+        wrapped_type = translated_type_name(interrogate_type_wrapped_type(type))
+        print >>handle, "typedef %s %s;" % (wrapped_type, typename)
+        return
     else:
         if interrogate_type_is_struct(type):
             classtype = "struct"
@@ -211,7 +220,7 @@ def processType(handle, type):
         elif interrogate_type_is_union(type):
             classtype = "union"
         else:
-            print "I don't know what type %s is" % typename
+            print "I don't know what type %s is" % interrogate_type_true_name(type)
             return
         
         if len(derivations) > 0:

+ 8 - 0
direct/src/plugin/p3dCert.cxx

@@ -157,6 +157,10 @@ AuthDialog(const string &cert_filename, const string &cert_dir) :
   _stack = NULL;
   _verify_result = -1;
 
+  // Center the window on the screen.
+  position((Fl::w() - w()) / 2, (Fl::h() - h()) / 2);
+  set_modal();
+
   read_cert_file(cert_filename);
   get_friendly_name();
   verify_cert();
@@ -583,6 +587,10 @@ ViewCertDialog(AuthDialog *auth_dialog, X509 *cert) :
   _auth_dialog(auth_dialog),
   _cert(cert)
 {
+  // Center the window on the screen.
+  position((Fl::w() - w()) / 2, (Fl::h() - h()) / 2);
+  set_modal();
+
   layout();
 }
 

+ 4 - 3
direct/src/showbase/PythonUtil.py

@@ -1429,11 +1429,12 @@ dtoolSuperBase = None
 
 def _getDtoolSuperBase():
     global dtoolSuperBase
-    from panda3d.core import PandaNode
-    dtoolSuperBase = PandaNode('').__class__.__bases__[0].__bases__[0].__bases__[0]
+    from panda3d.core import TypedObject
+    dtoolSuperBase = TypedObject.__bases__[0]
     assert repr(dtoolSuperBase) == "<type 'libdtoolconfig.DTOOL_SUPER_BASE111'>" \
         or repr(dtoolSuperBase) == "<type 'libdtoolconfig.DTOOL_SUPPER_BASE111'>" \
-        or repr(dtoolSuperBase) == "<type 'dtoolconfig.DTOOL_SUPER_BASE111'>"
+        or repr(dtoolSuperBase) == "<type 'dtoolconfig.DTOOL_SUPER_BASE111'>" \
+        or repr(dtoolSuperBase) == "<type 'dtoolconfig.DTOOL_SUPER_BASE'>"
 
 safeReprNotify = None
 

+ 10 - 1
doc/man/pview.1

@@ -1,4 +1,4 @@
-.TH PVIEW 1 "27 December 2014" "" Panda3D
+.TH PVIEW 1 "1 May 2015" "" Panda3D
 .SH NAME
 pview \- quickly view a Panda model and/or animation
 .SH SYNOPSIS
@@ -43,6 +43,15 @@ exit.
 Delete the model files after loading them (presumably this option
 will only be used when loading a temporary model file).
 .TP
+.B \-L
+Enable lighting in the scene.  This can also be achieved with 
+the 'l' hotkey at runtime.
+.TP
+.BI "\-P " pipename
+Select the given graphics pipe for the window, rather than using
+the platform default.  The allowed values for <pipe> are those 
+from the Config.prc variables 'load-display' and 'aux-display'.
+.TP
 .B \-V
 Report the current version of Panda, and exit.
 .TP

File diff suppressed because it is too large
+ 237 - 236
dtool/metalibs/dtoolconfig/pydtool.cxx


+ 13 - 5
dtool/src/cppparser/cppExpression.cxx

@@ -26,6 +26,7 @@
 #include "cppFunctionGroup.h"
 #include "cppFunctionType.h"
 #include "cppBison.h"
+#include "pdtoa.h"
 
 #include <assert.h>
 
@@ -1079,7 +1080,13 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
     break;
 
   case T_real:
-    out << _u._real;
+    {
+      // We use our own dtoa implementation here because it guarantees
+      // to never format the number as an integer.
+      char buffer[32];
+      pdtoa(_u._real, buffer);
+      out << buffer;
+    }
     break;
 
   case T_string:
@@ -1155,14 +1162,15 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
     break;
 
   case T_construct:
-    out << "(" << _u._typecast._to->get_typedef_name(scope)
-        << "(";
+    _u._typecast._to->output(out, indent_level, scope, false);
+    out << "(";
     _u._typecast._op1->output(out, indent_level, scope, false);
-    out << "))";
+    out << ")";
     break;
 
   case T_default_construct:
-    out << "(" << _u._typecast._to->get_typedef_name(scope) << "())";
+    _u._typecast._to->output(out, indent_level, scope, false);
+    out << "()";
     break;
 
   case T_new:

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

@@ -558,7 +558,7 @@ output(ostream &out, int indent_level, CPPScope *scope, bool complete,
     out << " = 0";
   }
   if (_initializer != NULL) {
-    out << " = (" << *_initializer << ")";
+    out << " = " << *_initializer;
   }
 }
 

+ 13 - 0
dtool/src/cppparser/cppTypedefType.cxx

@@ -204,6 +204,19 @@ CPPDeclaration *CPPTypedefType::
 substitute_decl(CPPDeclaration::SubstDecl &subst,
                 CPPScope *current_scope, CPPScope *global_scope) {
 
+  if (_ident != NULL && _ident->get_scope(current_scope, global_scope) == global_scope) {
+    // Hack... I know that size_t etc is supposed to work fine, so
+    // preserve these top-level typedefs.
+    CPPDeclaration *top =
+      CPPType::substitute_decl(subst, current_scope, global_scope);
+    if (top != this) {
+      return top;
+    }
+    top = new CPPTypedefType(*this);
+    subst.insert(SubstDecl::value_type(this, top));
+    return top;
+  }
+
   return _type->substitute_decl(subst, current_scope, global_scope);
 
   // Bah, this doesn't seem to work, and I can't figure out why.

+ 1 - 1
dtool/src/dtoolbase/atomicAdjustGccImpl.h

@@ -26,7 +26,7 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_DTOOL AtomicAdjustGccImpl {
 public:
-#if __GCC_ATOMIC_LONG_LOCK_FREE > __GCC_ATOMIC_INT_LOCK_FREE
+#if __GCC_ATOMIC_LONG_LOCK_FREE >= __GCC_ATOMIC_INT_LOCK_FREE
   // If the long can be more lock-free than int, use it instead.
   typedef __attribute__ ((aligned (__SIZEOF_LONG__))) long Integer;
 #else

+ 1 - 1
dtool/src/dtoolbase/p3dtoolbase_composite2.cxx

@@ -2,7 +2,7 @@
 #include "mutexWin32Impl.cxx"
 #include "mutexSpinlockImpl.cxx"
 #include "neverFreeMemory.cxx"
-#include "pdtoa.c"
+#include "pdtoa.cxx"
 #include "pstrtod.cxx"
 #include "register_type.cxx"
 #include "typeHandle.cxx"

+ 2 - 2
dtool/src/dtoolbase/pallocator.T

@@ -51,7 +51,7 @@ allocate(TYPENAME pallocator_array<Type>::size_type n, TYPENAME allocator<void>:
   size_t alloc_size = n * sizeof(Type);
   // We also need to store the total number of bytes we allocated.
   alloc_size += header_reserved_bytes;
-  _type_handle.inc_memory_usage(TypeHandle::MC_array, (int)alloc_size);
+  _type_handle.inc_memory_usage(TypeHandle::MC_array, alloc_size);
   void *ptr = (TYPENAME pallocator_array<Type>::pointer)PANDA_MALLOC_ARRAY(alloc_size);
   *((size_t *)ptr) = alloc_size;
   return (TYPENAME pallocator_array<Type>::pointer)(((char *)ptr) + header_reserved_bytes);
@@ -69,7 +69,7 @@ deallocate(TYPENAME pallocator_array<Type>::pointer p, TYPENAME pallocator_array
   const size_t header_reserved_bytes = MemoryHook::get_header_reserved_bytes();
   void *ptr = (void *)((char *)p - header_reserved_bytes);
   size_t alloc_size = *((size_t *)ptr);
-  _type_handle.dec_memory_usage(TypeHandle::MC_array, (int)alloc_size);
+  _type_handle.dec_memory_usage(TypeHandle::MC_array, alloc_size);
   PANDA_FREE_ARRAY(ptr);
 #else
   free(p);

+ 0 - 0
dtool/src/dtoolbase/pdtoa.c → dtool/src/dtoolbase/pdtoa.cxx


+ 2 - 2
dtool/src/dtoolbase/typeHandle.cxx

@@ -49,7 +49,7 @@ get_memory_usage(MemoryClass memory_class) const {
 //               allocated memory for objects of this type.
 ////////////////////////////////////////////////////////////////////
 void TypeHandle::
-inc_memory_usage(MemoryClass memory_class, int size) {
+inc_memory_usage(MemoryClass memory_class, size_t size) {
   assert((int)memory_class >= 0 && (int)memory_class < (int)MC_limit);
   if ((*this) != TypeHandle::none()) {
     TypeRegistryNode *rnode = TypeRegistry::ptr()->look_up(*this, NULL);
@@ -72,7 +72,7 @@ inc_memory_usage(MemoryClass memory_class, int size) {
 //               the total allocated memory for objects of this type.
 ////////////////////////////////////////////////////////////////////
 void TypeHandle::
-dec_memory_usage(MemoryClass memory_class, int size) {
+dec_memory_usage(MemoryClass memory_class, size_t size) {
   assert((int)memory_class >= 0 && (int)memory_class < (int)MC_limit);
   if ((*this) != TypeHandle::none()) {
     TypeRegistryNode *rnode = TypeRegistry::ptr()->look_up(*this, NULL);

+ 4 - 4
dtool/src/dtoolbase/typeHandle.h

@@ -125,12 +125,12 @@ PUBLISHED:
 
 #ifdef DO_MEMORY_USAGE
   int get_memory_usage(MemoryClass memory_class) const;
-  void inc_memory_usage(MemoryClass memory_class, int size);
-  void dec_memory_usage(MemoryClass memory_class, int size);
+  void inc_memory_usage(MemoryClass memory_class, size_t size);
+  void dec_memory_usage(MemoryClass memory_class, size_t size);
 #else
   static CONSTEXPR int get_memory_usage(MemoryClass) { return 0; }
-  INLINE void inc_memory_usage(MemoryClass, int) { }
-  INLINE void dec_memory_usage(MemoryClass, int) { }
+  INLINE void inc_memory_usage(MemoryClass, size_t) { }
+  INLINE void dec_memory_usage(MemoryClass, size_t) { }
 #endif  // DO_MEMORY_USAGE
 
   INLINE int get_index() const;

+ 5 - 0
dtool/src/dtoolutil/string_utils.I

@@ -26,6 +26,11 @@ format_string(const string &value) {
   return value;
 }
 
+INLINE string
+format_string(bool value) {
+  return string(value ? "true" : "false");
+}
+
 INLINE string
 format_string(float value) {
   char buffer[32];

+ 1 - 0
dtool/src/dtoolutil/string_utils.h

@@ -69,6 +69,7 @@ INLINE string format_string(const Thing &thing);
 
 // Fast specializations for some primitive types.
 INLINE string format_string(const string &value);
+INLINE string format_string(bool value);
 INLINE string format_string(float value);
 INLINE string format_string(double value);
 INLINE string format_string(unsigned int value);

+ 13 - 19
dtool/src/interrogate/interfaceMakerPythonNative.cxx

@@ -720,11 +720,16 @@ get_valid_child_classes(std::map<std::string, CastDetails> &answer, CPPStructTyp
 ///////////////////////////////////////////////////////////////////////////////
 void InterfaceMakerPythonNative::
 write_python_instance(ostream &out, int indent_level, const string &return_expr,
-                      bool owns_memory, const string &class_name,
-                      CPPType *ctype, bool is_const) {
+                      bool owns_memory, const InterrogateType &itype, bool is_const) {
   out << boolalpha;
 
-  if (IsPandaTypedObject(ctype->as_struct_type())) {
+  if (!isExportThisRun(itype._cpptype)) {
+    _external_imports.insert(itype._cpptype);
+  }
+
+  string class_name = itype.get_scoped_name();
+
+  if (IsPandaTypedObject(itype._cpptype->as_struct_type())) {
     // We can't let DTool_CreatePyInstanceTyped do the NULL check since we
     // will be grabbing the type index (which would obviously crash when called
     // on a NULL pointer), so we do it here.
@@ -2636,7 +2641,7 @@ write_module_class(ostream &out, Object *obj) {
     write_function_slot(out, 2, slots, "bf_getsegcount");
     write_function_slot(out, 2, slots, "bf_getcharbuffer");
     out << "#endif\n";
-    out << "#if PY_MAJOR_VERSION >= 0x02060000\n";
+    out << "#if PY_VERSION_HEX >= 0x02060000\n";
     write_function_slot(out, 2, slots, "bf_getbuffer");
     write_function_slot(out, 2, slots, "bf_releasebuffer");
     out << "#endif\n";
@@ -6046,31 +6051,19 @@ pack_return_value(ostream &out, int indent_level, FunctionRemap *remap,
         TypeIndex type_index = builder.get_type(TypeManager::unwrap(TypeManager::resolve_type(type)),false);
         const InterrogateType &itype = idb->get_type(type_index);
 
-        if (!isExportThisRun(itype._cpptype)) {
-          _external_imports.insert(itype._cpptype);
-        }
-
-        write_python_instance(out, indent_level, return_expr, owns_memory, itype.get_scoped_name(), itype._cpptype, is_const);
+        write_python_instance(out, indent_level, return_expr, owns_memory, itype, is_const);
 
       } else {
         TypeIndex type_index = builder.get_type(TypeManager::unwrap(TypeManager::resolve_type(orig_type)),false);
         const InterrogateType &itype = idb->get_type(type_index);
 
-        if (!isExportThisRun(itype._cpptype)) {
-          _external_imports.insert(itype._cpptype);
-        }
-
-        write_python_instance(out, indent_level, return_expr, owns_memory, itype.get_scoped_name(), itype._cpptype, is_const);
+        write_python_instance(out, indent_level, return_expr, owns_memory, itype, is_const);
       }
     } else if (TypeManager::is_struct(orig_type->as_pointer_type()->_pointing_at)) {
       TypeIndex type_index = builder.get_type(TypeManager::unwrap(TypeManager::resolve_type(orig_type)),false);
       const InterrogateType &itype = idb->get_type(type_index);
 
-      if (!isExportThisRun(itype._cpptype)) {
-        _external_imports.insert(itype._cpptype);
-      }
-
-      write_python_instance(out, indent_level, return_expr, owns_memory, itype.get_scoped_name(), itype._cpptype, is_const);
+      write_python_instance(out, indent_level, return_expr, owns_memory, itype, is_const);
 
     } else {
       indent(out, indent_level) << "Should Never Reach This InterfaceMakerPythonNative::pack_python_value";
@@ -6638,6 +6631,7 @@ HasAGetClassTypeFunction(const InterrogateType &itype_class) {
 
   int num_methods = itype_class.number_of_methods();
   int mi;
+
   for (mi = 0; mi < num_methods; mi++) {
     FunctionIndex func_index = itype_class.get_method(mi);
     const InterrogateFunction &ifunc = idb->get_function(func_index);

+ 1 - 1
dtool/src/interrogate/interfaceMakerPythonNative.h

@@ -198,7 +198,7 @@ public:
   void get_valid_child_classes(std::map<std::string, CastDetails> &answer, CPPStructType *inclass, const std::string &upcast_seed = "", bool can_downcast = true);
   bool DoesInheritFromIsClass(const CPPStructType * inclass, const std::string &name);
   bool IsPandaTypedObject(CPPStructType * inclass) { return DoesInheritFromIsClass(inclass,"TypedObject"); };
-  void write_python_instance(ostream &out, int indent_level, const std::string &return_expr, bool owns_memory, const std::string &class_name, CPPType *ctype, bool is_const);
+  void write_python_instance(ostream &out, int indent_level, const std::string &return_expr, bool owns_memory, const InterrogateType &itype, bool is_const);
   bool HasAGetClassTypeFunction(const InterrogateType &itype_class);
   int NeedsAStrFunction(const InterrogateType &itype_class);
   int NeedsAReprFunction(const InterrogateType &itype_class);

+ 170 - 21
panda/src/bullet/bulletBodyNode.cxx

@@ -155,6 +155,8 @@ output(ostream &out) const {
 
   out << " (" << get_num_shapes() << " shapes)";
 
+  out << (is_active() ? " active" : " inactive");
+
   if (is_static()) out << " static";
   if (is_kinematic()) out << " kinematic";
 }
@@ -165,13 +167,16 @@ output(ostream &out) const {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void BulletBodyNode::
-add_shape(BulletShape *shape, const TransformState *ts) {
+add_shape(BulletShape *bullet_shape, const TransformState *ts) {
 
   nassertv(get_object());
   nassertv(ts);
 
-  nassertv(!(shape->ptr()->getShapeType() == CONVEX_HULL_SHAPE_PROXYTYPE 
-    && ((btConvexHullShape *)shape->ptr())->getNumVertices() == 0));
+  btCollisionShape *shape = bullet_shape->ptr();
+  nassertv(shape != NULL);
+
+  nassertv(!(shape->getShapeType() == CONVEX_HULL_SHAPE_PROXYTYPE &&
+            ((btConvexHullShape *)shape)->getNumVertices() == 0));
 
   // Transform
   btTransform trans = TransformState_to_btTrans(ts);
@@ -193,13 +198,13 @@ add_shape(BulletShape *shape, const TransformState *ts) {
       // After adding the shape we will have one shape, but with transform.
       // We need to wrap the shape within a compound shape, in oder to
       // be able to set the local transform.
-      next = shape->ptr();
+      next = shape;
     }
     else {
       // After adding the shape we will have a total of one shape, without 
       // local transform. We can set the shape directly.
       next = new btCompoundShape();
-      ((btCompoundShape *)next)->addChildShape(trans, shape->ptr());
+      ((btCompoundShape *)next)->addChildShape(trans, shape);
     }
 
     get_object()->setCollisionShape(next);
@@ -214,7 +219,7 @@ add_shape(BulletShape *shape, const TransformState *ts) {
       // to the compound shape.
       next = previous;
 
-      ((btCompoundShape *)next)->addChildShape(trans, shape->ptr());
+      ((btCompoundShape *)next)->addChildShape(trans, shape);
     }
     else {
       // We have one shape which is NOT a compound shape, and want to add
@@ -223,7 +228,7 @@ add_shape(BulletShape *shape, const TransformState *ts) {
 
       btTransform previous_trans = btTransform::getIdentity();
       ((btCompoundShape *)next)->addChildShape(previous_trans, previous);
-      ((btCompoundShape *)next)->addChildShape(trans, shape->ptr());
+      ((btCompoundShape *)next)->addChildShape(trans, shape);
 
       get_object()->setCollisionShape(next);
       _shape = next;
@@ -236,10 +241,10 @@ add_shape(BulletShape *shape, const TransformState *ts) {
     nassertv(previous->getShapeType() == COMPOUND_SHAPE_PROXYTYPE);
 
     next = previous;
-    ((btCompoundShape *)next)->addChildShape(trans, shape->ptr());
+    ((btCompoundShape *)next)->addChildShape(trans, shape);
   }
 
-  _shapes.push_back(shape);
+  _shapes.push_back(bullet_shape);
 
   // Restore the local scaling again
   np.set_scale(scale);
@@ -340,7 +345,16 @@ LPoint3 BulletBodyNode::
 get_shape_pos(int idx) const {
 
   nassertr(idx >= 0 && idx < (int)_shapes.size(), LPoint3::zero());
-  return get_shape_mat(idx).get_row3(3);
+
+  btCollisionShape *root = get_object()->getCollisionShape();
+  if (root->getShapeType() == COMPOUND_SHAPE_PROXYTYPE) {
+    btCompoundShape *compound = (btCompoundShape *)root;
+
+    btTransform trans = compound->getChildTransform(idx);
+    return btVector3_to_LVector3(trans.getOrigin());
+  }
+
+  return LPoint3::zero();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -350,15 +364,24 @@ get_shape_pos(int idx) const {
 ////////////////////////////////////////////////////////////////////
 LMatrix4 BulletBodyNode::
 get_shape_mat(int idx) const {
+  return get_shape_transform(idx)->get_mat();
+}
 
-  nassertr(idx >= 0 && idx < (int)_shapes.size(), LMatrix4::ident_mat());
+////////////////////////////////////////////////////////////////////
+//     Function: BulletBodyNode::get_shape_transform
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+CPT(TransformState) BulletBodyNode::
+get_shape_transform(int idx) const {
+  nassertr(idx >= 0 && idx < (int)_shapes.size(), TransformState::make_identity());
 
   btCollisionShape *root = get_object()->getCollisionShape();
   if (root->getShapeType() == COMPOUND_SHAPE_PROXYTYPE) {
     btCompoundShape *compound = (btCompoundShape *)root;
 
     btTransform trans = compound->getChildTransform(idx);
-    return btTrans_to_LMatrix4(trans);
+    return btTrans_to_TransformState(trans);
 
     // The above code assumes that shape's index in _shapes member
     // is the same as the shapes index within the compound. If it
@@ -375,7 +398,7 @@ get_shape_mat(int idx) const {
     */
   }
 
-  return LMatrix4::ident_mat();
+  return TransformState::make_identity();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -448,19 +471,22 @@ set_active(bool active, bool force) {
 ////////////////////////////////////////////////////////////////////
 //     Function: BulletBodyNode::set_deactivation_enabled
 //       Access: Published
-//  Description:
+//  Description: If true, this object will be deactivated after a
+//               certain amount of time has passed without movement.
+//               If false, the object will always remain active.
 ////////////////////////////////////////////////////////////////////
 void BulletBodyNode::
-set_deactivation_enabled(const bool enabled, const bool force) {
+set_deactivation_enabled(bool enabled) {
 
-  int state = (enabled) ? WANTS_DEACTIVATION : DISABLE_DEACTIVATION;
+  // Don't change the state if it's currently active and we enable
+  // deactivation.
+  if (enabled != is_deactivation_enabled()) {
 
-  if (force) {
+    // It's OK to set to ACTIVE_TAG even if we don't mean to activate it; it
+    // will be disabled right away if the deactivation timer has run out.
+    int state = (enabled) ? ACTIVE_TAG : DISABLE_DEACTIVATION;
     get_object()->forceActivationState(state);
   }
-  else {
-    get_object()->setActivationState(state);
-  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -471,7 +497,7 @@ set_deactivation_enabled(const bool enabled, const bool force) {
 bool BulletBodyNode::
 is_deactivation_enabled() const {
 
-  return (get_object()->getActivationState() & DISABLE_DEACTIVATION) == 0;
+  return (get_object()->getActivationState() != DISABLE_DEACTIVATION);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -700,3 +726,126 @@ cout << "origin " << aabbMin.x() << " " << aabbMin.y() << " " << aabbMin.z() <<
   return bounds;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BulletBodyNode::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void BulletBodyNode::
+write_datagram(BamWriter *manager, Datagram &dg) {
+  PandaNode::write_datagram(manager, dg);
+
+  dg.add_bool(is_static());
+  dg.add_bool(is_kinematic());
+  dg.add_bool(notifies_collisions());
+  dg.add_bool(get_collision_response());
+  dg.add_stdfloat(get_contact_processing_threshold());
+  //dg.add_bool(is_active());
+  dg.add_stdfloat(get_deactivation_time());
+  dg.add_bool(is_deactivation_enabled());
+  //dg.add_bool(is_debug_enabled());
+  dg.add_stdfloat(get_restitution());
+  dg.add_stdfloat(get_friction());
+#if BT_BULLET_VERSION >= 281
+  dg.add_stdfloat(get_rolling_friction());
+#else
+  dg.add_stdfloat(0);
+#endif
+  if (has_anisotropic_friction()) {
+    dg.add_bool(true);
+    get_anisotropic_friction().write_datagram(dg);
+  } else {
+    dg.add_bool(false);
+  }
+  dg.add_stdfloat(get_ccd_swept_sphere_radius());
+  dg.add_stdfloat(get_ccd_motion_threshold());
+
+  for (int i = 0; i < _shapes.size(); ++i) {
+    manager->write_pointer(dg, get_shape(i));
+    manager->write_pointer(dg, get_shape_transform(i));
+  }
+
+  // Write NULL pointer to indicate the end of the list.
+  manager->write_pointer(dg, NULL);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletBodyNode::complete_pointers
+//       Access: Public, Virtual
+//  Description: Receives an array of pointers, one for each time
+//               manager->read_pointer() was called in fillin().
+//               Returns the number of pointers processed.
+////////////////////////////////////////////////////////////////////
+int BulletBodyNode::
+complete_pointers(TypedWritable **p_list, BamReader *manager) {
+  int pi = PandaNode::complete_pointers(p_list, manager);
+
+  PT(BulletShape) shape = DCAST(BulletShape, p_list[pi++]);
+
+  while (shape != (BulletShape *)NULL) {
+    const TransformState *trans = DCAST(TransformState, p_list[pi++]);
+    add_shape(shape, trans);
+
+    shape = DCAST(BulletShape, p_list[pi++]);
+  }
+
+  return pi;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletBodyNode::require_fully_complete
+//       Access: Public, Virtual
+//  Description: Some objects require all of their nested pointers to
+//               have been completed before the objects themselves can
+//               be completed.  If this is the case, override this
+//               method to return true, and be careful with circular
+//               references (which would make the object unreadable
+//               from a bam file).
+////////////////////////////////////////////////////////////////////
+bool BulletBodyNode::
+require_fully_complete() const {
+  // We require the shape pointers to be complete before we add them.
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletBodyNode::fillin
+//       Access: Protected
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new BulletBodyNode.
+////////////////////////////////////////////////////////////////////
+void BulletBodyNode::
+fillin(DatagramIterator &scan, BamReader *manager) {
+  PandaNode::fillin(scan, manager);
+
+  set_static(scan.get_bool());
+  set_kinematic(scan.get_bool());
+  notify_collisions(scan.get_bool());
+  set_collision_response(scan.get_bool());
+  set_contact_processing_threshold(scan.get_stdfloat());
+  //set_active(scan.get_bool(), true);
+  set_deactivation_time(scan.get_stdfloat());
+  set_deactivation_enabled(scan.get_bool());
+  set_restitution(scan.get_stdfloat());
+  set_friction(scan.get_stdfloat());
+#if BT_BULLET_VERSION >= 281
+  set_rolling_friction(scan.get_stdfloat());
+#else
+  scan.get_stdfloat();
+#endif
+  if (scan.get_bool()) {
+    LVector3 friction;
+    friction.read_datagram(scan);
+    set_anisotropic_friction(friction);
+  }
+  set_ccd_swept_sphere_radius(scan.get_stdfloat());
+  set_ccd_motion_threshold(scan.get_stdfloat());
+
+  // Read shapes.  The list is bounded by a NULL pointer.
+  while (manager->read_pointer(scan)) {
+    // Each shape comes with a TransformState.
+    manager->read_pointer(scan);
+  }
+}

+ 13 - 3
panda/src/bullet/bulletBodyNode.h

@@ -33,9 +33,10 @@ class BulletShape;
 // Description : 
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDABULLET BulletBodyNode : public PandaNode {
+protected:
+  BulletBodyNode(const char *name);
 
 PUBLISHED:
-  BulletBodyNode(const char *name);
   INLINE ~BulletBodyNode();
 
   // Shapes
@@ -48,6 +49,7 @@ PUBLISHED:
 
   LPoint3 get_shape_pos(int idx) const;
   LMatrix4 get_shape_mat(int idx) const;
+  CPT(TransformState) get_shape_transform(int idx) const;
   BoundingSphere get_shape_bounds() const;
 
   void add_shapes_from_collision_solids(CollisionNode *cnode);
@@ -82,7 +84,7 @@ PUBLISHED:
   void set_deactivation_time(PN_stdfloat dt);
   PN_stdfloat get_deactivation_time() const;
 
-  void set_deactivation_enabled(const bool enabled, const bool force=false);
+  void set_deactivation_enabled(bool enabled);
   bool is_deactivation_enabled() const;
 
   // Debug Visualistion
@@ -142,7 +144,15 @@ private:
 
   static bool is_identity(btTransform &trans);
 
-////////////////////////////////////////////////////////////////////
+public:
+  virtual void write_datagram(BamWriter *manager, Datagram &dg);
+  virtual int complete_pointers(TypedWritable **plist,
+                                BamReader *manager);
+  virtual bool require_fully_complete() const;
+
+protected:
+  void fillin(DatagramIterator &scan, BamReader *manager);
+
 public:
   static TypeHandle get_class_type() {
     return _type_handle;

+ 64 - 1
panda/src/bullet/bulletBoxShape.cxx

@@ -66,7 +66,7 @@ get_half_extents_with_margin() const {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: BulletBoxShape::make_from_solid
-//       Access: Public
+//       Access: Public, Static
 //  Description:
 ////////////////////////////////////////////////////////////////////
 BulletBoxShape *BulletBoxShape::
@@ -82,3 +82,66 @@ make_from_solid(const CollisionBox *solid) {
   return new BulletBoxShape(extents);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BulletBoxShape::register_with_read_factory
+//       Access: Public, Static
+//  Description: Tells the BamReader how to create objects of type
+//               BulletShape.
+////////////////////////////////////////////////////////////////////
+void BulletBoxShape::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletBoxShape::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void BulletBoxShape::
+write_datagram(BamWriter *manager, Datagram &dg) {
+  dg.add_stdfloat(get_margin());
+  get_half_extents_with_margin().write_datagram(dg);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletBoxShape::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of type BulletShape is encountered
+//               in the Bam file.  It should create the BulletShape
+//               and extract its information from the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *BulletBoxShape::
+make_from_bam(const FactoryParams &params) {
+  BulletBoxShape *param = new BulletBoxShape;
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  param->fillin(scan, manager);
+
+  return param;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletBoxShape::fillin
+//       Access: Protected
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new BulletShape.
+////////////////////////////////////////////////////////////////////
+void BulletBoxShape::
+fillin(DatagramIterator &scan, BamReader *manager) {
+  nassertv(_shape == NULL);
+
+  PN_stdfloat margin = scan.get_stdfloat();
+
+  LVector3 half_extents;
+  half_extents.read_datagram(scan);
+
+  _shape = new btBoxShape(LVecBase3_to_btVector3(half_extents));
+  _shape->setUserPointer(this);
+  _shape->setMargin(margin);
+}

+ 11 - 1
panda/src/bullet/bulletBoxShape.h

@@ -29,6 +29,9 @@
 // Description : 
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDABULLET BulletBoxShape : public BulletShape {
+private:
+  // Only used by make_from_bam
+  INLINE BulletBoxShape() : _shape(NULL) {};
 
 PUBLISHED:
   BulletBoxShape(const LVecBase3 &halfExtents);
@@ -47,7 +50,14 @@ public:
 private:
   btBoxShape *_shape;
 
-////////////////////////////////////////////////////////////////////
+public:
+  static void register_with_read_factory();
+  virtual void write_datagram(BamWriter *manager, Datagram &dg);
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+  void fillin(DatagramIterator &scan, BamReader *manager);
+
 public:
   static TypeHandle get_class_type() {
     return _type_handle;

+ 100 - 4
panda/src/bullet/bulletConvexHullShape.cxx

@@ -66,10 +66,17 @@ add_array(const PTA_LVecBase3 &points) {
   _shape->setUserPointer(this);
 
   PTA_LVecBase3::const_iterator it;
-  for (it=points.begin(); it!=points.end(); it++) {
-    LVecBase3 v = *it;
-    _shape->addPoint(LVecBase3_to_btVector3(v));
+
+#if BT_BULLET_VERSION >= 282
+  for (it = points.begin(); it != points.end(); ++it) {
+    _shape->addPoint(LVecBase3_to_btVector3(*it), false);
   }
+  _shape->recalcLocalAabb();
+#else
+  for (it = points.begin(); it != points.end(); ++it) {
+    _shape->addPoint(LVecBase3_to_btVector3(*it));
+  }
+#endif
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -100,8 +107,97 @@ add_geom(const Geom *geom, const TransformState *ts) {
   _shape->setUserPointer(this);
 
   pvector<LPoint3>::const_iterator it;
-  for (it=points.begin(); it!=points.end(); it++) {
+
+#if BT_BULLET_VERSION >= 282
+  for (it = points.begin(); it != points.end(); ++it) {
+    LVecBase3 v = *it;
+    _shape->addPoint(LVecBase3_to_btVector3(*it), false);
+  }
+  _shape->recalcLocalAabb();
+#else
+  for (it = points.begin(); it != points.end(); ++it) {
+    LVecBase3 v = *it;
     _shape->addPoint(LVecBase3_to_btVector3(*it));
   }
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletConvexHullShape::register_with_read_factory
+//       Access: Public, Static
+//  Description: Tells the BamReader how to create objects of type
+//               BulletShape.
+////////////////////////////////////////////////////////////////////
+void BulletConvexHullShape::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletConvexHullShape::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void BulletConvexHullShape::
+write_datagram(BamWriter *manager, Datagram &dg) {
+  dg.add_stdfloat(get_margin());
+
+  unsigned int num_points = _shape->getNumPoints();
+  dg.add_uint32(num_points);
+
+  const btVector3 *points = _shape->getUnscaledPoints();
+
+  for (unsigned int i = 0; i < num_points; ++i) {
+    LVecBase3 point = btVector3_to_LVecBase3(points[i]);
+    point.write_datagram(dg);
+  }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BulletConvexHullShape::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of type BulletShape is encountered
+//               in the Bam file.  It should create the BulletShape
+//               and extract its information from the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *BulletConvexHullShape::
+make_from_bam(const FactoryParams &params) {
+  BulletConvexHullShape *param = new BulletConvexHullShape;
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  param->fillin(scan, manager);
+
+  return param;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletConvexHullShape::fillin
+//       Access: Protected
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new BulletShape.
+////////////////////////////////////////////////////////////////////
+void BulletConvexHullShape::
+fillin(DatagramIterator &scan, BamReader *manager) {
+  PN_stdfloat margin = scan.get_stdfloat();
+  unsigned int num_points = scan.get_uint32();
+
+#if BT_BULLET_VERSION >= 282
+  for (unsigned int i = 0; i < num_points; ++i) {
+    LVecBase3 point;
+    point.read_datagram(scan);
+    _shape->addPoint(LVecBase3_to_btVector3(point), false);
+  }
+  _shape->recalcLocalAabb();
+#else
+  for (unsigned int i = 0; i < num_points; ++i) {
+    LVecBase3 point;
+    point.read_datagram(scan);
+    _shape->addPoint(LVecBase3_to_btVector3(point));
+  }
+#endif
+}

+ 8 - 2
panda/src/bullet/bulletConvexHullShape.h

@@ -29,7 +29,6 @@
 // Description : 
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDABULLET BulletConvexHullShape : public BulletShape {
-
 PUBLISHED:
   BulletConvexHullShape();
   INLINE BulletConvexHullShape(const BulletConvexHullShape &copy);
@@ -47,7 +46,14 @@ public:
 private:
   btConvexHullShape *_shape;
 
-////////////////////////////////////////////////////////////////////
+public:
+  static void register_with_read_factory();
+  virtual void write_datagram(BamWriter *manager, Datagram &dg);
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+  void fillin(DatagramIterator &scan, BamReader *manager);
+
 public:
   static TypeHandle get_class_type() {
     return _type_handle;

+ 67 - 0
panda/src/bullet/bulletDebugNode.cxx

@@ -463,3 +463,70 @@ drawSphere(btScalar radius, const btTransform &transform, const btVector3 &color
   drawArc(center, zoffs, xoffs, radius, radius, 0, SIMD_2_PI, color, false, 10.0);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BulletDebugNode::register_with_read_factory
+//       Access: Public, Static
+//  Description: Tells the BamReader how to create objects of type
+//               BulletDebugNode.
+////////////////////////////////////////////////////////////////////
+void BulletDebugNode::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletDebugNode::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void BulletDebugNode::
+write_datagram(BamWriter *manager, Datagram &dg) {
+  // Don't upcall to GeomNode since we're not interested in storing
+  // the actual debug Geoms in the .bam file.
+  PandaNode::write_datagram(manager, dg);
+
+  dg.add_bool(_wireframe);
+  dg.add_bool(_constraints);
+  dg.add_bool(_bounds);
+  dg.add_bool(_drawer._normals);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletDebugNode::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of this type is encountered
+//               in the Bam file.  It should create the rigid body
+//               and extract its information from the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *BulletDebugNode::
+make_from_bam(const FactoryParams &params) {
+  BulletDebugNode *param = new BulletDebugNode;
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  param->fillin(scan, manager);
+
+  return param;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletDebugNode::fillin
+//       Access: Protected
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new BulletDebugNode.
+////////////////////////////////////////////////////////////////////
+void BulletDebugNode::
+fillin(DatagramIterator &scan, BamReader *manager) {
+  // Don't upcall to GeomNode since we're not interested in storing
+  // the actual debug Geoms in the .bam file.
+  PandaNode::fillin(scan, manager);
+
+  _wireframe = scan.get_bool();
+  _constraints = scan.get_bool();
+  _bounds = scan.get_bool();
+  _drawer._normals = scan.get_bool();
+}

+ 8 - 1
panda/src/bullet/bulletDebugNode.h

@@ -101,7 +101,14 @@ private:
 
   friend class BulletWorld;
 
-////////////////////////////////////////////////////////////////////
+public:
+  static void register_with_read_factory();
+  virtual void write_datagram(BamWriter *manager, Datagram &dg);
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+  void fillin(DatagramIterator &scan, BamReader *manager);
+
 public:
   static TypeHandle get_class_type() {
     return _type_handle;

+ 68 - 1
panda/src/bullet/bulletPlaneShape.cxx

@@ -43,7 +43,7 @@ ptr() const {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: BulletPlaneShape::make_from_solid
-//       Access: Public
+//       Access: Public, Static
 //  Description:
 ////////////////////////////////////////////////////////////////////
 BulletPlaneShape *BulletPlaneShape::
@@ -55,3 +55,70 @@ make_from_solid(const CollisionPlane *solid) {
   return new BulletPlaneShape(normal, constant);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BulletPlaneShape::register_with_read_factory
+//       Access: Public, Static
+//  Description: Tells the BamReader how to create objects of type
+//               BulletShape.
+////////////////////////////////////////////////////////////////////
+void BulletPlaneShape::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletPlaneShape::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void BulletPlaneShape::
+write_datagram(BamWriter *manager, Datagram &dg) {
+  dg.add_stdfloat(get_margin());
+  get_plane_normal().write_datagram(dg);
+  dg.add_stdfloat(get_plane_constant());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletPlaneShape::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of type BulletShape is encountered
+//               in the Bam file.  It should create the BulletShape
+//               and extract its information from the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *BulletPlaneShape::
+make_from_bam(const FactoryParams &params) {
+  BulletPlaneShape *param = new BulletPlaneShape;
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  param->fillin(scan, manager);
+
+  return param;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletPlaneShape::fillin
+//       Access: Protected
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new BulletShape.
+////////////////////////////////////////////////////////////////////
+void BulletPlaneShape::
+fillin(DatagramIterator &scan, BamReader *manager) {
+  nassertv(_shape == NULL);
+
+  PN_stdfloat margin = scan.get_stdfloat();
+
+  LVector3 normal;
+  normal.read_datagram(scan);
+
+  PN_stdfloat constant = scan.get_stdfloat();
+
+  _shape = new btStaticPlaneShape(LVecBase3_to_btVector3(normal), constant);
+  _shape->setUserPointer(this);
+  _shape->setMargin(margin);
+}
+

+ 11 - 1
panda/src/bullet/bulletPlaneShape.h

@@ -29,6 +29,9 @@
 // Description : 
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDABULLET BulletPlaneShape : public BulletShape {
+private:
+  // Only used by make_from_bam
+  INLINE BulletPlaneShape() : _shape(NULL) {};
 
 PUBLISHED:
   BulletPlaneShape(const LVector3 &normal, PN_stdfloat constant);
@@ -47,7 +50,14 @@ public:
 private:
   btStaticPlaneShape *_shape;
 
-////////////////////////////////////////////////////////////////////
+public:
+  static void register_with_read_factory();
+  virtual void write_datagram(BamWriter *manager, Datagram &dg);
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+  void fillin(DatagramIterator &scan, BamReader *manager);
+
 public:
   static TypeHandle get_class_type() {
     return _type_handle;

+ 99 - 0
panda/src/bullet/bulletRigidBodyNode.cxx

@@ -490,6 +490,28 @@ get_gravity() const {
   return btVector3_to_LVector3(_rigid->getGravity());
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BulletRigidBodyNode::get_linear_factor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+LVector3 BulletRigidBodyNode::
+get_linear_factor() const {
+
+  return btVector3_to_LVector3(_rigid->getLinearFactor());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletRigidBodyNode::get_angular_factor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+LVector3 BulletRigidBodyNode::
+get_angular_factor() const {
+
+  return btVector3_to_LVector3(_rigid->getAngularFactor());
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: BulletRigidBodyNode::set_linear_factor
 //       Access: Published
@@ -650,3 +672,80 @@ pick_dirty_flag() {
   return _motion->pick_dirty_flag();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BulletRigidBodyNode::register_with_read_factory
+//       Access: Public, Static
+//  Description: Tells the BamReader how to create objects of type
+//               BulletRigidBodyNode.
+////////////////////////////////////////////////////////////////////
+void BulletRigidBodyNode::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletRigidBodyNode::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void BulletRigidBodyNode::
+write_datagram(BamWriter *manager, Datagram &dg) {
+  BulletBodyNode::write_datagram(manager, dg);
+
+  dg.add_stdfloat(get_mass());
+  dg.add_stdfloat(get_linear_damping());
+  dg.add_stdfloat(get_angular_damping());
+  dg.add_stdfloat(get_linear_sleep_threshold());
+  dg.add_stdfloat(get_angular_sleep_threshold());
+  get_gravity().write_datagram(dg);
+  get_linear_factor().write_datagram(dg);
+  get_angular_factor().write_datagram(dg);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletRigidBodyNode::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of this type is encountered
+//               in the Bam file.  It should create the rigid body
+//               and extract its information from the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *BulletRigidBodyNode::
+make_from_bam(const FactoryParams &params) {
+  BulletRigidBodyNode *param = new BulletRigidBodyNode;
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  param->fillin(scan, manager);
+
+  return param;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletRigidBodyNode::fillin
+//       Access: Protected
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new BulletRigidBodyNode.
+////////////////////////////////////////////////////////////////////
+void BulletRigidBodyNode::
+fillin(DatagramIterator &scan, BamReader *manager) {
+  BulletBodyNode::fillin(scan, manager);
+
+  set_mass(scan.get_stdfloat());
+  set_linear_damping(scan.get_stdfloat());
+  set_angular_damping(scan.get_stdfloat());
+  set_linear_sleep_threshold(scan.get_stdfloat());
+  set_angular_sleep_threshold(scan.get_stdfloat());
+
+  LVector3 gravity, linear_factor, angular_factor;
+  gravity.read_datagram(scan);
+  linear_factor.read_datagram(scan);
+  angular_factor.read_datagram(scan);
+
+  set_gravity(gravity);
+  set_linear_factor(linear_factor);
+  set_angular_factor(angular_factor);
+}

+ 11 - 2
panda/src/bullet/bulletRigidBodyNode.h

@@ -80,6 +80,8 @@ PUBLISHED:
   LVector3 get_gravity() const;
 
   // Restrict movement
+  LVector3 get_linear_factor() const;
+  LVector3 get_angular_factor() const;
   void set_linear_factor(const LVector3 &factor);
   void set_angular_factor(const LVector3 &factor);
 
@@ -100,7 +102,7 @@ protected:
 private:
   virtual void shape_changed();
 
-  // The motion state is used for syncronisation between Bullet
+  // The motion state is used for synchronisation between Bullet
   // and the Panda3D scene graph.
   class MotionState : public btMotionState {
 
@@ -127,7 +129,14 @@ private:
   MotionState *_motion;
   btRigidBody *_rigid;
 
-////////////////////////////////////////////////////////////////////
+public:
+  static void register_with_read_factory();
+  virtual void write_datagram(BamWriter *manager, Datagram &dg);
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+  void fillin(DatagramIterator &scan, BamReader *manager);
+
 public:
   static TypeHandle get_class_type() {
     return _type_handle;

+ 5 - 3
panda/src/bullet/bulletShape.h

@@ -26,7 +26,9 @@
 //       Class : BulletShape
 // Description : 
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDABULLET BulletShape : public TypedReferenceCount {
+class EXPCL_PANDABULLET BulletShape : public TypedWritableReferenceCount {
+protected:
+  INLINE BulletShape() {};
 
 PUBLISHED:
   INLINE virtual ~BulletShape();
@@ -58,9 +60,9 @@ public:
     return _type_handle;
   }
   static void init_type() {
-    TypedReferenceCount::init_type();
+    TypedWritableReferenceCount::init_type();
     register_type(_type_handle, "BulletShape", 
-                  TypedReferenceCount::get_class_type());
+                  TypedWritableReferenceCount::get_class_type());
   }
   virtual TypeHandle get_type() const {
     return get_class_type();

+ 61 - 1
panda/src/bullet/bulletSphereShape.cxx

@@ -41,7 +41,7 @@ ptr() const {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: BulletSphereShape::make_from_solid
-//       Access: Public
+//       Access: Public, Static
 //  Description:
 ////////////////////////////////////////////////////////////////////
 BulletSphereShape *BulletSphereShape::
@@ -50,3 +50,63 @@ make_from_solid(const CollisionSphere *solid) {
   return new BulletSphereShape(solid->get_radius());
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BulletSphereShape::register_with_read_factory
+//       Access: Public, Static
+//  Description: Tells the BamReader how to create objects of type
+//               BulletShape.
+////////////////////////////////////////////////////////////////////
+void BulletSphereShape::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletSphereShape::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void BulletSphereShape::
+write_datagram(BamWriter *manager, Datagram &dg) {
+  dg.add_stdfloat(get_margin());
+  dg.add_stdfloat(get_radius());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletSphereShape::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of type BulletShape is encountered
+//               in the Bam file.  It should create the BulletShape
+//               and extract its information from the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *BulletSphereShape::
+make_from_bam(const FactoryParams &params) {
+  BulletSphereShape *param = new BulletSphereShape;
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  param->fillin(scan, manager);
+
+  return param;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletSphereShape::fillin
+//       Access: Protected
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new BulletShape.
+////////////////////////////////////////////////////////////////////
+void BulletSphereShape::
+fillin(DatagramIterator &scan, BamReader *manager) {
+  nassertv(_shape == NULL);
+
+  PN_stdfloat margin = scan.get_stdfloat();
+
+  _shape = new btSphereShape(scan.get_stdfloat());
+  _shape->setUserPointer(this);
+  _shape->setMargin(margin);
+}

+ 11 - 1
panda/src/bullet/bulletSphereShape.h

@@ -28,6 +28,9 @@
 // Description : 
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDABULLET BulletSphereShape : public BulletShape {
+private:
+  // Only used by make_from_bam
+  INLINE BulletSphereShape() : _shape(NULL) {};
 
 PUBLISHED:
   BulletSphereShape(PN_stdfloat radius);
@@ -45,7 +48,14 @@ public:
 private:
   btSphereShape *_shape;
 
-////////////////////////////////////////////////////////////////////
+public:
+  static void register_with_read_factory();
+  virtual void write_datagram(BamWriter *manager, Datagram &dg);
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+  void fillin(DatagramIterator &scan, BamReader *manager);
+
 public:
   static TypeHandle get_class_type() {
     return _type_handle;

+ 122 - 0
panda/src/bullet/bulletTriangleMesh.cxx

@@ -213,3 +213,125 @@ write(ostream &out, int indent_level) const {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BulletTriangleMesh::register_with_read_factory
+//       Access: Public, Static
+//  Description: Tells the BamReader how to create objects of type
+//               BulletTriangleMesh.
+////////////////////////////////////////////////////////////////////
+void BulletTriangleMesh::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletTriangleMesh::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void BulletTriangleMesh::
+write_datagram(BamWriter *manager, Datagram &dg) {
+  dg.add_stdfloat(get_welding_distance());
+
+  // In case we ever want to represent more than 1 indexed mesh.
+  dg.add_int32(1);
+
+  btIndexedMesh &mesh = _mesh->getIndexedMeshArray()[0];
+  dg.add_int32(mesh.m_numVertices);
+  dg.add_int32(mesh.m_numTriangles);
+
+  // In case we want to use this to distinguish 16-bit vs 32-bit indices.
+  dg.add_bool(true);
+
+  // Add the vertices.
+  const unsigned char *vptr = mesh.m_vertexBase;
+  nassertv(vptr != NULL || mesh.m_numVertices == 0);
+
+  for (int i = 0; i < mesh.m_numVertices; ++i) {
+    const btVector3 &vertex = *((btVector3 *)vptr);
+    dg.add_stdfloat(vertex.getX());
+    dg.add_stdfloat(vertex.getY());
+    dg.add_stdfloat(vertex.getZ());
+    vptr += mesh.m_vertexStride;
+  }
+
+  // Now add the triangle indices.
+  const unsigned char *iptr = mesh.m_triangleIndexBase;
+  nassertv(iptr != NULL || mesh.m_numTriangles == 0);
+
+  if (_mesh->getUse32bitIndices()) {
+    for (int i = 0; i < mesh.m_numTriangles; ++i) {
+      int *triangle = (int *)iptr;
+      dg.add_int32(triangle[0]);
+      dg.add_int32(triangle[1]);
+      dg.add_int32(triangle[2]);
+      iptr += mesh.m_triangleIndexStride;
+    }
+  } else {
+    for (int i = 0; i < mesh.m_numTriangles; ++i) {
+      short int *triangle = (short int *)iptr;
+      dg.add_int32(triangle[0]);
+      dg.add_int32(triangle[1]);
+      dg.add_int32(triangle[2]);
+      iptr += mesh.m_triangleIndexStride;
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletTriangleMesh::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of type BulletShape is encountered
+//               in the Bam file.  It should create the BulletShape
+//               and extract its information from the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *BulletTriangleMesh::
+make_from_bam(const FactoryParams &params) {
+  BulletTriangleMesh *param = new BulletTriangleMesh;
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  param->fillin(scan, manager);
+
+  return param;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletTriangleMesh::fillin
+//       Access: Protected
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new BulletTriangleMesh.
+////////////////////////////////////////////////////////////////////
+void BulletTriangleMesh::
+fillin(DatagramIterator &scan, BamReader *manager) {
+  set_welding_distance(scan.get_stdfloat());
+
+  nassertv(scan.get_int32() == 1);
+  int num_vertices = scan.get_int32();
+  int num_triangles = scan.get_int32();
+  nassertv(scan.get_bool() == true);
+
+  // Read and add the vertices.
+  _mesh->preallocateVertices(num_vertices);
+  for (int i = 0; i < num_vertices; ++i) {
+    PN_stdfloat x = scan.get_stdfloat();
+    PN_stdfloat y = scan.get_stdfloat();
+    PN_stdfloat z = scan.get_stdfloat();
+    _mesh->findOrAddVertex(btVector3(x, y, z), false);
+  }
+
+  // Now read and add the indices.
+  int num_indices = num_triangles * 3;
+  _mesh->preallocateIndices(num_indices);
+  for (int i = 0; i < num_indices; ++i) {
+    _mesh->addIndex(scan.get_int32());
+  }
+
+  // Since we manually added the vertices individually, we have to
+  // update the triangle count appropriately.
+  _mesh->getIndexedMeshArray()[0].m_numTriangles = num_triangles;
+}

+ 12 - 5
panda/src/bullet/bulletTriangleMesh.h

@@ -20,7 +20,7 @@
 #include "bullet_includes.h"
 #include "bullet_utils.h"
 
-#include "typedReferenceCount.h"
+#include "typedWritableReferenceCount.h"
 #include "nodePath.h"
 #include "luse.h"
 #include "geom.h"
@@ -31,7 +31,7 @@
 //       Class : BulletTriangleMesh
 // Description : 
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDABULLET BulletTriangleMesh : public TypedReferenceCount {
+class EXPCL_PANDABULLET BulletTriangleMesh : public TypedWritableReferenceCount {
 
 PUBLISHED:
   BulletTriangleMesh();
@@ -63,15 +63,22 @@ public:
 private:
   btTriangleMesh *_mesh;
 
-////////////////////////////////////////////////////////////////////
+public:
+  static void register_with_read_factory();
+  virtual void write_datagram(BamWriter *manager, Datagram &dg);
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+  void fillin(DatagramIterator &scan, BamReader *manager);
+
 public:
   static TypeHandle get_class_type() {
     return _type_handle;
   }
   static void init_type() {
-    TypedReferenceCount::init_type();
+    TypedWritableReferenceCount::init_type();
     register_type(_type_handle, "BulletTriangleMesh", 
-                  TypedReferenceCount::get_class_type());
+                  TypedWritableReferenceCount::get_class_type());
   }
   virtual TypeHandle get_type() const {
     return get_class_type();

+ 116 - 1
panda/src/bullet/bulletTriangleMeshShape.cxx

@@ -21,6 +21,21 @@
 
 TypeHandle BulletTriangleMeshShape::_type_handle;
 
+////////////////////////////////////////////////////////////////////
+//     Function: BulletTriangleMeshShape::Constructor
+//       Access: Private
+//  Description: Only used by make_from_bam.
+////////////////////////////////////////////////////////////////////
+BulletTriangleMeshShape::
+BulletTriangleMeshShape() :
+  _mesh(NULL),
+  _gimpact_shape(NULL),
+  _bvh_shape(NULL),
+  _dynamic(false),
+  _compress(false),
+  _bvh(false) {
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: BulletTriangleMeshShape::Constructor
 //       Access: Published
@@ -28,7 +43,10 @@ TypeHandle BulletTriangleMeshShape::_type_handle;
 //               if 'dynamic' is set to FALSE.
 ////////////////////////////////////////////////////////////////////
 BulletTriangleMeshShape::
-BulletTriangleMeshShape(BulletTriangleMesh *mesh, bool dynamic, bool compress, bool bvh) {
+BulletTriangleMeshShape(BulletTriangleMesh *mesh, bool dynamic, bool compress, bool bvh) :
+  _dynamic(dynamic),
+  _compress(compress),
+  _bvh(bvh) {
 
   // Assert that mesh is not NULL
   if (!mesh) {
@@ -101,3 +119,100 @@ refit_tree(const LPoint3 &aabb_min, const LPoint3 &aabb_max) {
                         LVecBase3_to_btVector3(aabb_max));
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BulletTriangleMeshShape::register_with_read_factory
+//       Access: Public, Static
+//  Description: Tells the BamReader how to create objects of type
+//               BulletTriangleMeshShape.
+////////////////////////////////////////////////////////////////////
+void BulletTriangleMeshShape::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletTriangleMeshShape::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void BulletTriangleMeshShape::
+write_datagram(BamWriter *manager, Datagram &dg) {
+  dg.add_stdfloat(get_margin());
+
+  manager->write_pointer(dg, _mesh);
+
+  dg.add_bool(_dynamic);
+  if (!_dynamic) {
+    dg.add_bool(_compress);
+    dg.add_bool(_bvh);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletTriangleMeshShape::complete_pointers
+//       Access: Public, Virtual
+//  Description: Receives an array of pointers, one for each time
+//               manager->read_pointer() was called in fillin().
+//               Returns the number of pointers processed.
+////////////////////////////////////////////////////////////////////
+int BulletTriangleMeshShape::
+complete_pointers(TypedWritable **p_list, BamReader *manager) {
+  int pi = BulletShape::complete_pointers(p_list, manager);
+
+  _mesh = DCAST(BulletTriangleMesh, p_list[pi++]);
+
+  btTriangleMesh *mesh_ptr = _mesh->ptr();
+  nassertr(mesh_ptr != NULL, pi);
+
+  if (_dynamic) {
+    _gimpact_shape = new btGImpactMeshShape(mesh_ptr);
+    _gimpact_shape->updateBound();
+    _gimpact_shape->setUserPointer(this);
+  } else {
+    _bvh_shape = new btBvhTriangleMeshShape(mesh_ptr, _compress, _bvh);
+    _bvh_shape->setUserPointer(this);
+  }
+
+  return pi;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletTriangleMeshShape::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of type BulletShape is encountered
+//               in the Bam file.  It should create the BulletShape
+//               and extract its information from the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *BulletTriangleMeshShape::
+make_from_bam(const FactoryParams &params) {
+  BulletTriangleMeshShape *param = new BulletTriangleMeshShape;
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  param->fillin(scan, manager);
+
+  return param;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletTriangleMeshShape::fillin
+//       Access: Protected
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new BulletTriangleMeshShape.
+////////////////////////////////////////////////////////////////////
+void BulletTriangleMeshShape::
+fillin(DatagramIterator &scan, BamReader *manager) {
+  PN_stdfloat margin = scan.get_stdfloat();
+
+  manager->read_pointer(scan);
+
+  _dynamic = scan.get_bool();
+  if (!_dynamic) {
+    _compress = scan.get_bool();
+    _bvh = scan.get_bool();
+  }
+}

+ 16 - 1
panda/src/bullet/bulletTriangleMeshShape.h

@@ -29,6 +29,8 @@ class BulletTriangleMesh;
 // Description : 
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDABULLET BulletTriangleMeshShape : public BulletShape {
+private:
+  INLINE BulletTriangleMeshShape();
 
 PUBLISHED:
   BulletTriangleMeshShape(BulletTriangleMesh *mesh, bool dynamic, bool compress=true, bool bvh=true);
@@ -50,7 +52,20 @@ private:
 
   PT(BulletTriangleMesh) _mesh;
 
-////////////////////////////////////////////////////////////////////
+  bool _dynamic : 1;
+  bool _compress : 1;
+  bool _bvh : 1;
+
+public:
+  static void register_with_read_factory();
+  virtual void write_datagram(BamWriter *manager, Datagram &dg);
+  virtual int complete_pointers(TypedWritable **plist,
+                              BamReader *manager);
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+  void fillin(DatagramIterator &scan, BamReader *manager);
+
 public:
   static TypeHandle get_class_type() {
     return _type_handle;

+ 10 - 0
panda/src/bullet/config_bullet.cxx

@@ -182,6 +182,16 @@ init_libbullet() {
   BulletVehicle::init_type();
   BulletWorld::init_type();
 
+  // Register factory functions for constructing objects from .bam files
+  BulletBoxShape::register_with_read_factory();
+  BulletConvexHullShape::register_with_read_factory();
+  BulletDebugNode::register_with_read_factory();
+  BulletPlaneShape::register_with_read_factory();
+  BulletRigidBodyNode::register_with_read_factory();
+  BulletSphereShape::register_with_read_factory();
+  BulletTriangleMesh::register_with_read_factory();
+  BulletTriangleMeshShape::register_with_read_factory();
+
   // Custom contact callbacks
   gContactAddedCallback = contact_added_callback;
   gContactProcessedCallback = contact_processed_callback;

+ 18 - 10
panda/src/display/get_x11.h

@@ -17,7 +17,7 @@
 
 #include "pandabase.h"
 
-#ifdef HAVE_X11 
+#ifdef HAVE_X11
 // This header file is designed to help work around some of the
 // namespace spamming that X11 causes, by renaming the symbols that
 // X11 declares that are known to conflict with other library names
@@ -30,14 +30,21 @@
 #ifdef CPPPARSER
 // A simple hack so interrogate can get all of the necessary
 // typenames.
-typedef int X11_Display;
-typedef int X11_Window;
-typedef int X11_Cursor;
-typedef int XErrorEvent;
-typedef int XVisualInfo;
-typedef int Atom;
-typedef int XIM;
-typedef int XIC;
+typedef struct _XDisplay X11_Display;
+typedef unsigned int XID;
+typedef unsigned int Atom;
+typedef unsigned int Cardinal;
+typedef XID Colormap;
+typedef XID X11_Window;
+typedef XID X11_Cursor;
+typedef struct _XIM *XIM;
+typedef struct _XIC *XIC;
+struct XErrorEvent;
+struct XVisualInfo;
+#define Bool int
+#define Status int
+#define True 1
+#define False 0
 #else
 
 #include "pre_x11_include.h"
@@ -45,6 +52,7 @@ typedef int XIC;
 #include <X11/Xutil.h>
 #include <X11/keysym.h>
 #include <X11/Xatom.h>
+#include <X11/Intrinsic.h>
 
 #ifdef HAVE_XRANDR
 #include <X11/extensions/Xrandr.h>
@@ -55,7 +63,7 @@ typedef int XIC;
 #endif
 
 #ifdef HAVE_XF86DGA
-#include <X11/extensions/xf86dga.h>
+#include <X11/extensions/Xxf86dga.h>
 #endif
 
 #include "post_x11_include.h"

+ 48 - 0
panda/src/display/graphicsOutput.I

@@ -207,6 +207,20 @@ get_y_size() const {
   return _size.get_y();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::get_fb_size
+//       Access: Published
+//  Description: Returns the internal size of the window or buffer.
+//               This is almost always the same as get_size(),
+//               except when a pixel_zoom is in effect--see
+//               set_pixel_zoom().
+////////////////////////////////////////////////////////////////////
+INLINE LVecBase2i GraphicsOutput::
+get_fb_size() const {
+  return LVecBase2i(max(int(_size.get_x() * get_pixel_factor()), 1),
+                    max(int(_size.get_y() * get_pixel_factor()), 1));
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsOutput::get_fb_x_size
 //       Access: Published
@@ -233,6 +247,23 @@ get_fb_y_size() const {
   return max(int(_size.get_y() * get_pixel_factor()), 1);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::get_sbs_left_size
+//       Access: Published
+//  Description: If side-by-side stereo is enabled, this returns the
+//               pixel size of the left eye, based on scaling
+//               get_size() by get_sbs_left_dimensions().  If
+//               side-by-side stereo is not enabled, this returns the
+//               same as get_size().
+////////////////////////////////////////////////////////////////////
+INLINE LVecBase2i GraphicsOutput::
+get_sbs_left_size() const {
+  PN_stdfloat left_w = _sbs_left_dimensions[1] - _sbs_left_dimensions[0];
+  PN_stdfloat left_h = _sbs_left_dimensions[3] - _sbs_left_dimensions[2];
+  return LVecBase2i(max(int(_size.get_x() * left_w), 1),
+                    max(int(_size.get_y() * left_h), 1));
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsOutput::get_sbs_left_x_size
 //       Access: Published
@@ -263,6 +294,23 @@ get_sbs_left_y_size() const {
   return max(int(_size.get_y() * left_h), 1);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::get_sbs_right_size
+//       Access: Published
+//  Description: If side-by-side stereo is enabled, this returns the
+//               pixel size of the right eye, based on scaling
+//               get_size() by get_sbs_right_dimensions().  If
+//               side-by-side stereo is not enabled, this returns the
+//               same as get_size().
+////////////////////////////////////////////////////////////////////
+INLINE LVecBase2i GraphicsOutput::
+get_sbs_right_size() const {
+  PN_stdfloat right_w = _sbs_right_dimensions[1] - _sbs_right_dimensions[0];
+  PN_stdfloat right_h = _sbs_right_dimensions[3] - _sbs_right_dimensions[2];
+  return LVecBase2i(max(int(_size.get_x() * right_w), 1),
+                    max(int(_size.get_y() * right_h), 1));
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsOutput::get_sbs_right_x_size
 //       Access: Published

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

@@ -135,10 +135,13 @@ PUBLISHED:
   INLINE const LVecBase2i &get_size() const;
   INLINE int get_x_size() const;
   INLINE int get_y_size() const;
+  INLINE LVecBase2i get_fb_size() const;
   INLINE int get_fb_x_size() const;
   INLINE int get_fb_y_size() const;
+  INLINE LVecBase2i get_sbs_left_size() const;
   INLINE int get_sbs_left_x_size() const;
   INLINE int get_sbs_left_y_size() const;
+  INLINE LVecBase2i get_sbs_right_size() const;
   INLINE int get_sbs_right_x_size() const;
   INLINE int get_sbs_right_y_size() const;
   INLINE bool has_size() const;

+ 26 - 0
panda/src/display/graphicsStateGuardian.I

@@ -397,6 +397,22 @@ get_max_cube_map_dimension() const {
   return _max_cube_map_dimension;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::get_max_buffer_texture_size
+//       Access: Published
+//  Description: Returns the largest possible buffer texture size,
+//               or -1 if there is no particular limit.  Returns 0
+//               if cube map textures are not supported.
+//
+//               The value returned may not be meaningful until after
+//               the graphics context has been fully created (e.g. the
+//               window has been opened).
+////////////////////////////////////////////////////////////////////
+INLINE int GraphicsStateGuardian::
+get_max_buffer_texture_size() const {
+  return _max_buffer_texture_size;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::get_supports_texture_combine
 //       Access: Published
@@ -469,6 +485,16 @@ get_supports_cube_map() const {
   return _supports_cube_map;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::get_supports_buffer_texture
+//       Access: Published
+//  Description: Returns true if this GSG can render buffer textures.
+////////////////////////////////////////////////////////////////////
+INLINE bool GraphicsStateGuardian::
+get_supports_buffer_texture() const {
+  return _supports_buffer_texture;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::get_supports_tex_non_pow2
 //       Access: Published

+ 15 - 0
panda/src/display/graphicsStateGuardian.cxx

@@ -185,6 +185,7 @@ GraphicsStateGuardian(CoordinateSystem internal_coordinate_system,
   _max_3d_texture_dimension = 0;
   _max_2d_texture_array_layers = 0;
   _max_cube_map_dimension = 0;
+  _max_buffer_texture_size = 0;
 
   // Assume we don't support these fairly advanced texture combiner
   // modes.
@@ -195,6 +196,7 @@ GraphicsStateGuardian(CoordinateSystem internal_coordinate_system,
   _supports_3d_texture = false;
   _supports_2d_texture_array = false;
   _supports_cube_map = false;
+  _supports_buffer_texture = false;
   _supports_tex_non_pow2 = false;
   _supports_texture_srgb = false;
   _supports_compressed_texture = false;
@@ -1265,10 +1267,17 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
   case Shader::SMO_model_to_view: {
     return &(get_external_transform()->get_mat());
   }
+  case Shader::SMO_model_to_apiview: {
+    return &(get_internal_transform()->get_mat());
+  }
   case Shader::SMO_view_to_model: {
     t = get_external_transform()->get_inverse()->get_mat();
     return &t;
   }
+  case Shader::SMO_apiview_to_model: {
+    t = get_internal_transform()->get_inverse()->get_mat();
+    return &t;
+  }
   case Shader::SMO_apiview_to_view: {
     return &(_inv_cs_transform->get_mat());
   }
@@ -1301,6 +1310,12 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
     t = _cs_transform->get_mat() * _projection_mat->get_mat();
     return &t;
   }
+  case Shader::SMO_apiclip_to_apiview: {
+    return &(_projection_mat_inv->get_mat());
+  }
+  case Shader::SMO_apiview_to_apiclip: {
+    return &(_projection_mat->get_mat());
+  }
   case Shader::SMO_view_x_to_view: {
     const NodePath &np = _target_shader->get_shader_input_nodepath(name);
     nassertr(!np.is_empty(), &LMatrix4::ident_mat());

+ 4 - 0
panda/src/display/graphicsStateGuardian.h

@@ -121,6 +121,7 @@ PUBLISHED:
   INLINE int get_max_3d_texture_dimension() const;
   INLINE int get_max_2d_texture_array_layers() const; //z axis
   INLINE int get_max_cube_map_dimension() const;
+  INLINE int get_max_buffer_texture_size() const;
 
   INLINE bool get_supports_texture_combine() const;
   INLINE bool get_supports_texture_saved_result() const;
@@ -129,6 +130,7 @@ PUBLISHED:
   INLINE bool get_supports_3d_texture() const;
   INLINE bool get_supports_2d_texture_array() const;
   INLINE bool get_supports_cube_map() const;
+  INLINE bool get_supports_buffer_texture() const;
   INLINE bool get_supports_tex_non_pow2() const;
   INLINE bool get_supports_texture_srgb() const;
 
@@ -476,6 +478,7 @@ protected:
   int _max_3d_texture_dimension;
   int _max_2d_texture_array_layers; //on the z axis
   int _max_cube_map_dimension;
+  int _max_buffer_texture_size;
 
   bool _supports_texture_combine;
   bool _supports_texture_saved_result;
@@ -484,6 +487,7 @@ protected:
   bool _supports_3d_texture;
   bool _supports_2d_texture_array;
   bool _supports_cube_map;
+  bool _supports_buffer_texture;
   bool _supports_tex_non_pow2;
   bool _supports_texture_srgb;
 

+ 4 - 18
panda/src/display/graphicsWindow.cxx

@@ -736,24 +736,10 @@ set_properties_now(WindowProperties &properties) {
     // Fullscreen property specified, but unchanged.
     properties.clear_fullscreen();
   }
-  if (properties.has_mouse_mode() ) {
-    
-    if (properties.get_mouse_mode() == _properties.get_mouse_mode()) {  
-      properties.clear_mouse_mode();
-    }
-    else {
-      if(properties.get_mouse_mode() == WindowProperties::M_absolute) {
-        _properties.set_mouse_mode(WindowProperties::M_absolute);
-        mouse_mode_absolute();
-        properties.clear_mouse_mode();
-      }
-      else
-      {
-        _properties.set_mouse_mode(WindowProperties::M_relative);
-        mouse_mode_relative();
-        properties.clear_mouse_mode();        
-      }    
-    }
+  if (properties.has_mouse_mode() &&
+      properties.get_mouse_mode() == _properties.get_mouse_mode()) {
+    // Mouse mode specified, but unchanged.
+    properties.clear_mouse_mode();
   }
 }
 

+ 3 - 3
panda/src/display/pStatGPUTimer.I

@@ -25,7 +25,7 @@ PStatGPUTimer(GraphicsStateGuardian *gsg, PStatCollector &collector) :
   PStatTimer(collector),
   _gsg(gsg)
 {
-  if (gsg->get_timer_queries_active()) {
+  if (gsg->get_timer_queries_active() && collector.is_active()) {
     gsg->issue_timer_query(collector.get_index());
     //cerr << "issuing " << collector << " active " << collector.is_active() << "\n";
   }
@@ -41,7 +41,7 @@ PStatGPUTimer(GraphicsStateGuardian *gsg, PStatCollector &collector, Thread *cur
   PStatTimer(collector, current_thread),
   _gsg(gsg)
 {
-  if (gsg->get_timer_queries_active()) {
+  if (gsg->get_timer_queries_active() && collector.is_active()) {
     gsg->issue_timer_query(collector.get_index());
   }
 }
@@ -53,7 +53,7 @@ PStatGPUTimer(GraphicsStateGuardian *gsg, PStatCollector &collector, Thread *cur
 ////////////////////////////////////////////////////////////////////
 INLINE PStatGPUTimer::
 ~PStatGPUTimer() {
-  if (_gsg->get_timer_queries_active()) {
+  if (_gsg->get_timer_queries_active() && _collector.is_active()) {
     _gsg->issue_timer_query(_collector.get_index() | 0x8000);
   }
 }

+ 23 - 12
panda/src/display/windowProperties.I

@@ -798,19 +798,30 @@ clear_z_order() {
 //     Function: WindowProperties::set_mouse_mode
 //       Access: Published
 //  Description: Specifies the mode in which the window is to operate
-//               its mouse pointer.  The default is M_absolute, which
-//               is the normal mode in which a mouse pointer operates;
-//               but you can also set M_relative, which is
-//               particularly useful for FPS-style mouse movements
-//               where you have hidden the mouse pointer and are are
-//               more interested in how fast the mouse is moving,
-//               rather than precisely where the pointer is hovering.
+//               its mouse pointer.
+//
+//               M_absolute: the normal mode in which a mouse pointer
+//               operates, where the mouse can move outside the window
+//               and the mouse coordinates are relative to its
+//               position in the window.
+//
+//               M_relative (OSX or Unix/X11 only): a mode where only
+//               relative movements are reported; particularly useful
+//               for FPS-style mouse movements where you have hidden
+//               the mouse pointer and are are more interested in how
+//               fast the mouse is moving, rather than precisely where
+//               the pointer is hovering.
+//
+//               This has no effect on Windows.  On Unix/X11, this
+//               requires the Xxf86dga extension to be available.
+//
+//               M_confined: this mode reports absolute mouse
+//               positions, but confines the mouse pointer to
+//               the window boundary.  It can portably replace
+//               M_relative for an FPS, but you need to periodically
+//               move the pointer to the center of the window
+//               and track movement deltas.
 //
-//               This has no effect on Windows, which does not
-//               have this concept; but is important to do on OSX
-//               and Unix/X11 to properly enable a smooth FPS-style
-//               mouselook mode.  On Unix/X11, this requires the
-//               Xxf86dga extension to be available.
 ////////////////////////////////////////////////////////////////////
 INLINE void WindowProperties::
 set_mouse_mode(MouseMode mode) {

+ 4 - 0
panda/src/display/windowProperties.cxx

@@ -400,6 +400,8 @@ operator << (ostream &out, WindowProperties::MouseMode mode) {
     return out << "absolute";
   case WindowProperties::M_relative:
     return out << "relative";
+  case WindowProperties::M_confined:
+    return out << "confined";
   }
   return out << "**invalid WindowProperties::MouseMode(" << (int)mode << ")**";
 }
@@ -413,6 +415,8 @@ operator >> (istream &in, WindowProperties::MouseMode &mode) {
     mode = WindowProperties::M_absolute;
   } else if (word == "relative") {
     mode = WindowProperties::M_relative;
+  } else if (word == "confined") {
+    mode = WindowProperties::M_confined;
   } else {
     display_cat.warning()
       << "Unknown mouse mode: " << word << "\n";

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

@@ -40,6 +40,7 @@ PUBLISHED:
   enum MouseMode {
     M_absolute,
     M_relative,
+    M_confined,
   };
 
   WindowProperties();

+ 136 - 0
panda/src/egg/eggTexture.I

@@ -1057,6 +1057,142 @@ get_read_mipmaps() const {
   return _read_mipmaps;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggTexture::set_min_lod
+//       Access: Published
+//  Description: Sets the minimum mipmap level that may be sampled.
+////////////////////////////////////////////////////////////////////
+INLINE void EggTexture::
+set_min_lod(double min_lod) {
+  _min_lod = min_lod;
+  _flags |= F_has_min_lod;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTexture::clear_min_lod
+//       Access: Published
+//  Description: Removes the specification of a minimum mipmap level
+//               from the texture.
+////////////////////////////////////////////////////////////////////
+INLINE void EggTexture::
+clear_min_lod() {
+  _min_lod = -1000;
+  _flags &= ~F_has_min_lod;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTexture::has_min_lod
+//       Access: Published
+//  Description: Returns true if a value for the minimum mipmap level
+//               has been specified for this texture, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool EggTexture::
+has_min_lod() const {
+  return (_flags & F_has_min_lod) != 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTexture::get_min_lod
+//       Access: Published
+//  Description: Returns the minimum mipmap level that has been
+//               specified for this texture.
+////////////////////////////////////////////////////////////////////
+INLINE double EggTexture::
+get_min_lod() const {
+  return _min_lod;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTexture::set_max_lod
+//       Access: Published
+//  Description: Sets the maximum mipmap level that may be sampled.
+////////////////////////////////////////////////////////////////////
+INLINE void EggTexture::
+set_max_lod(double max_lod) {
+  _max_lod = max_lod;
+  _flags |= F_has_max_lod;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTexture::clear_max_lod
+//       Access: Published
+//  Description: Removes the specification of a maximum mipmap level
+//               from the texture.
+////////////////////////////////////////////////////////////////////
+INLINE void EggTexture::
+clear_max_lod() {
+  _max_lod = 1000;
+  _flags &= ~F_has_max_lod;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTexture::has_max_lod
+//       Access: Published
+//  Description: Returns true if a value for the maximum mipmap level
+//               has been specified for this texture, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool EggTexture::
+has_max_lod() const {
+  return (_flags & F_has_max_lod) != 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTexture::get_max_lod
+//       Access: Published
+//  Description: Returns the maximum mipmap level that has been
+//               specified for this texture.
+////////////////////////////////////////////////////////////////////
+INLINE double EggTexture::
+get_max_lod() const {
+  return _max_lod;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTexture::set_lod_bias
+//       Access: Published
+//  Description: Sets the mipmap level bias that is added to the
+//               mipmap level to be sampled.
+////////////////////////////////////////////////////////////////////
+INLINE void EggTexture::
+set_lod_bias(double lod_bias) {
+  _lod_bias = lod_bias;
+  _flags |= F_has_lod_bias;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTexture::clear_lod_bias
+//       Access: Published
+//  Description: Removes the specification of a maximum mipmap level
+//               from the texture.
+////////////////////////////////////////////////////////////////////
+INLINE void EggTexture::
+clear_lod_bias() {
+  _lod_bias = 1000;
+  _flags &= ~F_has_lod_bias;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTexture::has_lod_bias
+//       Access: Published
+//  Description: Returns true if a value for the maximum mipmap level
+//               has been specified for this texture, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool EggTexture::
+has_lod_bias() const {
+  return (_flags & F_has_lod_bias) != 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTexture::get_lod_bias
+//       Access: Published
+//  Description: Returns the maximum mipmap level that has been
+//               specified for this texture.
+////////////////////////////////////////////////////////////////////
+INLINE double EggTexture::
+get_lod_bias() const {
+  return _lod_bias;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggTexture::get_multitexture_sort
 //       Access: Published

+ 20 - 0
panda/src/egg/eggTexture.h

@@ -281,6 +281,20 @@ PUBLISHED:
   INLINE void set_read_mipmaps(bool read_mipmaps);
   INLINE bool get_read_mipmaps() const;
 
+  INLINE void set_min_lod(double min_lod);
+  INLINE void clear_min_lod();
+  INLINE bool has_min_lod() const;
+  INLINE double get_min_lod() const;
+
+  INLINE void set_max_lod(double max_lod);
+  INLINE void clear_max_lod();
+  INLINE bool has_max_lod() const;
+  INLINE double get_max_lod() const;
+
+  INLINE void set_lod_bias(double lod_bias);
+  INLINE void clear_lod_bias();
+  INLINE bool has_lod_bias() const;
+  INLINE double get_lod_bias() const;
 
   void clear_multitexture();
   bool multitexture_over(EggTexture *other);
@@ -320,6 +334,9 @@ private:
     F_has_alpha_scale        = 0x0200,
     F_has_border_color       = 0x0400,
     F_has_num_views          = 0x0800,
+    F_has_min_lod            = 0x1000,
+    F_has_max_lod            = 0x2000,
+    F_has_lod_bias           = 0x4000,
   };
 
   TextureType _texture_type;
@@ -347,6 +364,9 @@ private:
   int _alpha_file_channel;
   bool _read_mipmaps;
   int _multitexture_sort;
+  double _min_lod;
+  double _max_lod;
+  double _lod_bias;
 
   class SourceAndOperand {
   public:

+ 9 - 0
panda/src/egg/parser.yxx

@@ -699,6 +699,15 @@ texture_body:
   } else if (cmp_nocase_uh(name, "read_mipmaps") == 0) {
     texture->set_read_mipmaps(((int)value) != 0);
 
+  } else if (cmp_nocase_uh(name, "min_lod") == 0) {
+    texture->set_min_lod(value);
+
+  } else if (cmp_nocase_uh(name, "max_lod") == 0) {
+    texture->set_max_lod(value);
+
+  } else if (cmp_nocase_uh(name, "lod_bias") == 0) {
+    texture->set_lod_bias(value);
+
   } else {
     eggyywarning("Unsupported texture scalar: " + name);
   }

+ 39 - 23
panda/src/egg2pg/eggLoader.cxx

@@ -1088,36 +1088,38 @@ apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) {
     tex->set_compression(convert_compression_mode(egg_tex->get_compression_mode()));
   }
 
+  SamplerState sampler;
+
   EggTexture::WrapMode wrap_u = egg_tex->determine_wrap_u();
   EggTexture::WrapMode wrap_v = egg_tex->determine_wrap_v();
   EggTexture::WrapMode wrap_w = egg_tex->determine_wrap_w();
 
   if (wrap_u != EggTexture::WM_unspecified) {
-    tex->set_wrap_u(convert_wrap_mode(wrap_u));
+    sampler.set_wrap_u(convert_wrap_mode(wrap_u));
   }
   if (wrap_v != EggTexture::WM_unspecified) {
-    tex->set_wrap_v(convert_wrap_mode(wrap_v));
+    sampler.set_wrap_v(convert_wrap_mode(wrap_v));
   }
   if (wrap_w != EggTexture::WM_unspecified) {
-    tex->set_wrap_w(convert_wrap_mode(wrap_w));
+    sampler.set_wrap_w(convert_wrap_mode(wrap_w));
   }
 
   if (egg_tex->has_border_color()) {
-    tex->set_border_color(egg_tex->get_border_color());
+    sampler.set_border_color(egg_tex->get_border_color());
   }
 
   switch (egg_tex->get_minfilter()) {
   case EggTexture::FT_nearest:
-    tex->set_minfilter(SamplerState::FT_nearest);
+    sampler.set_minfilter(SamplerState::FT_nearest);
     break;
 
   case EggTexture::FT_linear:
     if (egg_ignore_filters) {
       egg2pg_cat.warning()
         << "Ignoring minfilter request\n";
-      tex->set_minfilter(SamplerState::FT_nearest);
+      sampler.set_minfilter(SamplerState::FT_nearest);
     } else {
-      tex->set_minfilter(SamplerState::FT_linear);
+      sampler.set_minfilter(SamplerState::FT_linear);
     }
     break;
 
@@ -1125,13 +1127,13 @@ apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) {
     if (egg_ignore_filters) {
       egg2pg_cat.warning()
         << "Ignoring minfilter request\n";
-      tex->set_minfilter(SamplerState::FT_nearest);
+      sampler.set_minfilter(SamplerState::FT_nearest);
     } else if (egg_ignore_mipmaps) {
       egg2pg_cat.warning()
         << "Ignoring mipmap request\n";
-      tex->set_minfilter(SamplerState::FT_nearest);
+      sampler.set_minfilter(SamplerState::FT_nearest);
     } else {
-      tex->set_minfilter(SamplerState::FT_nearest_mipmap_nearest);
+      sampler.set_minfilter(SamplerState::FT_nearest_mipmap_nearest);
     }
     break;
 
@@ -1139,13 +1141,13 @@ apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) {
     if (egg_ignore_filters) {
       egg2pg_cat.warning()
         << "Ignoring minfilter request\n";
-      tex->set_minfilter(SamplerState::FT_nearest);
+      sampler.set_minfilter(SamplerState::FT_nearest);
     } else if (egg_ignore_mipmaps) {
       egg2pg_cat.warning()
         << "Ignoring mipmap request\n";
-      tex->set_minfilter(SamplerState::FT_linear);
+      sampler.set_minfilter(SamplerState::FT_linear);
     } else {
-      tex->set_minfilter(SamplerState::FT_linear_mipmap_nearest);
+      sampler.set_minfilter(SamplerState::FT_linear_mipmap_nearest);
     }
     break;
 
@@ -1153,13 +1155,13 @@ apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) {
     if (egg_ignore_filters) {
       egg2pg_cat.warning()
         << "Ignoring minfilter request\n";
-      tex->set_minfilter(SamplerState::FT_nearest);
+      sampler.set_minfilter(SamplerState::FT_nearest);
     } else if (egg_ignore_mipmaps) {
       egg2pg_cat.warning()
         << "Ignoring mipmap request\n";
-      tex->set_minfilter(SamplerState::FT_nearest);
+      sampler.set_minfilter(SamplerState::FT_nearest);
     } else {
-      tex->set_minfilter(SamplerState::FT_nearest_mipmap_linear);
+      sampler.set_minfilter(SamplerState::FT_nearest_mipmap_linear);
     }
     break;
 
@@ -1167,13 +1169,13 @@ apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) {
     if (egg_ignore_filters) {
       egg2pg_cat.warning()
         << "Ignoring minfilter request\n";
-      tex->set_minfilter(SamplerState::FT_nearest);
+      sampler.set_minfilter(SamplerState::FT_nearest);
     } else if (egg_ignore_mipmaps) {
       egg2pg_cat.warning()
         << "Ignoring mipmap request\n";
-      tex->set_minfilter(SamplerState::FT_linear);
+      sampler.set_minfilter(SamplerState::FT_linear);
     } else {
-      tex->set_minfilter(SamplerState::FT_linear_mipmap_linear);
+      sampler.set_minfilter(SamplerState::FT_linear_mipmap_linear);
     }
     break;
 
@@ -1185,7 +1187,7 @@ apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) {
   case EggTexture::FT_nearest:
   case EggTexture::FT_nearest_mipmap_nearest:
   case EggTexture::FT_nearest_mipmap_linear:
-    tex->set_magfilter(SamplerState::FT_nearest);
+    sampler.set_magfilter(SamplerState::FT_nearest);
     break;
 
   case EggTexture::FT_linear:
@@ -1194,9 +1196,9 @@ apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) {
     if (egg_ignore_filters) {
       egg2pg_cat.warning()
         << "Ignoring magfilter request\n";
-      tex->set_magfilter(SamplerState::FT_nearest);
+      sampler.set_magfilter(SamplerState::FT_nearest);
     } else {
-      tex->set_magfilter(SamplerState::FT_linear);
+      sampler.set_magfilter(SamplerState::FT_linear);
     }
     break;
 
@@ -1205,9 +1207,23 @@ apply_texture_attributes(Texture *tex, const EggTexture *egg_tex) {
   }
 
   if (egg_tex->has_anisotropic_degree()) {
-    tex->set_anisotropic_degree(egg_tex->get_anisotropic_degree());
+    sampler.set_anisotropic_degree(egg_tex->get_anisotropic_degree());
+  }
+
+  if (egg_tex->has_min_lod()) {
+    sampler.set_min_lod(egg_tex->get_min_lod());
+  }
+
+  if (egg_tex->has_max_lod()) {
+    sampler.set_max_lod(egg_tex->get_max_lod());
+  }
+
+  if (egg_tex->has_lod_bias()) {
+    sampler.set_lod_bias(egg_tex->get_lod_bias());
   }
 
+  tex->set_default_sampler(sampler);
+
   if (tex->get_num_components() == 1) {
     switch (egg_tex->get_format()) {
     case EggTexture::F_red:

+ 1 - 3
panda/src/glstuff/glCgShaderContext_src.cxx

@@ -643,9 +643,7 @@ update_shader_texture_bindings(ShaderContext *prev) {
     SamplerState sampler;
 
     if (id != NULL) {
-      const ShaderInput *input = _glgsg->_target_shader->get_shader_input(id);
-      tex = input->get_texture();
-      sampler = input->get_sampler();
+      tex = _glgsg->_target_shader->get_shader_input_texture(id, &sampler);
 
     } else {
       if (_shader->_tex_spec[i]._stage >= texattrib->get_num_on_stages()) {

+ 77 - 13
panda/src/glstuff/glGeomMunger_src.cxx

@@ -87,6 +87,46 @@ munge_format_impl(const GeomVertexFormat *orig,
   CLP(GraphicsStateGuardian) *glgsg;
   DCAST_INTO_R(glgsg, get_gsg(), NULL);
 
+#ifndef OPENGLES
+  // OpenGL ES 1 does, but regular OpenGL doesn't support GL_BYTE vertices
+  // and texture coordinates.
+  const GeomVertexColumn *vertex_type = orig->get_vertex_column();
+  if (vertex_type != (GeomVertexColumn *)NULL &&
+      (vertex_type->get_numeric_type() == NT_int8 ||
+       vertex_type->get_numeric_type() == NT_uint8)) {
+    int vertex_array = orig->get_array_with(InternalName::get_vertex());
+
+    PT(GeomVertexArrayFormat) new_array_format = new_format->modify_array(vertex_array);
+
+    // Replace the existing vertex format with the new format.
+    new_array_format->add_column
+      (InternalName::get_vertex(), 3, NT_int16,
+       C_point, vertex_type->get_start(), vertex_type->get_column_alignment());
+  }
+
+  // Convert packed formats that OpenGL may not understand.
+  for (int i = 0; i < orig->get_num_columns(); ++i) {
+    const GeomVertexColumn *column = orig->get_column(i);
+    int array = orig->get_array_with(column->get_name());
+
+    if (column->get_numeric_type() == NT_packed_dabc &&
+        !glgsg->_supports_packed_dabc) {
+      // Unpack the packed ARGB color into its four byte components.
+      PT(GeomVertexArrayFormat) array_format = new_format->modify_array(array);
+      array_format->add_column(column->get_name(), 4, NT_uint8, C_color,
+                               column->get_start(), column->get_column_alignment());
+
+    } else if (column->get_numeric_type() == NT_packed_ufloat &&
+               !glgsg->_supports_packed_ufloat) {
+      // Unpack to three 32-bit floats.  (In future, should try 16-bit float)
+      PT(GeomVertexArrayFormat) array_format = new_format->modify_array(array);
+      array_format->add_column(column->get_name(), 3, NT_float32,
+                               column->get_contents(), column->get_start(),
+                               column->get_column_alignment());
+    }
+  }
+#endif  // !OPENGLES
+
   const GeomVertexColumn *color_type = orig->get_color_column();
   if (color_type != (GeomVertexColumn *)NULL &&
       color_type->get_numeric_type() == NT_packed_dabc &&
@@ -99,8 +139,8 @@ munge_format_impl(const GeomVertexFormat *orig,
 
     // Replace the existing color format with the new format.
     new_array_format->add_column
-      (InternalName::get_color(), 4, NT_uint8,
-       C_color, color_type->get_start(), color_type->get_column_alignment());
+      (InternalName::get_color(), 4, NT_uint8, C_color,
+       color_type->get_start(), color_type->get_column_alignment());
   }
 
   if (animation.get_animation_type() == AT_hardware) {
@@ -237,21 +277,45 @@ premunge_format_impl(const GeomVertexFormat *orig) {
   CLP(GraphicsStateGuardian) *glgsg;
   DCAST_INTO_R(glgsg, get_gsg(), NULL);
 
-  const GeomVertexColumn *color_type = orig->get_color_column();
-  if (color_type != (GeomVertexColumn *)NULL &&
-      color_type->get_numeric_type() == NT_packed_dabc &&
-      !glgsg->_supports_packed_dabc) {
-    // We need to convert the color format; OpenGL doesn't support the
-    // byte order of DirectX's packed ARGB format.
-    int color_array = orig->get_array_with(InternalName::get_color());
+#ifndef OPENGLES
+  // OpenGL ES 1 does, but regular OpenGL doesn't support GL_BYTE vertices
+  // and texture coordinates.
+  const GeomVertexColumn *vertex_type = orig->get_vertex_column();
+  if (vertex_type != (GeomVertexColumn *)NULL &&
+      (vertex_type->get_numeric_type() == NT_int8 ||
+       vertex_type->get_numeric_type() == NT_uint8)) {
+    int vertex_array = orig->get_array_with(InternalName::get_vertex());
 
-    PT(GeomVertexArrayFormat) new_array_format = new_format->modify_array(color_array);
+    PT(GeomVertexArrayFormat) new_array_format = new_format->modify_array(vertex_array);
 
-    // Replace the existing color format with the new format.
+    // Replace the existing vertex format with the new format.
     new_array_format->add_column
-      (InternalName::get_color(), 4, NT_uint8,
-       C_color, color_type->get_start(), color_type->get_column_alignment());
+      (InternalName::get_vertex(), 3, NT_int16,
+       C_point, vertex_type->get_start(), vertex_type->get_column_alignment());
+  }
+
+  // Convert packed formats that OpenGL may not understand.
+  for (int i = 0; i < orig->get_num_columns(); ++i) {
+    const GeomVertexColumn *column = orig->get_column(i);
+    int array = orig->get_array_with(column->get_name());
+
+    if (column->get_numeric_type() == NT_packed_dabc &&
+        !glgsg->_supports_packed_dabc) {
+      // Unpack the packed ARGB color into its four byte components.
+      PT(GeomVertexArrayFormat) array_format = new_format->modify_array(array);
+      array_format->add_column(column->get_name(), 4, NT_uint8, C_color,
+                               column->get_start(), column->get_column_alignment());
+
+    } else if (column->get_numeric_type() == NT_packed_ufloat &&
+               !glgsg->_supports_packed_ufloat) {
+      // Unpack to three 32-bit floats.  (In future, should try 16-bit float)
+      PT(GeomVertexArrayFormat) array_format = new_format->modify_array(array);
+      array_format->add_column(column->get_name(), 3, NT_float32,
+                               column->get_contents(), column->get_start(),
+                               column->get_column_alignment());
+    }
   }
+#endif  // !OPENGLES
 
   CPT(GeomVertexFormat) format = GeomVertexFormat::register_format(new_format);
 

+ 35 - 7
panda/src/glstuff/glGraphicsBuffer_src.cxx

@@ -32,7 +32,8 @@ CLP(GraphicsBuffer)(GraphicsEngine *engine, GraphicsPipe *pipe,
   _generate_mipmap_pcollector(_draw_window_pcollector, "Generate mipmaps"),
   _resolve_multisample_pcollector(_draw_window_pcollector, "Resolve multisamples"),
   _requested_multisamples(0),
-  _requested_coverage_samples(0)
+  _requested_coverage_samples(0),
+  _rb_context(NULL)
 {
   // A FBO doesn't have a back buffer.
   _draw_buffer_type       = RenderBuffer::T_front;
@@ -50,6 +51,7 @@ CLP(GraphicsBuffer)(GraphicsEngine *engine, GraphicsPipe *pipe,
     _rb[i] = 0;
     _rbm[i] = 0;
   }
+  _rb_data_size_bytes = 0;
 
   _shared_depth_buffer = 0;
   _bound_tex_page = -1;
@@ -246,6 +248,7 @@ rebuild_bitplanes() {
     } else {
       glgsg->bind_fbo(0);
     }
+    _rb_context->set_active(true);
     return;
   }
 
@@ -273,6 +276,7 @@ rebuild_bitplanes() {
     rb_resize = true;
   }
   _rb_size_z = 1;
+  _rb_data_size_bytes = 0;
 
   int num_fbos = 1;
 
@@ -381,6 +385,10 @@ rebuild_bitplanes() {
       // buffer was requested.
       _use_depth_stencil = true;
     }
+  } else if (attach[RTP_depth_stencil] != NULL && attach[RTP_depth] == NULL) {
+    // The depth stencil slot was assigned a texture, but we don't support it.
+    // Downgrade to a regular depth texture.
+    swap(attach[RTP_depth], attach[RTP_depth_stencil]);
   }
 
   // Knowing this, we can already be a tiny bit more accurate about the
@@ -522,6 +530,9 @@ rebuild_bitplanes() {
     _fb_properties.set_rgba_bits(0, 0, 0, 0);
   }
 
+  _rb_context->set_active(true);
+  _rb_context->update_data_size_bytes(_rb_data_size_bytes);
+
   _initial_clear = false;
   report_my_gl_errors();
 
@@ -824,6 +835,7 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
       glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_STENCIL_SIZE_EXT, &stencil_size);
       _fb_properties.set_depth_bits(depth_size);
       _fb_properties.set_stencil_bits(stencil_size);
+      _rb_data_size_bytes += _rb_size_x * _rb_size_y * ((depth_size + stencil_size) / 8);
 
       glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, 0);
 
@@ -847,6 +859,7 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
       glgsg->_glRenderbufferStorage(GL_RENDERBUFFER_EXT, gl_format, _rb_size_x, _rb_size_y);
       glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &depth_size);
       _fb_properties.set_depth_bits(depth_size);
+      _rb_data_size_bytes += _rb_size_x * _rb_size_y * (depth_size / 8);
 
       glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, 0);
 
@@ -864,14 +877,17 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
       GLCAT.debug() << "Creating color renderbuffer.\n";
       glgsg->_glRenderbufferStorage(GL_RENDERBUFFER_EXT, gl_format, _rb_size_x, _rb_size_y);
 
+      GLint red_size = 0, green_size = 0, blue_size = 0, alpha_size = 0;
+      glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_RED_SIZE_EXT, &red_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_ALPHA_SIZE_EXT, &alpha_size);
+
       if (attachpoint == GL_COLOR_ATTACHMENT0_EXT) {
-        GLint red_size = 0, green_size = 0, blue_size = 0, alpha_size = 0;
-        glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_RED_SIZE_EXT, &red_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_ALPHA_SIZE_EXT, &alpha_size);
         _fb_properties.set_rgba_bits(red_size, green_size, blue_size, alpha_size);
       }
+      _rb_data_size_bytes += _rb_size_x * _rb_size_y * ((red_size + green_size + blue_size + alpha_size) / 8);
+
       glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, 0);
       glgsg->_glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, attachpoint,
                                         GL_RENDERBUFFER_EXT, _rb[slot]);
@@ -1232,6 +1248,10 @@ open_buffer() {
     return false;
   }
 
+  if (_rb_context == NULL) {
+    _rb_context = new BufferContext(&(glgsg->_renderbuffer_residency));
+  }
+
   // Describe the framebuffer properties of the FBO.
   //
   // Unfortunately, we can't currently predict which formats
@@ -1403,6 +1423,13 @@ open_buffer() {
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsBuffer)::
 close_buffer() {
+  _rb_data_size_bytes = 0;
+  if (_rb_context != NULL) {
+    _rb_context->update_data_size_bytes(0);
+    delete _rb_context;
+    _rb_context = NULL;
+  }
+
   check_host_valid();
 
   if (_gsg == 0) {
@@ -1421,13 +1448,14 @@ close_buffer() {
       _rb[i] = 0;
     }
   }
-  // Delete the renderbuffers.
+  // Delete the multisample renderbuffers.
   for (int i=0; i<RTP_COUNT; i++) {
     if (_rbm[i] != 0) {
       glgsg->_glDeleteRenderbuffers(1, &(_rbm[i]));
       _rb[i] = 0;
     }
   }
+
   _rb_size_x = 0;
   _rb_size_y = 0;
   report_my_gl_errors();

+ 4 - 1
panda/src/glstuff/glGraphicsBuffer_src.h

@@ -57,7 +57,6 @@
 //               the buffer will render as if multisamples is 0.
 //
 ////////////////////////////////////////////////////////////////////
-
 class EXPCL_GL CLP(GraphicsBuffer) : public GraphicsBuffer {
 public:
   CLP(GraphicsBuffer)(GraphicsEngine *engine, GraphicsPipe *pipe,
@@ -125,6 +124,10 @@ private:
   GLuint      _rb[RTP_COUNT];
   GLuint      _rbm[RTP_COUNT];
 
+  // For memory tracking of renderbuffers.
+  BufferContext *_rb_context;
+  size_t _rb_data_size_bytes;
+
   // List of textures for which we might have to generate mipmaps
   // after rendering one frame.
   typedef pvector<CLP(TextureContext)*> TextureContexts;

+ 211 - 41
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -313,7 +313,8 @@ int CLP(GraphicsStateGuardian)::get_driver_shader_version_minor() { return _gl_s
 ////////////////////////////////////////////////////////////////////
 CLP(GraphicsStateGuardian)::
 CLP(GraphicsStateGuardian)(GraphicsEngine *engine, GraphicsPipe *pipe) :
-  GraphicsStateGuardian(CS_yup_right, engine, pipe)
+  GraphicsStateGuardian(gl_coordinate_system, engine, pipe),
+  _renderbuffer_residency(get_prepared_objects()->get_name(), "renderbuffer")
 {
   _error_count = 0;
 
@@ -865,6 +866,17 @@ reset() {
   }
 #endif
 
+#ifndef OPENGLES
+  if (is_at_least_gl_version(3, 0)) {
+    _glTexBuffer = (PFNGLTEXBUFFERPROC)get_extension_func("glTexBuffer");
+    _supports_buffer_texture = true;
+
+  } else if (has_extension("GL_ARB_texture_buffer_object")) {
+    _glTexBuffer = (PFNGLTEXBUFFERPROC)get_extension_func("glTexBufferARB");
+    _supports_buffer_texture = true;
+  }
+#endif
+
   _supports_texture_srgb = false;
   if (is_at_least_gl_version(2, 1) || has_extension("GL_EXT_texture_sRGB")) {
     _supports_texture_srgb = true;
@@ -1013,9 +1025,13 @@ reset() {
 
 #ifdef OPENGLES
   _supports_packed_dabc = false;
+  _supports_packed_ufloat = false;
 #else
-  _supports_packed_dabc = /*gl_support_packed_dabc &&*/
-    has_extension("GL_ARB_vertex_array_bgra") || has_extension("GL_EXT_vertex_array_bgra");
+  _supports_packed_dabc = is_at_least_gl_version(3, 2) ||
+                          has_extension("GL_ARB_vertex_array_bgra") ||
+                          has_extension("GL_EXT_vertex_array_bgra");
+  _supports_packed_ufloat = is_at_least_gl_version(4, 4) ||
+                            has_extension("GL_ARB_vertex_type_10f_11f_11f_rev");
 #endif
 
   _supports_multisample =
@@ -1131,6 +1147,9 @@ reset() {
 #else
   _supports_depth_texture = (is_at_least_gl_version(1, 4) ||
                              has_extension("GL_ARB_depth_texture"));
+  _supports_depth_stencil = (is_at_least_gl_version(3, 0) ||
+                             has_extension("GL_ARB_framebuffer_object") ||
+                             has_extension("GL_EXT_packed_depth_stencil"));
 #endif
 
 #ifdef OPENGLES_2
@@ -1375,6 +1394,10 @@ reset() {
        get_extension_func("glUniformMatrix4fv");
     _glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)
        get_extension_func("glValidateProgram");
+    _glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC)
+       get_extension_func("glVertexAttrib4fv");
+    _glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC)
+       get_extension_func("glVertexAttrib4dv");
     _glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)
        get_extension_func("glVertexAttribPointer");
 
@@ -1440,6 +1463,8 @@ reset() {
   _glUniformMatrix3fv = glUniformMatrix3fv;
   _glUniformMatrix4fv = glUniformMatrix4fv;
   _glValidateProgram = glValidateProgram;
+  _glVertexAttrib4fv = glVertexAttrib4fv;
+  _glVertexAttrib4dv = NULL;
   _glVertexAttribPointer = glVertexAttribPointer;
   _glVertexAttribIPointer = NULL;
   _glVertexAttribLPointer = NULL;
@@ -1453,6 +1478,23 @@ reset() {
   }
 #endif
 
+#ifndef OPENGLES
+  // Check for uniform buffers.
+  if (is_at_least_gl_version(3, 1) || has_extension("GL_ARB_uniform_buffer_object")) {
+    _supports_uniform_buffers = true;
+    _glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC)
+       get_extension_func("glGetActiveUniformsiv");
+    _glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC)
+       get_extension_func("glGetActiveUniformBlockiv");
+    _glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)
+       get_extension_func("glGetActiveUniformBlockName");
+  } else {
+    _supports_uniform_buffers = false;
+  }
+#else
+  _supports_uniform_buffers = false;
+#endif
+
   // Check whether we support geometry instancing and instanced vertex attribs.
 #if defined(OPENGLES_1)
   _supports_vertex_attrib_divisor = false;
@@ -1965,6 +2007,7 @@ reset() {
   GLint max_3d_texture_size = 0;
   GLint max_2d_texture_array_layers = 0;
   GLint max_cube_map_size = 0;
+  GLint max_buffer_texture_size = 0;
 
   glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
   _max_texture_dimension = max_texture_size;
@@ -1990,6 +2033,15 @@ reset() {
     _max_cube_map_dimension = 0;
   }
 
+#ifndef OPENGLES
+  if (_supports_buffer_texture) {
+    glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &max_buffer_texture_size);
+    _max_buffer_texture_size = max_buffer_texture_size;
+  } else {
+    _max_buffer_texture_size = 0;
+  }
+#endif  // !OPENGLES
+
   GLint max_elements_vertices = 0, max_elements_indices = 0;
 #ifndef OPENGLES
   glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &max_elements_vertices);
@@ -2871,7 +2923,8 @@ calc_projection_mat(const Lens *lens) {
   // choice in the modelview matrix.
 
   LMatrix4 result =
-    LMatrix4::convert_mat(CS_yup_right, lens->get_coordinate_system()) *
+    LMatrix4::convert_mat(_internal_coordinate_system,
+                          lens->get_coordinate_system()) *
     lens->get_projection_mat(_current_stereo_channel);
 
   if (_scene_setup->get_inverted()) {
@@ -2931,6 +2984,8 @@ begin_frame(Thread *current_thread) {
   if (!GraphicsStateGuardian::begin_frame(current_thread)) {
     return false;
   }
+  _renderbuffer_residency.begin_frame(current_thread);
+
   report_my_gl_errors();
 
 #ifdef DO_PSTATS
@@ -3091,6 +3146,8 @@ end_frame(Thread *current_thread) {
 
   GraphicsStateGuardian::end_frame(current_thread);
 
+  _renderbuffer_residency.end_frame(current_thread);
+
   // Flush any PCollectors specific to this kind of GSG.
   _primitive_batches_display_list_pcollector.flush_level();
   _vertices_display_list_pcollector.flush_level();
@@ -3709,7 +3766,7 @@ update_standard_vertex_arrays(bool force) {
         return false;
       }
       glVertexPointer(num_values, get_numeric_type(numeric_type),
-                         stride, client_pointer + start);
+                      stride, client_pointer + start);
       glEnableClientState(GL_VERTEX_ARRAY);
     }
   }
@@ -3796,7 +3853,7 @@ disable_standard_vertex_arrays() {
 ////////////////////////////////////////////////////////////////////
 bool CLP(GraphicsStateGuardian)::
 draw_triangles(const GeomPrimitivePipelineReader *reader, bool force) {
-  PStatGPUTimer timer(this, _draw_primitive_pcollector, reader->get_current_thread());
+  //PStatGPUTimer timer(this, _draw_primitive_pcollector, reader->get_current_thread());
 
 #ifndef NDEBUG
   if (GLCAT.is_spam()) {
@@ -3863,7 +3920,7 @@ draw_triangles(const GeomPrimitivePipelineReader *reader, bool force) {
 ////////////////////////////////////////////////////////////////////
 bool CLP(GraphicsStateGuardian)::
 draw_tristrips(const GeomPrimitivePipelineReader *reader, bool force) {
-  PStatGPUTimer timer(this, _draw_primitive_pcollector, reader->get_current_thread());
+  //PStatGPUTimer timer(this, _draw_primitive_pcollector, reader->get_current_thread());
 
   report_my_gl_errors();
 
@@ -3990,7 +4047,8 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader, bool force) {
 ////////////////////////////////////////////////////////////////////
 bool CLP(GraphicsStateGuardian)::
 draw_trifans(const GeomPrimitivePipelineReader *reader, bool force) {
-  PStatGPUTimer timer(this, _draw_primitive_pcollector, reader->get_current_thread());
+  //PStatGPUTimer timer(this, _draw_primitive_pcollector, reader->get_current_thread());
+
 #ifndef NDEBUG
   if (GLCAT.is_spam()) {
     GLCAT.spam() << "draw_trifans: " << *(reader->get_object()) << "\n";
@@ -4070,7 +4128,7 @@ draw_trifans(const GeomPrimitivePipelineReader *reader, bool force) {
 ////////////////////////////////////////////////////////////////////
 bool CLP(GraphicsStateGuardian)::
 draw_patches(const GeomPrimitivePipelineReader *reader, bool force) {
-  PStatGPUTimer timer(this, _draw_primitive_pcollector, reader->get_current_thread());
+  //PStatGPUTimer timer(this, _draw_primitive_pcollector, reader->get_current_thread());
 
 #ifndef NDEBUG
   if (GLCAT.is_spam()) {
@@ -4146,7 +4204,8 @@ draw_patches(const GeomPrimitivePipelineReader *reader, bool force) {
 ////////////////////////////////////////////////////////////////////
 bool CLP(GraphicsStateGuardian)::
 draw_lines(const GeomPrimitivePipelineReader *reader, bool force) {
-  PStatGPUTimer timer(this, _draw_primitive_pcollector, reader->get_current_thread());
+  //PStatGPUTimer timer(this, _draw_primitive_pcollector, reader->get_current_thread());
+
 #ifndef NDEBUG
   if (GLCAT.is_spam()) {
     GLCAT.spam() << "draw_lines: " << *(reader->get_object()) << "\n";
@@ -4210,7 +4269,7 @@ draw_lines(const GeomPrimitivePipelineReader *reader, bool force) {
 ////////////////////////////////////////////////////////////////////
 bool CLP(GraphicsStateGuardian)::
 draw_linestrips(const GeomPrimitivePipelineReader *reader, bool force) {
-  PStatGPUTimer timer(this, _draw_primitive_pcollector, reader->get_current_thread());
+  //PStatGPUTimer timer(this, _draw_primitive_pcollector, reader->get_current_thread());
 
   report_my_gl_errors();
 
@@ -4334,7 +4393,8 @@ draw_linestrips(const GeomPrimitivePipelineReader *reader, bool force) {
 ////////////////////////////////////////////////////////////////////
 bool CLP(GraphicsStateGuardian)::
 draw_points(const GeomPrimitivePipelineReader *reader, bool force) {
-  PStatGPUTimer timer(this, _draw_primitive_pcollector, reader->get_current_thread());
+  //PStatGPUTimer timer(this, _draw_primitive_pcollector, reader->get_current_thread());
+
 #ifndef NDEBUG
   if (GLCAT.is_spam()) {
     GLCAT.spam() << "draw_points: " << *(reader->get_object()) << "\n";
@@ -4534,6 +4594,15 @@ prepare_texture(Texture *tex, int view) {
         << "Cube map textures are not supported by this OpenGL driver.\n";
       return NULL;
     }
+    break;
+
+  case Texture::TT_buffer_texture:
+    if (!_supports_buffer_texture) {
+      GLCAT.warning()
+        << "Buffer textures are not supported by this OpenGL driver.\n";
+      return NULL;
+    }
+    break;
 
   default:
     break;
@@ -6973,16 +7042,20 @@ query_gl_version() {
       _gl_shadlang_ver_major = 1;
       _gl_shadlang_ver_minor = 1;
       const char *verstr = (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION);
-      if (verstr == NULL || sscanf(verstr, "%d.%d", &_gl_shadlang_ver_major, &_gl_shadlang_ver_minor) != 2) {
-        GLCAT.warning()  << "Invalid GL_SHADING_LANGUAGE_VERSION format.\n";
+      if (verstr == NULL ||
+          sscanf(verstr, "%d.%d", &_gl_shadlang_ver_major,
+                                  &_gl_shadlang_ver_minor) != 2) {
+        GLCAT.warning() << "Invalid GL_SHADING_LANGUAGE_VERSION format.\n";
       }
     }
 #elif defined(OPENGLES_2)
     _gl_shadlang_ver_major = 1;
     _gl_shadlang_ver_minor = 0;
     const char *verstr = (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION);
-    if (verstr == NULL || sscanf(verstr, "OpenGL ES GLSL %d.%d", &_gl_shadlang_ver_major, &_gl_shadlang_ver_minor) != 2) {
-      GLCAT.warning()  << "Invalid GL_SHADING_LANGUAGE_VERSION format.\n";
+    if (verstr == NULL ||
+        sscanf(verstr, "OpenGL ES GLSL %d.%d", &_gl_shadlang_ver_major,
+                                               &_gl_shadlang_ver_minor) != 2) {
+      GLCAT.warning() << "Invalid GL_SHADING_LANGUAGE_VERSION format.\n";
     }
 #endif
   }
@@ -7360,6 +7433,26 @@ get_numeric_type(Geom::NumericType numeric_type) {
   case Geom::NT_stdfloat:
     // Shouldn't happen, display error.
     break;
+
+  case Geom::NT_int8:
+    return GL_BYTE;
+
+  case Geom::NT_int16:
+    return GL_SHORT;
+
+  case Geom::NT_int32:
+#ifndef OPENGLES_1
+    return GL_INT;
+#else
+    break;
+#endif
+
+  case Geom::NT_packed_ufloat:
+#ifndef OPENGLES
+    return GL_UNSIGNED_INT_10F_11F_11F_REV;
+#else
+    break;
+#endif
   }
 
   GLCAT.error()
@@ -7386,27 +7479,35 @@ get_texture_target(Texture::TextureType texture_type) const {
     return GL_TEXTURE_2D;
 
   case Texture::TT_3d_texture:
-    if (_supports_3d_texture) {
 #ifndef OPENGLES_1
+    if (_supports_3d_texture) {
       return GL_TEXTURE_3D;
-#endif
-    } else {
-      return GL_NONE;
     }
+#endif
+    return GL_NONE;
+
   case Texture::TT_2d_texture_array:
-    if (_supports_2d_texture_array) {
 #ifndef OPENGLES
+    if (_supports_2d_texture_array) {
       return GL_TEXTURE_2D_ARRAY_EXT;
-#endif
-    } else {
-      return GL_NONE;
     }
+#endif
+    return GL_NONE;
+
   case Texture::TT_cube_map:
     if (_supports_cube_map) {
       return GL_TEXTURE_CUBE_MAP;
     } else {
       return GL_NONE;
     }
+
+  case Texture::TT_buffer_texture:
+#ifndef OPENGLES
+    if (_supports_buffer_texture) {
+      return GL_TEXTURE_BUFFER;
+    }
+#endif
+    return GL_NONE;
   }
 
   GLCAT.error() << "Invalid Texture::TextureType value!\n";
@@ -10304,6 +10405,12 @@ specify_texture(CLP(TextureContext) *gtc, const SamplerState &sampler) {
     // Unsupported target (e.g. 3-d texturing on GL 1.1).
     return false;
   }
+#ifndef OPENGLES
+  if (target == GL_TEXTURE_BUFFER) {
+    // Buffer textures may not receive texture parameters.
+    return false;
+  }
+#endif  // OPENGLES
 
   // Record the active sampler settings.
   gtc->_active_sampler = sampler;
@@ -10557,7 +10664,8 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) {
 
   // If we'll use immutable texture storage, we have to pick a sized
   // image format.
-  bool force_sized = (gl_immutable_texture_storage && _supports_tex_storage);
+  bool force_sized = (gl_immutable_texture_storage && _supports_tex_storage) ||
+                     (tex->get_texture_type() == Texture::TT_buffer_texture);
 
   GLint internal_format = get_internal_image_format(tex, force_sized);
   GLint external_format = get_external_image_format(tex);
@@ -10605,6 +10713,12 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) {
     max_dimension_z = _max_2d_texture_array_layers;
     break;
 
+  case Texture::TT_buffer_texture:
+    max_dimension_x = _max_buffer_texture_size;
+    max_dimension_y = 1;
+    max_dimension_z = 1;
+    break;
+
   default:
     max_dimension_x = _max_texture_dimension;
     max_dimension_y = _max_texture_dimension;
@@ -10683,6 +10797,13 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) {
 
   GLenum target = get_texture_target(tex->get_texture_type());
   uses_mipmaps = (uses_mipmaps && !gl_ignore_mipmaps) || gl_force_mipmaps;
+#ifndef OPENGLES
+  if (target == GL_TEXTURE_BUFFER) {
+    // Buffer textures may not have mipmaps.
+    uses_mipmaps = false;
+  }
+#endif  // OPENGLES
+
   bool needs_reload = false;
   if (!gtc->_has_storage ||
       gtc->_uses_mipmaps != uses_mipmaps ||
@@ -10692,6 +10813,12 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) {
       gtc->_depth != depth) {
     // We need to reload a new GL Texture object.
     needs_reload = true;
+
+    if (_use_object_labels) {
+      // This seems like a good time to assign a label for the debug messages.
+      const string &name = tex->get_name();
+      _glObjectLabel(GL_TEXTURE, gtc->_index, name.size(), name.data());
+    }
   }
 
   if (needs_reload && gtc->_immutable) {
@@ -10700,13 +10827,26 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) {
     glBindTexture(target, gtc->_index);
   }
 
-  if (needs_reload) {
-    if (_use_object_labels) {
-      // This seems like a good time to assign a label for the debug messages.
-      const string &name = tex->get_name();
-      _glObjectLabel(GL_TEXTURE, gtc->_index, name.size(), name.data());
-    }
+#ifndef OPENGLES
+  if (target == GL_TEXTURE_BUFFER) {
+    // Buffer textures don't support mipmappping.
+    gtc->_generate_mipmaps = false;
 
+    if (gtc->_buffer == 0) {
+      // The buffer object wasn't created yet.
+      _glGenBuffers(1, &gtc->_buffer);
+      _glBindBuffer(GL_TEXTURE_BUFFER, gtc->_buffer);
+      _glTexBuffer(GL_TEXTURE_BUFFER, internal_format, gtc->_buffer);
+      needs_reload = true;
+    } else {
+      _glBindBuffer(GL_TEXTURE_BUFFER, gtc->_buffer);
+      if (gtc->_internal_format != internal_format) {
+        _glTexBuffer(GL_TEXTURE_BUFFER, internal_format, gtc->_buffer);
+      }
+    }
+  } else
+#endif  // !OPENGLES
+  if (needs_reload) {
     // Figure out whether mipmaps will be generated by the GPU or by
     // Panda (or not at all), and how many mipmap levels should be created.
     gtc->_generate_mipmaps = false;
@@ -10788,6 +10928,8 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) {
       }
 
       switch (tex->get_texture_type()) {
+      case Texture::TT_buffer_texture:
+        // Won't get here, but squelch compiler warning
       case Texture::TT_1d_texture:
         _glTexStorage1D(target, num_levels, internal_format, width);
         break;
@@ -10903,9 +11045,7 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) {
       gtc->_width = width;
       gtc->_height = height;
       gtc->_depth = depth;
-    }
 
-    if (!image.is_null()) {
       gtc->update_data_size_bytes(get_texture_memory_size(tex));
     }
 
@@ -11147,6 +11287,17 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
         break;
 #endif  // OPENGLES
 
+#ifndef OPENGLES
+      case GL_TEXTURE_BUFFER:
+        if (_supports_buffer_texture) {
+          _glBufferSubData(GL_TEXTURE_BUFFER, 0, view_size, image_ptr);
+        } else {
+          report_my_gl_errors();
+          return false;
+        }
+        break;
+#endif  // OPENGLES
+
       default:
         if (image_compression == Texture::CM_off) {
           if (n==0) {
@@ -11300,6 +11451,7 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
         }
         break;
 #endif
+
 #ifndef OPENGLES
       case GL_TEXTURE_2D_ARRAY_EXT:
         if (_supports_2d_texture_array) {
@@ -11317,7 +11469,19 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
           return false;
         }
         break;
-#endif
+#endif  // OPENGLES
+
+#ifndef OPENGLES
+      case GL_TEXTURE_BUFFER:
+        if (_supports_buffer_texture) {
+          _glBufferData(GL_TEXTURE_BUFFER, view_size, image_ptr,
+                        get_usage(tex->get_usage_hint()));
+        } else {
+          report_my_gl_errors();
+          return false;
+        }
+        break;
+#endif  // OPENGLES
 
       default:
         if (image_compression == Texture::CM_off) {
@@ -11448,6 +11612,12 @@ get_texture_memory_size(Texture *tex) {
     // We need a particular page to get the level parameter from.
     page_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
     scale = 6;
+
+  } else if (target == GL_TEXTURE_BUFFER) {
+    // In the case of buffer textures, we provided the size to begin with,
+    // so no point in querying anything.  Plus, glGetTexParameter is not even
+    // supported for buffer textures.
+    return tex->get_expected_ram_image_size();
   }
 
   GLint minfilter;
@@ -11483,20 +11653,20 @@ get_texture_memory_size(Texture *tex) {
     luminance_size, intensity_size;
   GLint depth_size = 0;
   glGetTexLevelParameteriv(page_target, 0,
-                              GL_TEXTURE_RED_SIZE, &red_size);
+                           GL_TEXTURE_RED_SIZE, &red_size);
   glGetTexLevelParameteriv(page_target, 0,
-                              GL_TEXTURE_GREEN_SIZE, &green_size);
+                           GL_TEXTURE_GREEN_SIZE, &green_size);
   glGetTexLevelParameteriv(page_target, 0,
-                              GL_TEXTURE_BLUE_SIZE, &blue_size);
+                           GL_TEXTURE_BLUE_SIZE, &blue_size);
   glGetTexLevelParameteriv(page_target, 0,
-                              GL_TEXTURE_ALPHA_SIZE, &alpha_size);
+                           GL_TEXTURE_ALPHA_SIZE, &alpha_size);
   glGetTexLevelParameteriv(page_target, 0,
-                              GL_TEXTURE_LUMINANCE_SIZE, &luminance_size);
+                           GL_TEXTURE_LUMINANCE_SIZE, &luminance_size);
   glGetTexLevelParameteriv(page_target, 0,
-                              GL_TEXTURE_INTENSITY_SIZE, &intensity_size);
+                           GL_TEXTURE_INTENSITY_SIZE, &intensity_size);
   if (_supports_depth_texture) {
     glGetTexLevelParameteriv(page_target, 0,
-                                GL_TEXTURE_DEPTH_SIZE, &depth_size);
+                             GL_TEXTURE_DEPTH_SIZE, &depth_size);
   }
 
   GLint width = 1, height = 1, depth = 1;

+ 15 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -180,6 +180,8 @@ typedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, con
 typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
 typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
 typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v);
 typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer);
 typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
 typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
@@ -636,6 +638,7 @@ protected:
   GLint _max_image_units;
   bool _supports_multi_bind;
   bool _supports_get_program_binary;
+  bool _supports_uniform_buffers;
 
 #ifdef OPENGLES
   bool _supports_depth24;
@@ -695,6 +698,10 @@ public:
   PFNGLTEXSTORAGE2DPROC _glTexStorage2D;
   PFNGLTEXSTORAGE3DPROC _glTexStorage3D;
 
+#ifndef OPENGLES
+  PFNGLTEXBUFFERPROC _glTexBuffer;
+#endif
+
   bool _supports_clear_texture;
 #ifndef OPENGLES
   PFNGLCLEARTEXIMAGEPROC _glClearTexImage;
@@ -711,6 +718,7 @@ public:
   bool _supports_bgr;
   bool _supports_rescale_normal;
   bool _supports_packed_dabc;
+  bool _supports_packed_ufloat;
 
   PFNGLACTIVETEXTUREPROC _glActiveTexture;
 #ifndef OPENGLES_2
@@ -830,6 +838,8 @@ public:
   PFNGLUNIFORMMATRIX3FVPROC _glUniformMatrix3fv;
   PFNGLUNIFORMMATRIX4FVPROC _glUniformMatrix4fv;
   PFNGLVALIDATEPROGRAMPROC _glValidateProgram;
+  PFNGLVERTEXATTRIB4FVPROC _glVertexAttrib4fv;
+  PFNGLVERTEXATTRIB4DVPROC _glVertexAttrib4dv;
   PFNGLVERTEXATTRIBPOINTERPROC _glVertexAttribPointer;
   PFNGLVERTEXATTRIBIPOINTERPROC _glVertexAttribIPointer;
   PFNGLVERTEXATTRIBLPOINTERPROC _glVertexAttribLPointer;
@@ -838,6 +848,9 @@ public:
   PFNGLDRAWELEMENTSINSTANCEDPROC _glDrawElementsInstanced;
 #endif  // !OPENGLES_1
 #ifndef OPENGLES
+  PFNGLGETACTIVEUNIFORMSIVPROC _glGetActiveUniformsiv;
+  PFNGLGETACTIVEUNIFORMBLOCKIVPROC _glGetActiveUniformBlockiv;
+  PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC _glGetActiveUniformBlockName;
   PFNGLGENSAMPLERSPROC _glGenSamplers;
   PFNGLDELETESAMPLERSPROC _glDeleteSamplers;
   PFNGLBINDSAMPLERPROC _glBindSampler;
@@ -918,6 +931,8 @@ public:
   UsageTextures _usage_textures;
 #endif  // NDEBUG
 
+  BufferResidencyTracker _renderbuffer_residency;
+
   static PStatCollector _load_display_list_pcollector;
   static PStatCollector _primitive_batches_display_list_pcollector;
   static PStatCollector _vertices_display_list_pcollector;

File diff suppressed because it is too large
+ 1074 - 700
panda/src/glstuff/glShaderContext_src.cxx


+ 17 - 3
panda/src/glstuff/glShaderContext_src.h

@@ -20,6 +20,7 @@
 #include "shader.h"
 #include "shaderContext.h"
 #include "deletedChain.h"
+#include "paramTexture.h"
 
 class CLP(GraphicsStateGuardian);
 
@@ -35,6 +36,14 @@ public:
   ~CLP(ShaderContext)();
   ALLOC_DELETED_CHAIN(CLP(ShaderContext));
 
+  void reflect_attribute(int i, char *name_buf, GLsizei name_buflen);
+#ifndef OPENGLES
+  void reflect_uniform_block(int i, const char *block_name,
+                             char *name_buffer, GLsizei name_buflen);
+#endif
+  void reflect_uniform(int i, char *name_buffer, GLsizei name_buflen);
+  bool get_sampler_texture_type(int &out, GLenum param_type);
+
   INLINE bool valid(void);
   void bind(bool reissue_parameters = true);
   void unbind();
@@ -49,6 +58,7 @@ public:
   INLINE bool uses_custom_texture_bindings(void);
 
 private:
+  bool _validated;
   GLuint _glsl_program;
   typedef pvector<GLuint> GLSLShaders;
   GLSLShaders _glsl_shaders;
@@ -63,11 +73,15 @@ private:
   //typedef pvector<ParamContext> ParamContexts;
   //ParamContexts _params;
 
-  pvector<GLint> _glsl_parameter_map;
+  GLint _color_attrib_index;
   pmap<GLint, GLuint64> _glsl_uniform_handles;
 
-  pvector<CPT(InternalName)> _glsl_img_inputs;
-  pvector<CLP(TextureContext)*> _glsl_img_textures;
+  struct ImageInput {
+    CPT(InternalName) _name;
+    CLP(TextureContext) *_gtc;
+    bool _writable;
+  };
+  pvector<ImageInput> _glsl_img_inputs;
 
   CLP(GraphicsStateGuardian) *_glgsg;
 

+ 1 - 0
panda/src/glstuff/glTextureContext_src.I

@@ -26,6 +26,7 @@ CLP(TextureContext)(CLP(GraphicsStateGuardian) *glgsg,
   _glgsg = glgsg;
 
   glGenTextures(1, &_index);
+  _buffer = 0;
 
   _handle = 0;
   _has_storage = false;

+ 10 - 0
panda/src/glstuff/glTextureContext_src.cxx

@@ -34,6 +34,11 @@ CLP(TextureContext)::
 
   glDeleteTextures(1, &_index);
   _index = 0;
+
+  if (_buffer != 0) {
+    _glgsg->_glDeleteBuffers(1, &_buffer);
+    _buffer = 0;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -88,6 +93,11 @@ reset_data() {
   // Free the texture resources.
   glDeleteTextures(1, &_index);
 
+  if (_buffer != 0) {
+    _glgsg->_glDeleteBuffers(1, &_buffer);
+    _buffer = 0;
+  }
+
   // We still need a valid index number, though, in case we want to
   // re-load the texture later.
   glGenTextures(1, &_index);

+ 3 - 0
panda/src/glstuff/glTextureContext_src.h

@@ -48,6 +48,9 @@ public:
   // This is the GL "name" of the texture object.
   GLuint _index;
 
+  // This is only used for buffer textures.
+  GLuint _buffer;
+
   // This is the bindless "handle" to the texture object.
   GLuint64 _handle;
   bool _handle_resident;

+ 15 - 0
panda/src/glstuff/glmisc_src.cxx

@@ -222,6 +222,12 @@ ConfigVariableBool gl_dump_compiled_shaders
             "programs to disk with a filename like glsl_program0.dump "
             "into the current directory."));
 
+ConfigVariableBool gl_validate_shaders
+  ("gl-validate-shaders", true,
+   PRC_DESC("Set this to true to enable glValidateShader the first time "
+            "a shader is bound.  This may cause helpful information about "
+            "shaders to be printed."));
+
 ConfigVariableBool gl_immutable_texture_storage
   ("gl-immutable-texture-storage", false,
    PRC_DESC("This configures Panda to pre-allocate immutable storage "
@@ -278,6 +284,15 @@ ConfigVariableBool gl_support_shadow_filter
             "cards suffered from a broken implementation of the "
             "shadow map filtering features."));
 
+ConfigVariableEnum<CoordinateSystem> gl_coordinate_system
+  ("gl-coordinate-system", CS_yup_right,
+   PRC_DESC("Which coordinate system to use as the internal "
+            "coordinate system for OpenGL operations.  If you are "
+            "using features like fixed-function sphere mapping, it is "
+            "best to leave this to yup-right.  However, if you are "
+            "creating a shader-only application, it may be easier and "
+            "more efficient to set this to default."));
+
 extern ConfigVariableBool gl_parallel_arrays;
 
 void CLP(init_classes)() {

+ 3 - 0
panda/src/glstuff/glmisc_src.h

@@ -17,6 +17,7 @@
 #include "configVariableInt.h"
 #include "configVariableEnum.h"
 #include "geomEnums.h"
+#include "coordinateSystem.h"
 
 // Define some macros to transparently map to the double or float
 // versions of the OpenGL function names.
@@ -69,6 +70,7 @@ extern ConfigVariableBool gl_force_flush;
 extern ConfigVariableBool gl_separate_specular_color;
 extern ConfigVariableBool gl_cube_map_seamless;
 extern ConfigVariableBool gl_dump_compiled_shaders;
+extern ConfigVariableBool gl_validate_shaders;
 extern ConfigVariableBool gl_immutable_texture_storage;
 extern ConfigVariableBool gl_use_bindless_texture;
 extern ConfigVariableBool gl_enable_memory_barriers;
@@ -76,6 +78,7 @@ extern ConfigVariableBool gl_vertex_array_objects;
 extern ConfigVariableBool gl_support_primitive_restart_index;
 extern ConfigVariableBool gl_support_sampler_objects;
 extern ConfigVariableBool gl_support_shadow_filter;
+extern ConfigVariableEnum<CoordinateSystem> gl_coordinate_system;
 
 extern EXPCL_GL void CLP(init_classes)();
 

+ 6 - 1
panda/src/gobj/config_gobj.cxx

@@ -255,6 +255,11 @@ ConfigVariableBool dump_generated_shaders
           "to disk.  This is useful for debugging broken shader "
           "generators."));
 
+ConfigVariableBool cache_generated_shaders
+("cache-generated-shaders", true,
+ PRC_DESC("Set this true to cause all generated shaders to be cached in "
+          "memory.  This is useful to prevent unnecessary recompilation."));
+
 ConfigVariableBool enforce_attrib_lock
 ("enforce-attrib-lock", true,
  PRC_DESC("When a MaterialAttrib, TextureAttrib, or LightAttrib is "
@@ -279,7 +284,7 @@ ConfigVariableBool vertices_float64
           "slower."));
 
 ConfigVariableInt vertex_column_alignment
-("vertex-column-alignment", 1,
+("vertex-column-alignment", 4,
  PRC_DESC("This specifies the default byte alignment for each column of "
           "data within a GeomVertexData when it is assembled using the default "
           "interfaces.  Normally, you should not change this config variable "

+ 1 - 0
panda/src/gobj/config_gobj.h

@@ -64,6 +64,7 @@ extern EXPCL_PANDA_GOBJ ConfigVariableBool display_list_animation;
 extern EXPCL_PANDA_GOBJ ConfigVariableBool connect_triangle_strips;
 extern EXPCL_PANDA_GOBJ ConfigVariableBool preserve_triangle_strips;
 extern EXPCL_PANDA_GOBJ ConfigVariableBool dump_generated_shaders;
+extern EXPCL_PANDA_GOBJ ConfigVariableBool cache_generated_shaders;
 extern EXPCL_PANDA_GOBJ ConfigVariableBool enforce_attrib_lock;
 extern EXPCL_PANDA_GOBJ ConfigVariableBool vertices_float64;
 extern EXPCL_PANDA_GOBJ ConfigVariableInt vertex_column_alignment;

+ 12 - 0
panda/src/gobj/geomEnums.cxx

@@ -101,6 +101,18 @@ operator << (ostream &out, GeomEnums::NumericType numeric_type) {
 
   case GeomEnums::NT_stdfloat:
     return out << "stdfloat";
+
+  case GeomEnums::NT_int8:
+    return out << "int8";
+
+  case GeomEnums::NT_int16:
+    return out << "int16";
+
+  case GeomEnums::NT_int32:
+    return out << "int32";
+
+  case GeomEnums::NT_packed_ufloat:
+    return out << "packed_ufloat";
   }
 
   return out << "**invalid numeric type (" << (int)numeric_type << ")**";

+ 8 - 4
panda/src/gobj/geomEnums.h

@@ -144,12 +144,12 @@ PUBLISHED:
     // SM_uniform: all vertices across all faces have the same colors
     // and normals.  It doesn't really matter which ShadeModelAttrib
     // mode is used to render this primitive.
-    SM_uniform, 
+    SM_uniform,
 
     // SM_smooth: vertices within a single face have different
     // colors/normals that should be smoothed across the face.  This
     // primitive should be rendered with SmoothModelAttrib::M_smooth.
-    SM_smooth,  
+    SM_smooth,
 
     // SM_flat_(first,last)_vertex: each face within the primitive
     // might have a different color/normal than the other faces, but
@@ -177,12 +177,16 @@ PUBLISHED:
   enum NumericType {
     NT_uint8,        // An integer 0..255
     NT_uint16,       // An integer 0..65535
-    NT_uint32,       // An integer 0..4294967296
+    NT_uint32,       // An integer 0..4294967295
     NT_packed_dcba,  // DirectX style, four byte values packed in a uint32
     NT_packed_dabc,  // DirectX packed color order (ARGB)
     NT_float32,      // A single-precision float
     NT_float64,      // A double-precision float
-    NT_stdfloat      // Either single- or double-precision, according to vertices-float64.
+    NT_stdfloat,     // Either single- or double-precision, according to vertices-float64.
+    NT_int8,         // An integer -128..127
+    NT_int16,        // An integer -32768..32767
+    NT_int32,        // An integer -2147483648..2147483647
+    NT_packed_ufloat,// Three 10/11-bit float components packed in a uint32
   };
 
   // The contents determine the semantic meaning of a numeric value

+ 2 - 0
panda/src/gobj/geomPrimitive.cxx

@@ -22,6 +22,8 @@
 #include "geomVertexWriter.h"
 #include "geomVertexRewriter.h"
 #include "geomPoints.h"
+#include "geomLines.h"
+#include "geomTriangles.h"
 #include "preparedGraphicsObjects.h"
 #include "internalName.h"
 #include "bamReader.h"

+ 17 - 0
panda/src/gobj/geomVertexArrayFormat.cxx

@@ -627,20 +627,37 @@ get_format_string(bool pad) const {
     case NT_uint8:
       fmt_code = 'B';
       break;
+
     case NT_uint16:
       fmt_code = 'H';
       break;
+
     case NT_uint32:
     case NT_packed_dcba:
     case NT_packed_dabc:
       fmt_code = 'I';
       break;
+
     case NT_float32:
       fmt_code = 'f';
       break;
+
     case NT_float64:
       fmt_code = 'd';
       break;
+
+    case NT_int8:
+      fmt_code = 'b';
+      break;
+
+    case NT_int16:
+      fmt_code = 'h';
+      break;
+
+    case NT_int32:
+      fmt_code = 'i';
+      break;
+
     default:
       gobj_cat.error()
         << "Unknown numeric type " << column->get_numeric_type() << "!\n";

+ 12 - 293
panda/src/gobj/geomVertexColumn.I

@@ -33,13 +33,16 @@ GeomVertexColumn() :
 INLINE GeomVertexColumn::
 GeomVertexColumn(CPT_InternalName name, int num_components,
                  NumericType numeric_type, Contents contents,
-                 int start, int column_alignment) :
+                 int start, int column_alignment, int num_elements,
+                 int element_stride) :
   _name(MOVE(name)),
   _num_components(num_components),
   _numeric_type(numeric_type),
   _contents(contents),
   _start(start),
   _column_alignment(column_alignment),
+  _num_elements(num_elements),
+  _element_stride(element_stride),
   _packer(NULL)
 {
   setup();
@@ -58,6 +61,8 @@ GeomVertexColumn(const GeomVertexColumn &copy) :
   _contents(copy._contents),
   _start(copy._start),
   _column_alignment(copy._column_alignment),
+  _num_elements(copy._num_elements),
+  _element_stride(copy._element_stride),
   _packer(NULL)
 {
   setup();
@@ -317,6 +322,12 @@ compare_to(const GeomVertexColumn &other) const {
   if (_column_alignment != other._column_alignment) {
     return _column_alignment - other._column_alignment;
   }
+  if (_num_elements != other._num_elements) {
+    return _num_elements - other._num_elements;
+  }
+  if (_element_stride != other._element_stride) {
+    return _element_stride - other._element_stride;
+  }
   return 0;
 }
 
@@ -365,295 +376,3 @@ operator << (ostream &out, const GeomVertexColumn &obj) {
   obj.output(out);
   return out;
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexColumn::Packer::maybe_scale_color_f
-//       Access: Public
-//  Description: Converts an integer (typically a uint8) value to a
-//               floating-point value.  If the contents value
-//               indicates this is a color value, scales it into the
-//               range 0..1 per convention; otherwise leaves it alone.
-////////////////////////////////////////////////////////////////////
-INLINE float GeomVertexColumn::Packer::
-maybe_scale_color_f(unsigned int value) {
-  if (_column->get_contents() == C_color) {
-    return (float)value / 255.0f;
-  } else {
-    return (float)value;
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexColumn::Packer::maybe_scale_color_f
-//       Access: Public
-//  Description: Converts a pair of integers into the _v2 member.  See
-//               one-parameter maybe_scale_color_f() for more info.
-////////////////////////////////////////////////////////////////////
-INLINE void GeomVertexColumn::Packer::
-maybe_scale_color_f(unsigned int a, unsigned int b) {
-  if (_column->get_contents() == C_color) {
-    _v2.set((float)a / 255.0f,
-            (float)b / 255.0f);
-  } else {
-    _v2.set((float)a, (float)b);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexColumn::Packer::maybe_scale_color_f
-//       Access: Public
-//  Description: Converts a pair of integers into the _v3 member.  See
-//               one-parameter maybe_scale_color_f() for more info.
-////////////////////////////////////////////////////////////////////
-INLINE void GeomVertexColumn::Packer::
-maybe_scale_color_f(unsigned int a, unsigned int b, unsigned int c) {
-  if (_column->get_contents() == C_color) {
-    _v3.set((float)a / 255.0f,
-            (float)b / 255.0f,
-            (float)c / 255.0f);
-  } else {
-    _v3.set((float)a, (float)b, (float)c);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexColumn::Packer::maybe_scale_color_f
-//       Access: Public
-//  Description: Converts a pair of integers into the _v4 member.  See
-//               one-parameter maybe_scale_color_f() for more info.
-////////////////////////////////////////////////////////////////////
-INLINE void GeomVertexColumn::Packer::
-maybe_scale_color_f(unsigned int a, unsigned int b, unsigned int c,
-                    unsigned int d) {
-  if (_column->get_contents() == C_color) {
-    _v4.set((float)a / 255.0f,
-            (float)b / 255.0f,
-            (float)c / 255.0f,
-            (float)d / 255.0f);
-  } else {
-    _v4.set((float)a, (float)b, (float)c, (float)d);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexColumn::Packer::maybe_unscale_color_f
-//       Access: Public
-//  Description: Converts a floating-point value to a uint8 value.  If
-//               the contents value indicates this is a color value,
-//               scales it into the range 0..255 per convention;
-//               otherwise leaves it alone.
-////////////////////////////////////////////////////////////////////
-INLINE unsigned int GeomVertexColumn::Packer::
-maybe_unscale_color_f(float data) {
-  if (_column->get_contents() == C_color) {
-    return (unsigned int)(data * 255.0f);
-  } else {
-    return (unsigned int)data;
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexColumn::Packer::maybe_unscale_color_f
-//       Access: Public
-//  Description: Converts an LVecBase2f into a pair of uint8
-//               values.  See one-parameter maybe_unscale_color_f() for
-//               more info.
-////////////////////////////////////////////////////////////////////
-INLINE void GeomVertexColumn::Packer::
-maybe_unscale_color_f(const LVecBase2f &data) {
-  if (_column->get_contents() == C_color) {
-    _a = (unsigned int)(data[0] * 255.0f);
-    _b = (unsigned int)(data[1] * 255.0f);
-  } else {
-    _a = (unsigned int)data[0];
-    _b = (unsigned int)data[1];
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexColumn::Packer::maybe_unscale_color_f
-//       Access: Public
-//  Description: Converts an LVecBase3f into a pair of uint8
-//               values.  See one-parameter maybe_unscale_color_f() for
-//               more info.
-////////////////////////////////////////////////////////////////////
-INLINE void GeomVertexColumn::Packer::
-maybe_unscale_color_f(const LVecBase3f &data) {
-  if (_column->get_contents() == C_color) {
-    _a = (unsigned int)(data[0] * 255.0f);
-    _b = (unsigned int)(data[1] * 255.0f);
-    _c = (unsigned int)(data[2] * 255.0f);
-  } else {
-    _a = (unsigned int)data[0];
-    _b = (unsigned int)data[1];
-    _c = (unsigned int)data[2];
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexColumn::Packer::maybe_unscale_color_f
-//       Access: Public
-//  Description: Converts an LVecBase4f into a pair of uint8
-//               values.  See one-parameter maybe_unscale_color_f() for
-//               more info.
-////////////////////////////////////////////////////////////////////
-INLINE void GeomVertexColumn::Packer::
-maybe_unscale_color_f(const LVecBase4f &data) {
-  if (_column->get_contents() == C_color) {
-    _a = (unsigned int)(data[0] * 255.0f);
-    _b = (unsigned int)(data[1] * 255.0f);
-    _c = (unsigned int)(data[2] * 255.0f);
-    _d = (unsigned int)(data[3] * 255.0f);
-  } else {
-    _a = (unsigned int)data[0];
-    _b = (unsigned int)data[1];
-    _c = (unsigned int)data[2];
-    _d = (unsigned int)data[3];
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexColumn::Packer::maybe_scale_color_d
-//       Access: Public
-//  Description: Converts an integer (typically a uint8) value to a
-//               floating-point value.  If the contents value
-//               indicates this is a color value, scales it into the
-//               range 0..1 per convention; otherwise leaves it alone.
-////////////////////////////////////////////////////////////////////
-INLINE double GeomVertexColumn::Packer::
-maybe_scale_color_d(unsigned int value) {
-  if (_column->get_contents() == C_color) {
-    return (double)value / 255.0;
-  } else {
-    return (double)value;
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexColumn::Packer::maybe_scale_color_d
-//       Access: Public
-//  Description: Converts a pair of integers into the _v2d member.  See
-//               one-parameter maybe_scale_color_d() for more info.
-////////////////////////////////////////////////////////////////////
-INLINE void GeomVertexColumn::Packer::
-maybe_scale_color_d(unsigned int a, unsigned int b) {
-  if (_column->get_contents() == C_color) {
-    _v2d.set((double)a / 255.0,
-             (double)b / 255.0);
-  } else {
-    _v2d.set((double)a, (double)b);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexColumn::Packer::maybe_scale_color_d
-//       Access: Public
-//  Description: Converts a pair of integers into the _v3d member.  See
-//               one-parameter maybe_scale_color_d() for more info.
-////////////////////////////////////////////////////////////////////
-INLINE void GeomVertexColumn::Packer::
-maybe_scale_color_d(unsigned int a, unsigned int b, unsigned int c) {
-  if (_column->get_contents() == C_color) {
-    _v3d.set((double)a / 255.0,
-             (double)b / 255.0,
-             (double)c / 255.0);
-  } else {
-    _v3d.set((double)a, (double)b, (double)c);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexColumn::Packer::maybe_scale_color_d
-//       Access: Public
-//  Description: Converts a pair of integers into the _v4d member.  See
-//               one-parameter maybe_scale_color_d() for more info.
-////////////////////////////////////////////////////////////////////
-INLINE void GeomVertexColumn::Packer::
-maybe_scale_color_d(unsigned int a, unsigned int b, unsigned int c,
-                    unsigned int d) {
-  if (_column->get_contents() == C_color) {
-    _v4d.set((double)a / 255.0,
-             (double)b / 255.0,
-             (double)c / 255.0,
-             (double)d / 255.0);
-  } else {
-    _v4d.set((double)a, (double)b, (double)c, (double)d);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexColumn::Packer::maybe_unscale_color_d
-//       Access: Public
-//  Description: Converts a floating-point value to a uint8 value.  If
-//               the contents value indicates this is a color value,
-//               scales it into the range 0..255 per convention;
-//               otherwise leaves it alone.
-////////////////////////////////////////////////////////////////////
-INLINE unsigned int GeomVertexColumn::Packer::
-maybe_unscale_color_d(double data) {
-  if (_column->get_contents() == C_color) {
-    return (unsigned int)(data * 255.0);
-  } else {
-    return (unsigned int)data;
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexColumn::Packer::maybe_unscale_color_d
-//       Access: Public
-//  Description: Converts an LVecBase2d into a pair of uint8
-//               values.  See one-parameter maybe_unscale_color_d() for
-//               more info.
-////////////////////////////////////////////////////////////////////
-INLINE void GeomVertexColumn::Packer::
-maybe_unscale_color_d(const LVecBase2d &data) {
-  if (_column->get_contents() == C_color) {
-    _a = (unsigned int)(data[0] * 255.0);
-    _b = (unsigned int)(data[1] * 255.0);
-  } else {
-    _a = (unsigned int)data[0];
-    _b = (unsigned int)data[1];
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexColumn::Packer::maybe_unscale_color_d
-//       Access: Public
-//  Description: Converts an LVecBase3d into a pair of uint8
-//               values.  See one-parameter maybe_unscale_color_d() for
-//               more info.
-////////////////////////////////////////////////////////////////////
-INLINE void GeomVertexColumn::Packer::
-maybe_unscale_color_d(const LVecBase3d &data) {
-  if (_column->get_contents() == C_color) {
-    _a = (unsigned int)(data[0] * 255.0);
-    _b = (unsigned int)(data[1] * 255.0);
-    _c = (unsigned int)(data[2] * 255.0);
-  } else {
-    _a = (unsigned int)data[0];
-    _b = (unsigned int)data[1];
-    _c = (unsigned int)data[2];
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexColumn::Packer::maybe_unscale_color_d
-//       Access: Public
-//  Description: Converts an LVecBase4d into a pair of uint8
-//               values.  See one-parameter maybe_unscale_color_d() for
-//               more info.
-////////////////////////////////////////////////////////////////////
-INLINE void GeomVertexColumn::Packer::
-maybe_unscale_color_d(const LVecBase4d &data) {
-  if (_column->get_contents() == C_color) {
-    _a = (unsigned int)(data[0] * 255.0);
-    _b = (unsigned int)(data[1] * 255.0);
-    _c = (unsigned int)(data[2] * 255.0);
-    _d = (unsigned int)(data[3] * 255.0);
-  } else {
-    _a = (unsigned int)data[0];
-    _b = (unsigned int)data[1];
-    _c = (unsigned int)data[2];
-    _d = (unsigned int)data[3];
-  }
-}

File diff suppressed because it is too large
+ 375 - 129
panda/src/gobj/geomVertexColumn.cxx


+ 25 - 34
panda/src/gobj/geomVertexColumn.h

@@ -43,7 +43,8 @@ private:
 PUBLISHED:
   INLINE GeomVertexColumn(CPT_InternalName name, int num_components,
                           NumericType numeric_type, Contents contents,
-                          int start, int column_alignment = 0);
+                          int start, int column_alignment = 0,
+                          int num_elements = 0, int element_stride = 0);
   INLINE GeomVertexColumn(const GeomVertexColumn &copy);
   void operator = (const GeomVertexColumn &copy);
   INLINE ~GeomVertexColumn();
@@ -150,30 +151,6 @@ private:
       return "Packer";
     }
 
-    INLINE float maybe_scale_color_f(unsigned int value);
-    INLINE void maybe_scale_color_f(unsigned int a, unsigned int b);
-    INLINE void maybe_scale_color_f(unsigned int a, unsigned int b,
-                                    unsigned int c);
-    INLINE void maybe_scale_color_f(unsigned int a, unsigned int b,
-                                    unsigned int c, unsigned int d);
-
-    INLINE unsigned int maybe_unscale_color_f(float data);
-    INLINE void maybe_unscale_color_f(const LVecBase2f &data);
-    INLINE void maybe_unscale_color_f(const LVecBase3f &data);
-    INLINE void maybe_unscale_color_f(const LVecBase4f &data);
-
-    INLINE double maybe_scale_color_d(unsigned int value);
-    INLINE void maybe_scale_color_d(unsigned int a, unsigned int b);
-    INLINE void maybe_scale_color_d(unsigned int a, unsigned int b,
-                                    unsigned int c);
-    INLINE void maybe_scale_color_d(unsigned int a, unsigned int b,
-                                    unsigned int c, unsigned int d);
-
-    INLINE unsigned int maybe_unscale_color_d(double data);
-    INLINE void maybe_unscale_color_d(const LVecBase2d &data);
-    INLINE void maybe_unscale_color_d(const LVecBase3d &data);
-    INLINE void maybe_unscale_color_d(const LVecBase4d &data);
-
     const GeomVertexColumn *_column;
     LVecBase2f _v2;
     LVecBase3f _v3;
@@ -191,7 +168,7 @@ private:
   // This is a specialization on the generic Packer that handles
   // points, which are special because the fourth component, if not
   // present in the data, is implicitly 1.0; and if it is present,
-  // than any three-component or smaller return is implicitly divided
+  // then any three-component or smaller return is implicitly divided
   // by the fourth component.
   class Packer_point : public Packer {
   public:
@@ -199,14 +176,17 @@ private:
     virtual const LVecBase2f &get_data2f(const unsigned char *pointer);
     virtual const LVecBase3f &get_data3f(const unsigned char *pointer);
     virtual const LVecBase4f &get_data4f(const unsigned char *pointer);
+
     virtual double get_data1d(const unsigned char *pointer);
     virtual const LVecBase2d &get_data2d(const unsigned char *pointer);
     virtual const LVecBase3d &get_data3d(const unsigned char *pointer);
     virtual const LVecBase4d &get_data4d(const unsigned char *pointer);
+
     virtual void set_data1f(unsigned char *pointer, float data);
     virtual void set_data2f(unsigned char *pointer, const LVecBase2f &data);
     virtual void set_data3f(unsigned char *pointer, const LVecBase3f &data);
     virtual void set_data4f(unsigned char *pointer, const LVecBase4f &data);
+
     virtual void set_data1d(unsigned char *pointer, double data);
     virtual void set_data2d(unsigned char *pointer, const LVecBase2d &data);
     virtual void set_data3d(unsigned char *pointer, const LVecBase3d &data);
@@ -219,17 +199,28 @@ private:
 
   // This is similar to Packer_point, in that the fourth component is
   // implicitly 1.0 if it is not present in the data, but we never
-  // divide by alpha.
+  // divide by alpha.  It also transforms integer colors to the 0-1 range.
   class Packer_color : public Packer {
   public:
+    virtual float get_data1f(const unsigned char *pointer);
+    virtual const LVecBase2f &get_data2f(const unsigned char *pointer);
+    virtual const LVecBase3f &get_data3f(const unsigned char *pointer);
     virtual const LVecBase4f &get_data4f(const unsigned char *pointer);
+
+    virtual double get_data1d(const unsigned char *pointer);
+    virtual const LVecBase2d &get_data2d(const unsigned char *pointer);
+    virtual const LVecBase3d &get_data3d(const unsigned char *pointer);
     virtual const LVecBase4d &get_data4d(const unsigned char *pointer);
+
     virtual void set_data1f(unsigned char *pointer, float data);
     virtual void set_data2f(unsigned char *pointer, const LVecBase2f &data);
     virtual void set_data3f(unsigned char *pointer, const LVecBase3f &data);
+    virtual void set_data4f(unsigned char *pointer, const LVecBase4f &data);
+
     virtual void set_data1d(unsigned char *pointer, double data);
     virtual void set_data2d(unsigned char *pointer, const LVecBase2d &data);
     virtual void set_data3d(unsigned char *pointer, const LVecBase3d &data);
+    virtual void set_data4d(unsigned char *pointer, const LVecBase4d &data);
 
     virtual const char *get_name() const {
       return "Packer_color";
@@ -356,7 +347,7 @@ private:
     }
   };
 
-  class Packer_nativedouble_3 : public Packer_float64_3 {
+  class Packer_nativedouble_3 FINAL : public Packer_float64_3 {
   public:
     virtual const LVecBase3d &get_data3d(const unsigned char *pointer);
 
@@ -365,7 +356,7 @@ private:
     }
   };
 
-  class Packer_point_nativedouble_2 : public Packer_point_float64_2 {
+  class Packer_point_nativedouble_2 FINAL : public Packer_point_float64_2 {
   public:
     virtual const LVecBase2d &get_data2d(const unsigned char *pointer);
 
@@ -374,7 +365,7 @@ private:
     }
   };
 
-  class Packer_point_nativedouble_3 : public Packer_point_float64_3 {
+  class Packer_point_nativedouble_3 FINAL : public Packer_point_float64_3 {
   public:
     virtual const LVecBase3d &get_data3d(const unsigned char *pointer);
 
@@ -392,7 +383,7 @@ private:
     }
   };
 
-  class Packer_argb_packed : public Packer_color {
+  class Packer_argb_packed FINAL : public Packer_color {
   public:
     virtual const LVecBase4f &get_data4f(const unsigned char *pointer);
     virtual void set_data4f(unsigned char *pointer, const LVecBase4f &value);
@@ -402,7 +393,7 @@ private:
     }
   };
 
-  class Packer_rgba_uint8_4 : public Packer_color {
+  class Packer_rgba_uint8_4 FINAL : public Packer_color {
   public:
     virtual const LVecBase4f &get_data4f(const unsigned char *pointer);
     virtual void set_data4f(unsigned char *pointer, const LVecBase4f &value);
@@ -422,7 +413,7 @@ private:
     }
   };
 
-  class Packer_rgba_nativefloat_4 : public Packer_rgba_float32_4 {
+  class Packer_rgba_nativefloat_4 FINAL : public Packer_rgba_float32_4 {
   public:
     virtual const LVecBase4f &get_data4f(const unsigned char *pointer);
 
@@ -431,7 +422,7 @@ private:
     }
   };
 
-  class Packer_uint16_1 : public Packer {
+  class Packer_uint16_1 FINAL : public Packer {
   public:
     virtual int get_data1i(const unsigned char *pointer);
     virtual void set_data1i(unsigned char *pointer, int value);

+ 144 - 0
panda/src/gobj/geomVertexData.I

@@ -403,6 +403,150 @@ unpack_abcd_d(PN_uint32 data) {
   return data & 0xff;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexData::pack_ufloat
+//       Access: Public, Static
+//  Description: Packs three float values in an unsigned 32-bit int.
+////////////////////////////////////////////////////////////////////
+INLINE PN_uint32 GeomVertexData::
+pack_ufloat(float a, float b, float c) {
+  // Since we have to clamp both low exponents and negative numbers to 0,
+  // it's easier to see a float as having a 9-bit signed exponent.
+  union {
+    PN_int32 _packed;
+    float _float;
+  } f0, f1, f2;
+
+  f0._float = a;
+  f1._float = b;
+  f2._float = c;
+
+  // There are several cases here:
+  // 1. exponent 0xff: NaN or infinity (negative infinity excluded)
+  // 2. exponent too large: clamped to maximum value
+  // 3. normalized float
+  // 4. exponent 0: denormal float
+  // 5. zero or anything negative, clamped to 0
+
+  PN_uint32 packed = 0;
+
+  if ((f0._packed & 0x7f800000) == 0x7f800000 && (unsigned)f0._packed != 0xff800000u) {
+    packed |= (f0._packed >> 17) & 0x7ffu;
+  } else if (f0._packed >= 0x47800000) {
+    packed |= 0x7bf;
+  } else if (f0._packed >= 0x38800000) {
+    packed |= (f0._packed >> 17) - 0x1c00;
+  } else if (f0._packed >= 0x35000000) {
+    packed |= ((f0._packed & 0x7c0000u) | 0x800000u) >> (130 - (f0._packed >> 23));
+  }
+
+  if ((f1._packed & 0x7f800000) == 0x7f800000 && (unsigned)f1._packed != 0xff800000u) {
+    packed |= (f1._packed >> 6) & 0x3ff800u;
+  } else if (f1._packed >= 0x47800000) {
+    packed |= 0x3df800;
+  } else if (f1._packed >= 0x38800000) {
+    packed |= ((f1._packed >> 6) - 0xe00000) & 0x3ff800;
+  } else if (f1._packed >= 0x35000000) {
+    packed |= (((f1._packed & 0x7c0000u) | 0x800000u) >> (119 - (f1._packed >> 23))) & 0x1f800u;
+  }
+
+  if ((f2._packed & 0x7f800000) == 0x7f800000 && (unsigned)f2._packed != 0xff800000u) {
+    packed |= (f2._packed & 0x0ffe0000u) << 4;
+  } else if (f2._packed >= 0x47800000) {
+    packed |= 0xf7c00000;
+  } else if (f2._packed >= 0x38800000) {
+    packed |= ((f2._packed - 0x38000000) << 4) & 0xffc00000;
+  } else if (f2._packed >= 0x35000000) {
+    packed |= ((((f2._packed << 3) & 0x03c00000u) | 0x04000000u) >> (112 - (f2._packed >> 23))) & 0x07c00000u;
+  }
+
+  return packed;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexData::unpack_ufloat_a
+//       Access: Public, Static
+//  Description: Unpacks an unsigned float11 value from an uint32.
+////////////////////////////////////////////////////////////////////
+INLINE float GeomVertexData::
+unpack_ufloat_a(PN_uint32 data) {
+  if ((data & 0x7c0) == 0) {
+    // Denormal float (includes zero).
+    return ldexpf((data & 63) / 64.0f, -14);
+  }
+
+  union {
+    PN_uint32 _packed;
+    float _float;
+  } value;
+  value._packed = ((data & 0x7ff) << 17);
+
+  if ((data & 0x7c0) == 0x7c0) {
+    // Infinity / NaN
+    value._packed |= 0x7f800000;
+  } else {
+    value._packed += 0x38000000;
+  }
+
+  return value._float;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexData::unpack_ufloat_b
+//       Access: Public, Static
+//  Description: Unpacks an unsigned float11 value from an uint32.
+////////////////////////////////////////////////////////////////////
+INLINE float GeomVertexData::
+unpack_ufloat_b(PN_uint32 data) {
+  if ((data & 0x3e0000) == 0) {
+    // Denormal float (includes zero).
+    return ldexpf(((data >> 11) & 63) / 64.0f, -14);
+  }
+
+  union {
+    PN_uint32 _packed;
+    float _float;
+  } value;
+  value._packed = ((data & 0x3ff800) << 6);
+
+  if ((data & 0x3e0000) == 0x3e0000) {
+    // Infinity / NaN
+    value._packed |= 0x7f800000;
+  } else {
+    value._packed += 0x38000000;
+  }
+
+  return value._float;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexData::unpack_ufloat_c
+//       Access: Public, Static
+//  Description: Unpacks an unsigned float10 value from an uint32.
+////////////////////////////////////////////////////////////////////
+INLINE float GeomVertexData::
+unpack_ufloat_c(PN_uint32 data) {
+  if ((data & 0xf8000000u) == 0) {
+    // Denormal float (includes zero).
+    return ldexpf(((data >> 22) & 31) / 32.0f, -14);
+  }
+
+  union {
+    PN_uint32 _packed;
+    float _float;
+  } value;
+  value._packed = ((data & 0xffc00000u) >> 4);
+
+  if ((data & 0xf8000000u) == 0xf8000000u) {
+    // Infinity / NaN
+    value._packed |= 0x7f800000;
+  } else {
+    value._packed += 0x38000000;
+  }
+
+  return value._float;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexData::add_transform
 //       Access: Private, Static

+ 16 - 4
panda/src/gobj/geomVertexData.cxx

@@ -2368,7 +2368,7 @@ get_array_info(const InternalName *name,
                const GeomVertexArrayDataHandle *&array_reader,
                int &num_values,
                GeomVertexDataPipelineReader::NumericType &numeric_type,
-               int &start, int &stride, int &divisor,
+               bool &normalized, int &start, int &stride, int &divisor,
                int &num_elements, int &element_stride) const {
   nassertr(_got_array_readers, false);
   int array_index;
@@ -2377,6 +2377,7 @@ get_array_info(const InternalName *name,
     array_reader = _array_readers[array_index];
     num_values = column->get_num_values();
     numeric_type = column->get_numeric_type();
+    normalized = (column->get_contents() == GeomEnums::C_color);
     start = column->get_start();
     stride = _cdata->_format->get_array(array_index)->get_stride();
     divisor = _cdata->_format->get_array(array_index)->get_divisor();
@@ -2553,11 +2554,11 @@ set_num_rows(int n) {
     int num_values = column->get_num_values();
 
     switch (column->get_numeric_type()) {
-    case NT_packed_dcba:
-    case NT_packed_dabc:
     case NT_uint8:
     case NT_uint16:
     case NT_uint32:
+    case NT_packed_dcba:
+    case NT_packed_dabc:
       while (pointer < stop) {
         memset(pointer, 0xff, column->get_total_bytes());
         pointer += stride;
@@ -2578,15 +2579,26 @@ set_num_rows(int n) {
       while (pointer < stop) {
         PN_float64 *pi = (PN_float64 *)pointer;
         for (int i = 0; i < num_values; i++) {
-          pi[i] = 1.0f;
+          pi[i] = 1.0;
         }
         pointer += stride;
       }
       break;
 
     case NT_stdfloat:
+    case NT_int8:
+    case NT_int16:
+    case NT_int32:
       // Shouldn't have this type in the format.
       nassertr(false, false);
+      break;
+
+    case NT_packed_ufloat:
+      while (pointer < stop) {
+        *(PN_int32 *)pointer = 0x781e03c0;
+        pointer += stride;
+      }
+      break;
     }
   }
 

+ 6 - 1
panda/src/gobj/geomVertexData.h

@@ -176,6 +176,11 @@ public:
   static INLINE unsigned int unpack_abcd_c(PN_uint32 data);
   static INLINE unsigned int unpack_abcd_d(PN_uint32 data);
 
+  static INLINE PN_uint32 pack_ufloat(float a, float b, float c);
+  static INLINE float unpack_ufloat_a(PN_uint32 data);
+  static INLINE float unpack_ufloat_b(PN_uint32 data);
+  static INLINE float unpack_ufloat_c(PN_uint32 data);
+
 private:
   static void bytewise_copy(unsigned char *to, int to_stride,
                             const unsigned char *from, int from_stride,
@@ -453,7 +458,7 @@ public:
   bool get_array_info(const InternalName *name,
                       const GeomVertexArrayDataHandle *&array_reader,
                       int &num_values, NumericType &numeric_type,
-                      int &start, int &stride, int &divisor,
+                      bool &normalized, int &start, int &stride, int &divisor,
                       int &num_elements, int &element_stride) const;
 
   INLINE bool has_vertex() const;

+ 0 - 84
panda/src/gobj/geomVertexWriter.I

@@ -906,20 +906,6 @@ set_data2i(int a, int b) {
   set_data2i(LVecBase2i(a, b));
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexWriter::set_data2i
-//       Access: Published
-//  Description: Sets the write row to a particular 2-component
-//               value, and advances the write row.
-//
-//               It is an error for the write row to advance past
-//               the end of data.
-////////////////////////////////////////////////////////////////////
-INLINE void GeomVertexWriter::
-set_data2i(const int data[2]) {
-  set_data2i(LVecBase2i(data[0], data[1]));
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexWriter::set_data2i
 //       Access: Published
@@ -949,20 +935,6 @@ set_data3i(int a, int b, int c) {
   set_data3i(LVecBase3i(a, b, c));
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexWriter::set_data3i
-//       Access: Published
-//  Description: Sets the write row to a particular 3-component
-//               value, and advances the write row.
-//
-//               It is an error for the write row to advance past
-//               the end of data.
-////////////////////////////////////////////////////////////////////
-INLINE void GeomVertexWriter::
-set_data3i(const int data[3]) {
-  set_data3i(LVecBase3i(data[0], data[1], data[2]));
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexWriter::set_data3i
 //       Access: Published
@@ -992,20 +964,6 @@ set_data4i(int a, int b, int c, int d) {
   set_data4i(LVecBase4i(a, b, c, d));
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexWriter::set_data4i
-//       Access: Published
-//  Description: Sets the write row to a particular 4-component
-//               value, and advances the write row.
-//
-//               It is an error for the write row to advance past
-//               the end of data.
-////////////////////////////////////////////////////////////////////
-INLINE void GeomVertexWriter::
-set_data4i(const int data[4]) {
-  set_data4i(LVecBase4i(data[0], data[1], data[2], data[3]));
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexWriter::set_data4i
 //       Access: Published
@@ -1526,20 +1484,6 @@ add_data2i(int a, int b) {
   add_data2i(LVecBase2i(a, b));
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexWriter::add_data2i
-//       Access: Published
-//  Description: Sets the write row to a particular 2-component
-//               value, and advances the write row.
-//
-//               If the write row advances past the end of data,
-//               implicitly adds a new row to the data.
-////////////////////////////////////////////////////////////////////
-INLINE void GeomVertexWriter::
-add_data2i(const int data[2]) {
-  add_data2i(LVecBase2i(data[0], data[1]));
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexWriter::add_data2i
 //       Access: Published
@@ -1569,20 +1513,6 @@ add_data3i(int a, int b, int c) {
   add_data3i(LVecBase3i(a, b, c));
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexWriter::add_data3i
-//       Access: Published
-//  Description: Sets the write row to a particular 3-component
-//               value, and advances the write row.
-//
-//               If the write row advances past the end of data,
-//               implicitly adds a new row to the data.
-////////////////////////////////////////////////////////////////////
-INLINE void GeomVertexWriter::
-add_data3i(const int data[3]) {
-  add_data3i(LVecBase3i(data[0], data[1], data[2]));
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexWriter::add_data3i
 //       Access: Published
@@ -1612,20 +1542,6 @@ add_data4i(int a, int b, int c, int d) {
   add_data4i(LVecBase4i(a, b, c, d));
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexWriter::add_data4i
-//       Access: Published
-//  Description: Sets the write row to a particular 4-component
-//               value, and advances the write row.
-//
-//               If the write row advances past the end of data,
-//               implicitly adds a new row to the data.
-////////////////////////////////////////////////////////////////////
-INLINE void GeomVertexWriter::
-add_data4i(const int data[4]) {
-  add_data4i(LVecBase4i(data[0], data[1], data[2], data[3]));
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexWriter::add_data4i
 //       Access: Published

+ 0 - 6
panda/src/gobj/geomVertexWriter.h

@@ -144,13 +144,10 @@ PUBLISHED:
 
   INLINE void set_data1i(int data);
   INLINE void set_data2i(int a, int b);
-  INLINE void set_data2i(const int data[2]);
   INLINE void set_data2i(const LVecBase2i &data);
   INLINE void set_data3i(int a, int b, int c);
-  INLINE void set_data3i(const int data[3]);
   INLINE void set_data3i(const LVecBase3i &data);
   INLINE void set_data4i(int a, int b, int c, int d);
-  INLINE void set_data4i(const int data[4]);
   INLINE void set_data4i(const LVecBase4i &data);
 
   INLINE void add_data1f(float data);
@@ -185,13 +182,10 @@ PUBLISHED:
 
   INLINE void add_data1i(int data);
   INLINE void add_data2i(int a, int b);
-  INLINE void add_data2i(const int data[2]);
   INLINE void add_data2i(const LVecBase2i &data);
   INLINE void add_data3i(int a, int b, int c);
-  INLINE void add_data3i(const int data[3]);
   INLINE void add_data3i(const LVecBase3i &data);
   INLINE void add_data4i(int a, int b, int c, int d);
-  INLINE void add_data4i(const int data[4]);
   INLINE void add_data4i(const LVecBase4i &data);
 
   void output(ostream &out) const;

+ 1 - 1
panda/src/gobj/shader.I

@@ -865,7 +865,7 @@ get_filename_from_index(int index, ShaderType type) const {
     if (!fn.empty()) {
       return fn;
     }
-  } else if (glsl_preprocess && index > 2048 &&
+  } else if (glsl_preprocess && index >= 2048 &&
              (index - 2048) < (int)_included_files.size()) {
     return _included_files[index - 2048];
   }

+ 69 - 14
panda/src/gobj/shader.cxx

@@ -413,8 +413,10 @@ cp_dependency(ShaderMatInput inp) {
   if (inp == SMO_attr_fog || inp == SMO_attr_fogcolor) {
     dep |= SSD_fog;
   }
-  if ((inp == SMO_model_to_view)||
-      (inp == SMO_view_to_model)) {
+  if ((inp == SMO_model_to_view) ||
+      (inp == SMO_view_to_model) ||
+      (inp == SMO_model_to_apiview) ||
+      (inp == SMO_apiview_to_model)) {
     dep |= SSD_transform;
   }
   if ((inp == SMO_texpad_x) ||
@@ -483,6 +485,43 @@ cp_optimize_mat_spec(ShaderMatSpec &spec) {
       spec._part[0] = spec._part[1];
       spec._arg[0] = spec._arg[1];
     }
+
+    // More optimal combinations for common matrices.
+
+    if (spec._part[0] == SMO_model_to_view &&
+        spec._part[1] == SMO_view_to_apiclip) {
+      spec._part[0] = SMO_model_to_apiview;
+      spec._part[1] = SMO_apiview_to_apiclip;
+
+    } else if (spec._part[0] == SMO_apiclip_to_view &&
+               spec._part[1] == SMO_view_to_model) {
+      spec._part[0] = SMO_apiclip_to_apiview;
+      spec._part[1] = SMO_apiview_to_model;
+
+    } else if (spec._part[0] == SMO_apiview_to_view &&
+               spec._part[1] == SMO_view_to_apiclip) {
+      spec._func = SMF_first;
+      spec._part[0] = SMO_apiview_to_apiclip;
+      spec._part[1] = SMO_identity;
+
+    } else if (spec._part[0] == SMO_apiclip_to_view &&
+               spec._part[1] == SMO_view_to_apiview) {
+      spec._func = SMF_first;
+      spec._part[0] = SMO_apiclip_to_apiview;
+      spec._part[1] = SMO_identity;
+
+    } else if (spec._part[0] == SMO_apiview_to_view &&
+               spec._part[1] == SMO_view_to_model) {
+      spec._func = SMF_first;
+      spec._part[0] = SMO_apiview_to_model;
+      spec._part[1] = SMO_identity;
+
+    } else if (spec._part[0] == SMO_model_to_view &&
+               spec._part[1] == SMO_view_to_apiview) {
+      spec._func = SMF_first;
+      spec._part[0] = SMO_model_to_apiview;
+      spec._part[1] = SMO_identity;
+    }
   }
 
   // Calculate state and transform dependencies.
@@ -1790,6 +1829,7 @@ cg_analyze_shader(const ShaderCaps &caps) {
   //    }
   //  }
 
+  cg_release_resources();
   return true;
 }
 
@@ -2618,9 +2658,12 @@ make(const string &body, ShaderLanguage lang) {
 #endif
 
   ShaderFile sbody(body);
-  ShaderTable::const_iterator i = _make_table.find(sbody);
-  if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
-    return i->second;
+
+  if (cache_generated_shaders) {
+    ShaderTable::const_iterator i = _make_table.find(sbody);
+    if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
+      return i->second;
+    }
   }
 
   PT(Shader) shader = new Shader(lang);
@@ -2639,7 +2682,9 @@ make(const string &body, ShaderLanguage lang) {
   }
 #endif
 
-  _make_table[sbody] = shader;
+  if (cache_generated_shaders) {
+    _make_table[sbody] = shader;
+  }
 
   if (dump_generated_shaders) {
     ostringstream fns;
@@ -2679,9 +2724,11 @@ make(ShaderLanguage lang, const string &vertex, const string &fragment,
 
   ShaderFile sbody(vertex, fragment, geometry, tess_control, tess_evaluation);
 
-  ShaderTable::const_iterator i = _make_table.find(sbody);
-  if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
-    return i->second;
+  if (cache_generated_shaders) {
+    ShaderTable::const_iterator i = _make_table.find(sbody);
+    if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
+      return i->second;
+    }
   }
 
   PT(Shader) shader = new Shader(lang);
@@ -2698,8 +2745,10 @@ make(ShaderLanguage lang, const string &vertex, const string &fragment,
   }
 #endif
 
+  if (cache_generated_shaders) {
+    _make_table[sbody] = shader;
+  }
 
-  _make_table[sbody] = shader;
   return shader;
 }
 
@@ -2720,16 +2769,22 @@ make_compute(ShaderLanguage lang, const string &body) {
   sbody._separate = true;
   sbody._compute = body;
 
-  ShaderTable::const_iterator i = _make_table.find(sbody);
-  if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
-    return i->second;
+
+  if (cache_generated_shaders) {
+    ShaderTable::const_iterator i = _make_table.find(sbody);
+    if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
+      return i->second;
+    }
   }
 
   PT(Shader) shader = new Shader(lang);
   shader->_filename = ShaderFile("created-shader");
   shader->_text = sbody;
 
-  _make_table[sbody] = shader;
+  if (cache_generated_shaders) {
+    _make_table[sbody] = shader;
+  }
+
   return shader;
 }
 

+ 5 - 0
panda/src/gobj/shader.h

@@ -186,6 +186,11 @@ public:
     // SMO_clipplane_x is world coords, GLSL needs eye coords
     SMO_apiview_clipplane_i,
 
+    SMO_model_to_apiview,
+    SMO_apiview_to_model,
+    SMO_apiview_to_apiclip,
+    SMO_apiclip_to_apiview,
+
     SMO_INVALID
   };
 

+ 54 - 0
panda/src/gobj/texture.I

@@ -215,6 +215,26 @@ setup_cube_map(int size, ComponentType component_type, Format format) {
   setup_texture(TT_cube_map, size, size, 6, component_type, format);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::setup_buffer_texture
+//       Access: Published
+//  Description: Sets the texture as an empty buffer texture with
+//               the specified size and properties.  Follow up
+//               with set_ram_image() or modify_ram_image() to fill
+//               the image data, or use set_clear_color to let the
+//               texture be cleared to a solid color.
+//
+//               Note that a buffer texture's format needs to match
+//               the component type.
+////////////////////////////////////////////////////////////////////
+INLINE void Texture::
+setup_buffer_texture(int size, ComponentType component_type, Format format,
+                     GeomEnums::UsageHint usage) {
+  setup_texture(TT_buffer_texture, size, 1, 1, component_type, format);
+  CDWriter cdata(_cycler);
+  cdata->_usage_hint = usage;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::clear_image
 //       Access: Published
@@ -886,6 +906,18 @@ get_component_type() const {
   return cdata->_component_type;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::get_usage_hint
+//       Access: Published
+//  Description: Returns the usage hint specified for buffer textures,
+//               or UH_unspecified for all other texture types.
+////////////////////////////////////////////////////////////////////
+INLINE GeomEnums::UsageHint Texture::
+get_usage_hint() const {
+  CDReader cdata(_cycler);
+  return cdata->_usage_hint;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::set_wrap_u
 //       Access: Published
@@ -1073,6 +1105,28 @@ get_default_sampler() const {
   return cdata->_default_sampler;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::set_default_sampler
+//       Access: Published
+//  Description: This sets the default sampler state for this
+//               texture, containing the wrap and filter properties
+//               specified on the texture level; it may still be
+//               overridden by a sampler state specified at a higher
+//               level.  This encompasses the settings for get_wrap_u,
+//               get_minfilter, get_anisotropic_degree, etc.
+//
+//               This makes a copy of the SamplerState object, so
+//               future modifications of the same SamplerState will
+//               have no effect on this texture unless you call
+//               set_default_sampler again.
+////////////////////////////////////////////////////////////////////
+INLINE void Texture::
+set_default_sampler(const SamplerState &sampler) {
+  CDWriter cdata(_cycler, true);
+  cdata->_default_sampler = sampler;
+  cdata->inc_properties_modified();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::get_wrap_u
 //       Access: Published

+ 39 - 6
panda/src/gobj/texture.cxx

@@ -1524,6 +1524,10 @@ write(ostream &out, int indent_level) const {
   case TT_cube_map:
     out << "cube map, " << cdata->_x_size << " x " << cdata->_y_size;
     break;
+
+  case TT_buffer_texture:
+    out << "buffer, " << cdata->_x_size;
+    break;
   }
 
   if (cdata->_num_views > 1) {
@@ -1924,6 +1928,8 @@ format_texture_type(TextureType tt) {
     return "2d_texture_array";
   case TT_cube_map:
     return "cube_map";
+  case TT_buffer_texture:
+    return "buffer_texture";
   }
   return "**invalid**";
 }
@@ -1946,6 +1952,8 @@ string_texture_type(const string &str) {
     return TT_2d_texture_array;
   } else if (cmp_nocase(str, "cube_map") == 0) {
     return TT_cube_map;
+  } else if (cmp_nocase(str, "buffer_texture") == 0) {
+    return TT_buffer_texture;
   }
 
   gobj_cat->error()
@@ -2673,6 +2681,7 @@ do_read(CData *cdata, const Filename &fullpath, const Filename &alpha_fullpath,
     switch (cdata->_texture_type) {
     case TT_1d_texture:
     case TT_2d_texture:
+    case TT_buffer_texture:
       z_size = 1;
       break;
 
@@ -3071,10 +3080,16 @@ do_read_one(CData *cdata, const Filename &fullpath, const Filename &alpha_fullpa
 
     if (alpha_file_channel == 4 ||
         (alpha_file_channel == 2 && alpha_image.get_num_channels() == 2)) {
-      // Use the alpha channel.
-      for (int x = 0; x < image.get_x_size(); x++) {
-        for (int y = 0; y < image.get_y_size(); y++) {
-          image.set_alpha(x, y, alpha_image.get_alpha(x, y));
+
+      if (!alpha_image.has_alpha()) {
+        gobj_cat.error()
+          << alpha_fullpath.get_basename() << " has no channel " << alpha_file_channel << ".\n";
+      } else {
+        // Use the alpha channel.
+        for (int x = 0; x < image.get_x_size(); x++) {
+          for (int y = 0; y < image.get_y_size(); y++) {
+            image.set_alpha(x, y, alpha_image.get_alpha(x, y));
+          }
         }
       }
       cdata->_alpha_file_channel = alpha_image.get_num_channels();
@@ -4854,7 +4869,8 @@ do_reconsider_image_properties(CData *cdata, int x_size, int y_size, int num_com
     }
 
 #ifndef NDEBUG
-    if (cdata->_texture_type == TT_1d_texture) {
+    if (cdata->_texture_type == TT_1d_texture ||
+        cdata->_texture_type == TT_buffer_texture) {
       nassertr(y_size == 1, false);
     } else if (cdata->_texture_type == TT_cube_map) {
       nassertr(x_size == y_size, false);
@@ -5051,6 +5067,10 @@ do_setup_texture(CData *cdata, Texture::TextureType texture_type,
     cdata->_default_sampler.set_wrap_v(SamplerState::WM_clamp);
     cdata->_default_sampler.set_wrap_w(SamplerState::WM_clamp);
     break;
+
+  case TT_buffer_texture:
+    nassertv(y_size == 1 && z_size == 1);
+    break;
   }
 
   if (texture_type != TT_2d_texture) {
@@ -5199,7 +5219,8 @@ do_set_x_size(CData *cdata, int x_size) {
 void Texture::
 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);
+    nassertv((cdata->_texture_type != Texture::TT_buffer_texture &&
+              cdata->_texture_type != Texture::TT_1d_texture) || y_size == 1);
     cdata->_y_size = y_size;
     cdata->inc_image_modified();
     do_clear_ram_image(cdata);
@@ -7897,6 +7918,10 @@ do_write_datagram_body(CData *cdata, BamWriter *manager, Datagram &me) {
   me.add_uint8(cdata->_format);
   me.add_uint8(cdata->_num_components);
 
+  if (cdata->_texture_type == TT_buffer_texture) {
+    me.add_uint8(cdata->_usage_hint);
+  }
+
   me.add_uint8(cdata->_auto_texture_scale);
   me.add_uint32(cdata->_orig_file_x_size);
   me.add_uint32(cdata->_orig_file_y_size);
@@ -8063,6 +8088,7 @@ make_this_from_bam(const FactoryParams &params) {
       options.set_auto_texture_scale(auto_texture_scale);
 
       switch (texture_type) {
+      case TT_buffer_texture:
       case TT_1d_texture:
       case TT_2d_texture:
         if (alpha_filename.empty()) {
@@ -8124,6 +8150,10 @@ do_fillin_body(CData *cdata, DatagramIterator &scan, BamReader *manager) {
   cdata->_format = (Format)scan.get_uint8();
   cdata->_num_components = scan.get_uint8();
 
+  if (cdata->_texture_type == TT_buffer_texture) {
+    cdata->_usage_hint = (GeomEnums::UsageHint)scan.get_uint8();
+  }
+
   cdata->inc_properties_modified();
 
   cdata->_auto_texture_scale = ATS_unspecified;
@@ -8304,6 +8334,9 @@ CData() {
   // check in do_set_format depending on an uninitialized value.
   _format = F_rgba;
 
+  // Only used for buffer textures.
+  _usage_hint = GeomEnums::UH_unspecified;
+
   _pad_x_size = 0;
   _pad_y_size = 0;
   _pad_z_size = 0;

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

@@ -42,6 +42,7 @@
 #include "samplerState.h"
 #include "pnmImage.h"
 #include "colorSpace.h"
+#include "geomEnums.h"
 
 class PNMImage;
 class PfmFile;
@@ -82,6 +83,7 @@ PUBLISHED:
     TT_3d_texture,
     TT_2d_texture_array,
     TT_cube_map,
+    TT_buffer_texture,
   };
 
   enum ComponentType {
@@ -240,6 +242,8 @@ PUBLISHED:
   INLINE void setup_2d_texture_array(int z_size = 1);
   INLINE void setup_2d_texture_array(int x_size, int y_size, int z_size,
                                      ComponentType component_type, Format format);
+  INLINE void setup_buffer_texture(int size, ComponentType component_type,
+                                   Format format, GeomEnums::UsageHint usage);
   void generate_normalization_cube_map(int size);
   void generate_alpha_scale_map();
 
@@ -304,6 +308,7 @@ PUBLISHED:
   INLINE TextureType get_texture_type() const;
   INLINE Format get_format() const;
   INLINE ComponentType get_component_type() const;
+  INLINE GeomEnums::UsageHint get_usage_hint() const;
 
   INLINE void set_wrap_u(WrapMode wrap);
   INLINE void set_wrap_v(WrapMode wrap);
@@ -316,6 +321,7 @@ PUBLISHED:
   INLINE void set_render_to_texture(bool render_to_texture);
 
   INLINE const SamplerState &get_default_sampler() const;
+  INLINE void set_default_sampler(const SamplerState &sampler);
   INLINE SamplerState::WrapMode get_wrap_u() const;
   INLINE SamplerState::WrapMode get_wrap_v() const;
   INLINE SamplerState::WrapMode get_wrap_w() const;
@@ -829,6 +835,7 @@ protected:
     TextureType _texture_type;
     Format _format;
     ComponentType _component_type;
+    GeomEnums::UsageHint _usage_hint;
 
     bool _loaded_from_image;
     bool _loaded_from_txo;

+ 4 - 0
panda/src/grutil/frameRateMeter.cxx

@@ -180,6 +180,10 @@ clear_window() {
 ////////////////////////////////////////////////////////////////////
 bool FrameRateMeter::
 cull_callback(CullTraverser *trav, CullTraverserData &data) {
+  // This triggers when you try to parent a frame rate meter into
+  // the scene graph yourself.  Instead, use setup_window().
+  nassertr(_display_region != NULL, false);
+
   Thread *current_thread = trav->get_current_thread();
 
   // Statistics

+ 45 - 0
panda/src/linmath/lcast_to_src.I

@@ -138,3 +138,48 @@ lcast_to(FLOATTYPE2 *, const FLOATNAME(LMatrix4) &source) {
      source(2, 0), source(2, 1), source(2, 2), source(2, 3),
      source(3, 0), source(3, 1), source(3, 2), source(3, 3));
 }
+
+INLINE_LINMATH FLOATNAME2(LVecBase2)
+lcast_to(FLOATTYPE2 *, const LVecBase2i &source) {
+  return FLOATNAME2(LVecBase2)(source[0], source[1]);
+}
+
+INLINE_LINMATH FLOATNAME2(LVecBase3)
+lcast_to(FLOATTYPE2 *, const LVecBase3i &source) {
+  return FLOATNAME2(LVecBase3)(source[0], source[1], source[2]);
+}
+
+INLINE_LINMATH FLOATNAME2(LVecBase4)
+lcast_to(FLOATTYPE2 *, const LVecBase4i &source) {
+  return FLOATNAME2(LVecBase4)(source[0], source[1], source[2], source[3]);
+}
+
+INLINE_LINMATH FLOATNAME2(LVector2)
+lcast_to(FLOATTYPE2 *, const LVector2i &source) {
+  return FLOATNAME2(LVector2)(source[0], source[1]);
+}
+
+INLINE_LINMATH FLOATNAME2(LVector3)
+lcast_to(FLOATTYPE2 *, const LVector3i &source) {
+  return FLOATNAME2(LVector3)(source[0], source[1], source[2]);
+}
+
+INLINE_LINMATH FLOATNAME2(LVector4)
+lcast_to(FLOATTYPE2 *, const LVector4i &source) {
+  return FLOATNAME2(LVector4)(source[0], source[1], source[2], source[3]);
+}
+
+INLINE_LINMATH FLOATNAME2(LPoint2)
+lcast_to(FLOATTYPE2 *, const LPoint2i &source) {
+  return FLOATNAME2(LPoint2)(source[0], source[1]);
+}
+
+INLINE_LINMATH FLOATNAME2(LPoint3)
+lcast_to(FLOATTYPE2 *, const LPoint3i &source) {
+  return FLOATNAME2(LPoint3)(source[0], source[1], source[2]);
+}
+
+INLINE_LINMATH FLOATNAME2(LPoint4)
+lcast_to(FLOATTYPE2 *, const LPoint4i &source) {
+  return FLOATNAME2(LPoint4)(source[0], source[1], source[2], source[3]);
+}

+ 27 - 0
panda/src/linmath/lcast_to_src.h

@@ -86,6 +86,33 @@ lcast_to(FLOATTYPE2 *, const FLOATNAME(LMatrix3) &source);
 INLINE_LINMATH FLOATNAME2(LMatrix4)
 lcast_to(FLOATTYPE2 *, const FLOATNAME(LMatrix4) &source);
 
+INLINE_LINMATH FLOATNAME2(LVecBase2)
+lcast_to(FLOATTYPE2 *, const LVecBase2i &source);
+
+INLINE_LINMATH FLOATNAME2(LVecBase3)
+lcast_to(FLOATTYPE2 *, const LVecBase3i &source);
+
+INLINE_LINMATH FLOATNAME2(LVecBase4)
+lcast_to(FLOATTYPE2 *, const LVecBase4i &source);
+
+INLINE_LINMATH FLOATNAME2(LVector2)
+lcast_to(FLOATTYPE2 *, const LVector2i &source);
+
+INLINE_LINMATH FLOATNAME2(LVector3)
+lcast_to(FLOATTYPE2 *, const LVector3i &source);
+
+INLINE_LINMATH FLOATNAME2(LVector4)
+lcast_to(FLOATTYPE2 *, const LVector4i &source);
+
+INLINE_LINMATH FLOATNAME2(LPoint2)
+lcast_to(FLOATTYPE2 *, const LPoint2i &source);
+
+INLINE_LINMATH FLOATNAME2(LPoint3)
+lcast_to(FLOATTYPE2 *, const LPoint3i &source);
+
+INLINE_LINMATH FLOATNAME2(LPoint4)
+lcast_to(FLOATTYPE2 *, const LPoint4i &source);
+
 #include "lcast_to_src.I"
 
 #endif  // CPPPARSER

+ 2 - 0
panda/src/mathutil/boundingVolume.h

@@ -56,12 +56,14 @@ PUBLISHED:
 
   INLINE_MATHUTIL bool extend_by(const BoundingVolume *vol);
 
+public:
   // It might be nice to make these template member functions so we
   // could have true STL-style first/last iterators, but that's
   // impossible for virtual functions.
   bool around(const BoundingVolume **first,
               const BoundingVolume **last);
 
+PUBLISHED:
   // The contains() functions return the union of one or more of these
   // bits.
   enum IntersectionFlags {

+ 2 - 0
panda/src/mathutil/geometricBoundingVolume.h

@@ -36,6 +36,7 @@ PUBLISHED:
   INLINE_MATHUTIL bool extend_by(const GeometricBoundingVolume *vol);
   INLINE_MATHUTIL bool extend_by(const LPoint3 &point);
 
+public:
   // It might be nice to make these template member functions so we
   // could have true STL-style first/last iterators, but that's
   // impossible for virtual functions.
@@ -43,6 +44,7 @@ PUBLISHED:
                               const GeometricBoundingVolume **last);
   INLINE_MATHUTIL bool around(const LPoint3 *first, const LPoint3 *last);
 
+PUBLISHED:
   INLINE_MATHUTIL int contains(const GeometricBoundingVolume *vol) const;
   INLINE_MATHUTIL int contains(const LPoint3 &point) const;
   INLINE_MATHUTIL int contains(const LPoint3 &a, const LPoint3 &b) const;

+ 7 - 28
panda/src/pgraph/shaderAttrib.cxx

@@ -429,9 +429,12 @@ get_shader_input_ptr(const InternalName *id) const {
 //       Access: Published
 //  Description: Returns the ShaderInput as a texture.  Assertion
 //               fails if there is none, or if it is not a texture.
+//
+//               If sampler is not NULL, the sampler state to use
+//               for this texture is assigned to it.
 ////////////////////////////////////////////////////////////////////
 Texture *ShaderAttrib::
-get_shader_input_texture(const InternalName *id) const {
+get_shader_input_texture(const InternalName *id, SamplerState *sampler) const {
   Inputs::const_iterator i = _inputs.find(id);
   if (i == _inputs.end()) {
     ostringstream strm;
@@ -447,34 +450,10 @@ get_shader_input_texture(const InternalName *id) const {
       nassert_raise(strm.str());
       return NULL;
     }
-    return p->get_texture();
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ShaderAttrib::get_shader_input_sampler
-//       Access: Published
-//  Description: Returns the ShaderInput as a sampler.  Assertion
-//               fails if there is none, or if it is not a texture.
-////////////////////////////////////////////////////////////////////
-const SamplerState &ShaderAttrib::
-get_shader_input_sampler(const InternalName *id) const {
-  Inputs::const_iterator i = _inputs.find(id);
-  if (i == _inputs.end()) {
-    ostringstream strm;
-    strm << "Shader input " << id->get_name() << " is not present.\n";
-    nassert_raise(strm.str());
-    return SamplerState::get_default();
-  } else {
-    const ShaderInput *p = (*i).second;
-    if (p->get_value_type() != ShaderInput::M_texture &&
-        p->get_value_type() != ShaderInput::M_texture_sampler) {
-      ostringstream strm;
-      strm <<  "Shader input " << id->get_name() << " is not a texture.\n";
-      nassert_raise(strm.str());
-      return SamplerState::get_default();
+    if (sampler != NULL) {
+      *sampler = p->get_sampler();
     }
-    return p->get_sampler();
+    return p->get_texture();
   }
 }
 

+ 1 - 2
panda/src/pgraph/shaderAttrib.h

@@ -106,8 +106,7 @@ PUBLISHED:
 
   const NodePath &get_shader_input_nodepath(const InternalName *id) const;
   LVecBase4 get_shader_input_vector(InternalName *id) const;
-  Texture *get_shader_input_texture(const InternalName *id) const;
-  const SamplerState &get_shader_input_sampler(const InternalName *id) const;
+  Texture *get_shader_input_texture(const InternalName *id, SamplerState *sampler=NULL) const;
   const Shader::ShaderPtrData *get_shader_input_ptr(const InternalName *id) const;
   const LMatrix4 &get_shader_input_matrix(const InternalName *id, LMatrix4 &matrix) const;
 

+ 32 - 197
panda/src/pgraph/shaderInput.I

@@ -31,10 +31,7 @@ INLINE ShaderInput::
 ShaderInput(CPT_InternalName name, int priority) :
   _name(MOVE(name)),
   _type(M_invalid),
-  _priority(priority),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _priority(priority)
 {
 }
 
@@ -48,58 +45,8 @@ ShaderInput(CPT_InternalName name, Texture *tex, int priority) :
   _name(MOVE(name)),
   _type(M_texture),
   _priority(priority),
-  _value(tex),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read | A_write | A_layered)
-{
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ShaderInput::Constructor
-//       Access: Published
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE ShaderInput::
-ShaderInput(CPT_InternalName name, Texture *tex, const SamplerState &sampler, int priority) :
-  _name(MOVE(name)),
-  _type(M_texture_sampler),
-  _priority(priority),
-  _value(tex),
-  _sampler(sampler),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read | A_layered)
-{
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ShaderInput::Constructor
-//       Access: Published
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE ShaderInput::
-ShaderInput(CPT_InternalName name, Texture *tex, bool read, bool write, int z, int n, int priority) :
-  _name(MOVE(name)),
-  _type(M_texture),
-  _priority(priority),
-  _value(tex),
-  _bind_layer(z),
-  _bind_level(n),
-  _access(0)
+  _value(tex)
 {
-  if (read) {
-    _access |= A_read;
-  }
-  if (write) {
-    _access |= A_write;
-  }
-  if (z >= 0) {
-    _bind_layer = z;
-  } else {
-    _bind_layer = 0;
-    _access |= A_layered;
-  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -112,10 +59,7 @@ ShaderInput(CPT_InternalName name, ParamValueBase *param, int priority) :
   _name(MOVE(name)),
   _type(M_param),
   _priority(priority),
-  _value(param),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _value(param)
 {
 }
 
@@ -129,10 +73,7 @@ ShaderInput(CPT_InternalName name, const PTA_float &ptr, int priority) :
   _name(MOVE(name)),
   _type(M_numeric),
   _priority(priority),
-  _stored_ptr(ptr),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_ptr(ptr)
 {
 }
 
@@ -146,10 +87,7 @@ ShaderInput(CPT_InternalName name, const PTA_LVecBase4f &ptr, int priority) :
   _name(MOVE(name)),
   _type(M_numeric),
   _priority(priority),
-  _stored_ptr(ptr),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_ptr(ptr)
 {
 }
 
@@ -163,10 +101,7 @@ ShaderInput(CPT_InternalName name, const PTA_LVecBase3f &ptr, int priority) :
   _name(MOVE(name)),
   _type(M_numeric),
   _priority(priority),
-  _stored_ptr(ptr),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_ptr(ptr)
 {
 }
 
@@ -180,10 +115,7 @@ ShaderInput(CPT_InternalName name, const PTA_LVecBase2f &ptr, int priority) :
   _name(MOVE(name)),
   _type(M_numeric),
   _priority(priority),
-  _stored_ptr(ptr),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_ptr(ptr)
 {
 }
 
@@ -198,10 +130,7 @@ ShaderInput(CPT_InternalName name, const LVecBase4f &vec, int priority) :
   _type(M_vector),
   _priority(priority),
   _stored_ptr(vec),
-  _stored_vector(LCAST(PN_stdfloat, vec)),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_vector(LCAST(PN_stdfloat, vec))
 {
 }
 
@@ -216,10 +145,7 @@ ShaderInput(CPT_InternalName name, const LVecBase3f &vec, int priority) :
   _type(M_vector),
   _priority(priority),
   _stored_ptr(vec),
-  _stored_vector(vec.get_x(), vec.get_y(), vec.get_z(), 0.0),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_vector(vec.get_x(), vec.get_y(), vec.get_z(), 0.0)
 {
 }
 
@@ -234,10 +160,7 @@ ShaderInput(CPT_InternalName name, const LVecBase2f &vec, int priority) :
   _type(M_vector),
   _priority(priority),
   _stored_ptr(vec),
-  _stored_vector(vec.get_x(), vec.get_y(), 0.0, 0.0),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_vector(vec.get_x(), vec.get_y(), 0.0, 0.0)
 {
 }
 
@@ -251,10 +174,7 @@ ShaderInput(CPT_InternalName name, const PTA_LMatrix4f &ptr, int priority) :
   _name(MOVE(name)),
   _type(M_numeric),
   _priority(priority),
-  _stored_ptr(ptr),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_ptr(ptr)
 {
 }
 
@@ -268,10 +188,7 @@ ShaderInput(CPT_InternalName name, const PTA_LMatrix3f &ptr, int priority) :
   _name(MOVE(name)),
   _type(M_numeric),
   _priority(priority),
-  _stored_ptr(ptr),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_ptr(ptr)
 {
 }
 
@@ -285,10 +202,7 @@ ShaderInput(CPT_InternalName name, const LMatrix4f &mat, int priority) :
   _name(MOVE(name)),
   _type(M_numeric),
   _priority(priority),
-  _stored_ptr(mat),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_ptr(mat)
 {
 }
 
@@ -302,10 +216,7 @@ ShaderInput(CPT_InternalName name, const LMatrix3f &mat, int priority) :
   _name(MOVE(name)),
   _type(M_numeric),
   _priority(priority),
-  _stored_ptr(mat),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_ptr(mat)
 {
 }
 
@@ -319,10 +230,7 @@ ShaderInput(CPT_InternalName name, const PTA_double &ptr, int priority) :
   _name(MOVE(name)),
   _type(M_numeric),
   _priority(priority),
-  _stored_ptr(ptr),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_ptr(ptr)
 {
 }
 
@@ -336,10 +244,7 @@ ShaderInput(CPT_InternalName name, const PTA_LVecBase4d &ptr, int priority) :
   _name(MOVE(name)),
   _type(M_numeric),
   _priority(priority),
-  _stored_ptr(ptr),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_ptr(ptr)
 {
 }
 
@@ -353,10 +258,7 @@ ShaderInput(CPT_InternalName name, const PTA_LVecBase3d &ptr, int priority) :
   _name(MOVE(name)),
   _type(M_numeric),
   _priority(priority),
-  _stored_ptr(ptr),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_ptr(ptr)
 {
 }
 
@@ -370,10 +272,7 @@ ShaderInput(CPT_InternalName name, const PTA_LVecBase2d &ptr, int priority) :
   _name(MOVE(name)),
   _type(M_numeric),
   _priority(priority),
-  _stored_ptr(ptr),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_ptr(ptr)
 {
 }
 
@@ -388,10 +287,7 @@ ShaderInput(CPT_InternalName name, const LVecBase4d &vec, int priority) :
   _type(M_numeric),
   _priority(priority),
   _stored_ptr(vec),
-  _stored_vector(LCAST(PN_stdfloat, vec)),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_vector(LCAST(PN_stdfloat, vec))
 {
 }
 
@@ -406,10 +302,7 @@ ShaderInput(CPT_InternalName name, const LVecBase3d &vec, int priority) :
   _type(M_numeric),
   _priority(priority),
   _stored_ptr(vec),
-  _stored_vector(vec.get_x(), vec.get_y(), vec.get_z(), 0.0),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_vector(vec.get_x(), vec.get_y(), vec.get_z(), 0.0)
 {
 }
 
@@ -424,10 +317,7 @@ ShaderInput(CPT_InternalName name, const LVecBase2d &vec, int priority) :
   _type(M_numeric),
   _priority(priority),
   _stored_ptr(vec),
-  _stored_vector(vec.get_x(), vec.get_y(), 0.0, 0.0),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_vector(vec.get_x(), vec.get_y(), 0.0, 0.0)
 {
 }
 
@@ -441,10 +331,7 @@ ShaderInput(CPT_InternalName name, const PTA_LMatrix4d &ptr, int priority) :
   _name(MOVE(name)),
   _type(M_numeric),
   _priority(priority),
-  _stored_ptr(ptr),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_ptr(ptr)
 {
 }
 
@@ -458,10 +345,7 @@ ShaderInput(CPT_InternalName name, const PTA_LMatrix3d &ptr, int priority) :
   _name(MOVE(name)),
   _type(M_numeric),
   _priority(priority),
-  _stored_ptr(ptr),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_ptr(ptr)
 {
 }
 
@@ -475,10 +359,7 @@ ShaderInput(CPT_InternalName name, const LMatrix4d &mat, int priority) :
   _name(MOVE(name)),
   _type(M_numeric),
   _priority(priority),
-  _stored_ptr(mat),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_ptr(mat)
 {
 }
 
@@ -492,10 +373,7 @@ ShaderInput(CPT_InternalName name, const LMatrix3d &mat, int priority) :
   _name(MOVE(name)),
   _type(M_numeric),
   _priority(priority),
-  _stored_ptr(mat),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_ptr(mat)
 {
 }
 
@@ -509,10 +387,7 @@ ShaderInput(CPT_InternalName name, const PTA_int &ptr, int priority) :
   _name(MOVE(name)),
   _type(M_numeric),
   _priority(priority),
-  _stored_ptr(ptr),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_ptr(ptr)
 {
 }
 
@@ -526,10 +401,7 @@ ShaderInput(CPT_InternalName name, const PTA_LVecBase4i &ptr, int priority) :
   _name(MOVE(name)),
   _type(M_numeric),
   _priority(priority),
-  _stored_ptr(ptr),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_ptr(ptr)
 {
 }
 
@@ -543,10 +415,7 @@ ShaderInput(CPT_InternalName name, const PTA_LVecBase3i &ptr, int priority) :
   _name(MOVE(name)),
   _type(M_numeric),
   _priority(priority),
-  _stored_ptr(ptr),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_ptr(ptr)
 {
 }
 
@@ -560,10 +429,7 @@ ShaderInput(CPT_InternalName name, const PTA_LVecBase2i &ptr, int priority) :
   _name(MOVE(name)),
   _type(M_numeric),
   _priority(priority),
-  _stored_ptr(ptr),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_ptr(ptr)
 {
 }
 
@@ -578,10 +444,7 @@ ShaderInput(CPT_InternalName name, const LVecBase4i &vec, int priority) :
   _type(M_numeric),
   _priority(priority),
   _stored_ptr(vec),
-  _stored_vector((int)vec.get_x(), (int)vec.get_y(), (int)vec.get_z(), (int)vec.get_w()),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_vector((int)vec.get_x(), (int)vec.get_y(), (int)vec.get_z(), (int)vec.get_w())
 {
 }
 
@@ -596,10 +459,7 @@ ShaderInput(CPT_InternalName name, const LVecBase3i &vec, int priority) :
   _type(M_numeric),
   _priority(priority),
   _stored_ptr(vec),
-  _stored_vector((int)vec.get_x(), (int)vec.get_y(), (int)vec.get_z(), 0.0),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_vector((int)vec.get_x(), (int)vec.get_y(), (int)vec.get_z(), 0.0)
 {
 }
 
@@ -614,10 +474,7 @@ ShaderInput(CPT_InternalName name, const LVecBase2i &vec, int priority) :
   _type(M_numeric),
   _priority(priority),
   _stored_ptr(vec),
-  _stored_vector((int)vec.get_x(), (int)vec.get_y(), 0.0, 0.0),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _stored_vector((int)vec.get_x(), (int)vec.get_y(), 0.0, 0.0)
 {
 }
 
@@ -651,16 +508,6 @@ get_priority() const {
   return _priority;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: ShaderInput::get_texture
-//       Access: Published
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE Texture *ShaderInput::
-get_texture() const {
-  return DCAST(Texture, _value);
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: ShaderInput::get_vector
 //       Access: Published
@@ -681,18 +528,6 @@ get_ptr() const {
   return _stored_ptr;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: ShaderInput::get_sampler
-//       Access: Published
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE const SamplerState &ShaderInput::
-get_sampler() const {
-  return (_type == M_texture)
-    ? get_texture()->get_default_sampler()
-    : _sampler;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: ShaderInput::get_param
 //       Access: Public

+ 64 - 4
panda/src/pgraph/shaderInput.cxx

@@ -14,6 +14,7 @@
 
 #include "shaderInput.h"
 #include "paramNodePath.h"
+#include "paramTexture.h"
 
 TypeHandle ShaderInput::_type_handle;
 
@@ -43,10 +44,35 @@ ShaderInput(CPT_InternalName name, const NodePath &np, int priority) :
   _name(MOVE(name)),
   _type(M_nodepath),
   _priority(priority),
-  _value(new ParamNodePath(np)),
-  _bind_layer(0),
-  _bind_level(0),
-  _access(A_read)
+  _value(new ParamNodePath(np))
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShaderInput::Constructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+ShaderInput::
+ShaderInput(CPT_InternalName name, Texture *tex, bool read, bool write, int z, int n, int priority) :
+  _name(MOVE(name)),
+  _type(M_texture_image),
+  _priority(priority),
+  _value(new ParamTextureImage(tex, read, write, z, n))
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShaderInput::Constructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+ShaderInput::
+ShaderInput(CPT_InternalName name, Texture *tex, const SamplerState &sampler, int priority) :
+  _name(MOVE(name)),
+  _type(M_texture_sampler),
+  _priority(priority),
+  _value(new ParamTextureSampler(tex, sampler))
 {
 }
 
@@ -61,6 +87,40 @@ get_nodepath() const {
   return DCAST(ParamNodePath, _value)->get_value();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: ShaderInput::get_texture
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+Texture *ShaderInput::
+get_texture() const {
+  switch (_type) {
+  case M_texture_sampler:
+    return DCAST(ParamTextureSampler, _value)->get_texture();
+
+  case M_texture_image:
+    return DCAST(ParamTextureImage, _value)->get_texture();
+
+  case M_texture:
+    return DCAST(Texture, _value);
+
+  default:
+    return NULL;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShaderInput::get_sampler
+//       Access: Published
+//  Description: Warning: no error checking is done.
+////////////////////////////////////////////////////////////////////
+const SamplerState &ShaderInput::
+get_sampler() const {
+  return (_type == M_texture_sampler)
+    ? DCAST(ParamTextureSampler, _value)->get_sampler()
+    : get_texture()->get_default_sampler();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: ShaderInput::register_with_read_factory
 //       Access: Public, Static

+ 8 - 13
panda/src/pgraph/shaderInput.h

@@ -53,8 +53,6 @@ PUBLISHED:
   static const ShaderInput *get_blank();
   INLINE ShaderInput(CPT_InternalName name, int priority=0);
   INLINE ShaderInput(CPT_InternalName name, Texture *tex, int priority=0);
-  INLINE ShaderInput(CPT_InternalName name, Texture *tex, const SamplerState &sampler, int priority=0);
-  INLINE ShaderInput(CPT_InternalName name, Texture *tex, bool read, bool write, int z=-1, int n=0, int priority=0);
   INLINE ShaderInput(CPT_InternalName name, ParamValueBase *param, int priority=0);
   INLINE ShaderInput(CPT_InternalName name, const PTA_float &ptr, int priority=0);
   INLINE ShaderInput(CPT_InternalName name, const PTA_LVecBase4f &ptr, int priority=0);
@@ -89,6 +87,8 @@ PUBLISHED:
   INLINE ShaderInput(CPT_InternalName name, const LVecBase2i &vec, int priority=0);
 
   ShaderInput(CPT_InternalName name, const NodePath &np, int priority=0);
+  ShaderInput(CPT_InternalName name, Texture *tex, bool read, bool write, int z=-1, int n=0, int priority=0);
+  ShaderInput(CPT_InternalName name, Texture *tex, const SamplerState &sampler, int priority=0);
 
   enum ShaderInputType {
     M_invalid = 0,
@@ -97,19 +97,20 @@ PUBLISHED:
     M_vector,
     M_numeric,
     M_texture_sampler,
-    M_param
+    M_param,
+    M_texture_image
   };
 
   INLINE const InternalName *get_name() const;
 
   INLINE int get_value_type() const;
   INLINE int get_priority() const;
-  INLINE Texture *get_texture() const;
   INLINE const LVecBase4 &get_vector() const;
   INLINE const Shader::ShaderPtrData &get_ptr() const;
-  INLINE const SamplerState &get_sampler() const;
 
   const NodePath &get_nodepath() const;
+  Texture *get_texture() const;
+  const SamplerState &get_sampler() const;
 
 public:
   INLINE ParamValueBase *get_param() const;
@@ -117,25 +118,19 @@ public:
   static void register_with_read_factory();
 
 private:
-  SamplerState _sampler;
   LVecBase4 _stored_vector;
   Shader::ShaderPtrData _stored_ptr;
   CPT_InternalName _name;
   PT(TypedWritableReferenceCount) _value;
   int _priority;
-
-public:
-  int _type : 8;
-  int _access : 8;
-  int _bind_level : 16;
-  int _bind_layer;
+  int _type;
 
 public:
   static TypeHandle get_class_type() {
     return _type_handle;
   }
   static void init_type() {
-    ReferenceCount::init_type();
+    TypedWritableReferenceCount::init_type();
     register_type(_type_handle, "ShaderInput",
                   TypedWritableReferenceCount::get_class_type());
   }

+ 1 - 1
panda/src/pgraphnodes/shaderGenerator.cxx

@@ -652,7 +652,7 @@ synthesize_shader(const RenderState *rs) {
 
   text << "//Cg\n";
 
-  text << "/* Generated shader for render state " << rs << ":\n";
+  text << "/* Generated shader for render state:\n";
   rs->write(text, 2);
   text << "*/\n";
 

+ 3 - 3
panda/src/pnmimage/convert_srgb.I

@@ -18,7 +18,7 @@
 //  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) {
+INLINE float decode_sRGB_float(unsigned char val) {
   return to_linear_float_table[val];
 }
 
@@ -40,7 +40,7 @@ INLINE float decode_sRGB_float(float val) {
 //  Description: Decodes the sRGB-encoded unsigned char value to
 //               a linearized unsigned char value.
 ////////////////////////////////////////////////////////////////////
-CONSTEXPR unsigned char decode_sRGB_uchar(unsigned char val) {
+INLINE unsigned char decode_sRGB_uchar(unsigned char val) {
   return to_linear_uchar_table[val];
 }
 
@@ -88,7 +88,7 @@ encode_sRGB_float(float val) {
 //  Description: Encodes the linearized unsigned char value to an
 //               sRGB-encoded unsigned char value.
 ////////////////////////////////////////////////////////////////////
-CONSTEXPR unsigned char
+INLINE unsigned char
 encode_sRGB_uchar(unsigned char val) {
   return to_srgb8_table[val];
 }

+ 3 - 3
panda/src/pnmimage/convert_srgb.h

@@ -26,14 +26,14 @@ extern EXPCL_PANDA_PNMIMAGE ALIGN_64BYTE const unsigned char to_srgb8_table[256]
 extern EXPCL_PANDA_PNMIMAGE ALIGN_64BYTE const unsigned char to_linear_uchar_table[256];
 extern EXPCL_PANDA_PNMIMAGE ALIGN_64BYTE 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(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(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(unsigned char val);
 EXPCL_PANDA_PNMIMAGE INLINE unsigned char encode_sRGB_uchar(float val);
 
 // These functions convert more than one component in one go,

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