Browse Source

Merge branch 'master' of https://github.com/panda3d/panda3d

David Rose 10 years ago
parent
commit
bc58335214
100 changed files with 3044 additions and 1580 deletions
  1. 0 1
      direct/src/interval/Interval.py
  2. 20 0
      dtool/src/cppparser/cppArrayType.cxx
  3. 2 0
      dtool/src/cppparser/cppArrayType.h
  4. 666 667
      dtool/src/cppparser/cppBison.cxx.prebuilt
  5. 8 0
      dtool/src/cppparser/cppBison.yxx
  6. 20 0
      dtool/src/cppparser/cppConstType.cxx
  7. 2 0
      dtool/src/cppparser/cppConstType.h
  8. 32 0
      dtool/src/cppparser/cppExpression.cxx
  9. 6 0
      dtool/src/cppparser/cppExpression.h
  10. 20 0
      dtool/src/cppparser/cppExtensionType.cxx
  11. 2 0
      dtool/src/cppparser/cppExtensionType.h
  12. 19 5
      dtool/src/cppparser/cppInstance.cxx
  13. 4 0
      dtool/src/cppparser/cppInstance.h
  14. 20 0
      dtool/src/cppparser/cppPointerType.cxx
  15. 2 0
      dtool/src/cppparser/cppPointerType.h
  16. 20 0
      dtool/src/cppparser/cppReferenceType.cxx
  17. 2 0
      dtool/src/cppparser/cppReferenceType.h
  18. 20 0
      dtool/src/cppparser/cppSimpleType.cxx
  19. 2 0
      dtool/src/cppparser/cppSimpleType.h
  20. 297 7
      dtool/src/cppparser/cppStructType.cxx
  21. 8 1
      dtool/src/cppparser/cppStructType.h
  22. 20 0
      dtool/src/cppparser/cppType.cxx
  23. 2 0
      dtool/src/cppparser/cppType.h
  24. 20 0
      dtool/src/cppparser/cppTypedefType.cxx
  25. 2 0
      dtool/src/cppparser/cppTypedefType.h
  26. 52 27
      dtool/src/dtoolbase/dtoolbase_cc.h
  27. 80 0
      dtool/src/dtoolutil/unicodeLatinMap.cxx
  28. 2 0
      dtool/src/dtoolutil/unicodeLatinMap.h
  29. 4 0
      dtool/src/interrogate/interfaceMakerPythonNative.cxx
  30. 53 2
      dtool/src/interrogate/interrogateBuilder.cxx
  31. 3 2
      dtool/src/parser-inc/Eigen/Dense
  32. 11 0
      dtool/src/parser-inc/iostream
  33. 1 1
      panda/src/bullet/bulletBodyNode.cxx
  34. 24 14
      panda/src/collide/collisionBox.I
  35. 61 38
      panda/src/collide/collisionBox.cxx
  36. 14 11
      panda/src/collide/collisionBox.h
  37. 11 0
      panda/src/collide/collisionEntry.h
  38. 5 0
      panda/src/collide/collisionHandlerFloor.h
  39. 11 0
      panda/src/collide/collisionHandlerGravity.h
  40. 3 0
      panda/src/collide/collisionHandlerPhysical.h
  41. 3 0
      panda/src/collide/collisionHandlerPusher.h
  42. 5 0
      panda/src/collide/collisionParabola.h
  43. 4 0
      panda/src/collide/collisionPlane.h
  44. 4 0
      panda/src/collide/collisionPolygon.h
  45. 4 0
      panda/src/collide/collisionSegment.h
  46. 44 91
      panda/src/collide/collisionSphere.cxx
  47. 4 0
      panda/src/collide/collisionSphere.h
  48. 4 0
      panda/src/collide/collisionTraverser.h
  49. 5 0
      panda/src/collide/collisionTube.h
  50. 4 0
      panda/src/collide/collisionVisualizer.h
  51. 6 2
      panda/src/cull/cullBinStateSorted.I
  52. 22 1
      panda/src/display/graphicsStateGuardian.cxx
  53. 92 0
      panda/src/egg/eggMaterial.I
  54. 25 0
      panda/src/egg/eggMaterial.cxx
  55. 24 8
      panda/src/egg/eggMaterial.h
  56. 21 1
      panda/src/egg/parser.cxx.prebuilt
  57. 21 1
      panda/src/egg/parser.yxx
  58. 6 0
      panda/src/egg2pg/eggRenderState.cxx
  59. 8 0
      panda/src/egg2pg/eggSaver.cxx
  60. 28 0
      panda/src/express/ordered_vector.I
  61. 2 0
      panda/src/express/ordered_vector.h
  62. 5 5
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  63. 61 1
      panda/src/glstuff/glShaderContext_src.cxx
  64. 54 31
      panda/src/gobj/material.I
  65. 252 33
      panda/src/gobj/material.cxx
  66. 31 2
      panda/src/gobj/material.h
  67. 1 1
      panda/src/gobj/shader.cxx
  68. 5 0
      panda/src/gobj/shader.h
  69. 15 6
      panda/src/gobj/texture.cxx
  70. 6 6
      panda/src/gobj/texturePool.cxx
  71. 20 36
      panda/src/linmath/lpoint2_src.I
  72. 4 4
      panda/src/linmath/lpoint2_src.h
  73. 12 31
      panda/src/linmath/lpoint3_src.I
  74. 2 3
      panda/src/linmath/lpoint3_src.h
  75. 13 31
      panda/src/linmath/lpoint4_src.I
  76. 2 3
      panda/src/linmath/lpoint4_src.h
  77. 19 54
      panda/src/linmath/lvecBase2_src.I
  78. 11 10
      panda/src/linmath/lvecBase2_src.h
  79. 19 53
      panda/src/linmath/lvecBase3_src.I
  80. 10 8
      panda/src/linmath/lvecBase3_src.h
  81. 42 108
      panda/src/linmath/lvecBase4_src.I
  82. 20 17
      panda/src/linmath/lvecBase4_src.h
  83. 19 34
      panda/src/linmath/lvector2_src.I
  84. 4 4
      panda/src/linmath/lvector2_src.h
  85. 13 30
      panda/src/linmath/lvector3_src.I
  86. 2 3
      panda/src/linmath/lvector3_src.h
  87. 13 31
      panda/src/linmath/lvector4_src.I
  88. 2 3
      panda/src/linmath/lvector4_src.h
  89. 69 54
      panda/src/pgraph/clipPlaneAttrib.cxx
  90. 30 1
      panda/src/pgraph/light.I
  91. 80 2
      panda/src/pgraph/light.cxx
  92. 11 0
      panda/src/pgraph/light.h
  93. 104 62
      panda/src/pgraph/lightAttrib.cxx
  94. 1 1
      panda/src/pgraph/loader.cxx
  95. 134 0
      panda/src/pgraph/nodePath.cxx
  96. 5 0
      panda/src/pgraph/nodePath.h
  97. 1 0
      panda/src/pgraph/nodePathComponent.h
  98. 33 18
      panda/src/pgraph/occluderEffect.cxx
  99. 13 11
      panda/src/pgraph/paramNodePath.cxx
  100. 19 3
      panda/src/pgraphnodes/directionalLight.I

+ 0 - 1
direct/src/interval/Interval.py

@@ -399,7 +399,6 @@ class Interval(DirectObject):
         return (space + self.name + ' dur: %.2f' % self.duration)
 
     open_ended = property(getOpenEnded)
-    loop = property(getLoop, setLoop)
     stopped = property(isStopped)
     t = property(getT, setT)
     play_rate = property(getPlayRate, setPlayRate)

+ 20 - 0
dtool/src/cppparser/cppArrayType.cxx

@@ -87,6 +87,26 @@ is_trivial() const {
   return _element_type->is_trivial();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPArrayType::is_default_constructible
+//       Access: Public, Virtual
+//  Description: Returns true if the type is default-constructible.
+////////////////////////////////////////////////////////////////////
+bool CPPArrayType::
+is_default_constructible() const {
+  return _element_type->is_default_constructible();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPArrayType::is_copy_constructible
+//       Access: Public, Virtual
+//  Description: Returns true if the type is copy-constructible.
+////////////////////////////////////////////////////////////////////
+bool CPPArrayType::
+is_copy_constructible() const {
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPArrayType::is_equivalent
 //       Access: Public, Virtual

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

@@ -41,6 +41,8 @@ public:
                                 CPPScope *global_scope);
   virtual bool is_tbd() const;
   virtual bool is_trivial() const;
+  virtual bool is_default_constructible() const;
+  virtual bool is_copy_constructible() const;
   virtual bool is_equivalent(const CPPType &other) const;
 
   virtual void output(ostream &out, int indent_level, CPPScope *scope,

File diff suppressed because it is too large
+ 666 - 667
dtool/src/cppparser/cppBison.cxx.prebuilt


+ 8 - 0
dtool/src/cppparser/cppBison.yxx

@@ -1524,6 +1524,14 @@ maybe_initialize_or_function_body:
         | '=' const_expr ';'
 {
   $$ = $2;
+}
+        | '=' KW_DEFAULT ';'
+{
+  $$ = new CPPExpression(CPPExpression::get_default());
+}
+        | '=' KW_DELETE ';'
+{
+  $$ = new CPPExpression(CPPExpression::get_delete());
 }
         | '=' '{' structure_init '}'
 {

+ 20 - 0
dtool/src/cppparser/cppConstType.cxx

@@ -112,6 +112,26 @@ is_trivial() const {
   return _wrapped_around->is_trivial();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPConstType::is_default_constructible
+//       Access: Public, Virtual
+//  Description: Returns true if the type is default-constructible.
+////////////////////////////////////////////////////////////////////
+bool CPPConstType::
+is_default_constructible() const {
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPConstType::is_copy_constructible
+//       Access: Public, Virtual
+//  Description: Returns true if the type is copy-constructible.
+////////////////////////////////////////////////////////////////////
+bool CPPConstType::
+is_copy_constructible() const {
+  return _wrapped_around->is_copy_constructible();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPConstType::is_equivalent
 //       Access: Public, Virtual

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

@@ -39,6 +39,8 @@ public:
 
   virtual bool is_tbd() const;
   virtual bool is_trivial() const;
+  virtual bool is_default_constructible() const;
+  virtual bool is_copy_constructible() const;
   virtual bool is_equivalent(const CPPType &other) const;
 
   virtual void output(ostream &out, int indent_level, CPPScope *scope,

+ 32 - 0
dtool/src/cppparser/cppExpression.cxx

@@ -494,6 +494,30 @@ get_nullptr() {
   return expr;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPExpression::get_default
+//       Access: Public, Static
+//  Description:
+////////////////////////////////////////////////////////////////////
+const CPPExpression &CPPExpression::
+get_default() {
+  static CPPExpression expr(0);
+  expr._type = T_default;
+  return expr;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPExpression::get_delete
+//       Access: Public, Static
+//  Description:
+////////////////////////////////////////////////////////////////////
+const CPPExpression &CPPExpression::
+get_delete() {
+  static CPPExpression expr(0);
+  expr._type = T_delete;
+  return expr;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPExpression::Destructor
 //       Access: Public
@@ -1619,6 +1643,14 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
     }
     break;
 
+  case T_default:
+    out << "default";
+    break;
+
+  case T_delete:
+    out << "delete";
+    break;
+
   default:
     out << "(** invalid operand type " << (int)_type << " **)";
   }

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

@@ -52,6 +52,8 @@ public:
   static CPPExpression raw_literal(const string &raw, CPPInstance *lit_op);
 
   static const CPPExpression &get_nullptr();
+  static const CPPExpression &get_default();
+  static const CPPExpression &get_delete();
 
   ~CPPExpression();
 
@@ -124,6 +126,10 @@ public:
     T_trinary_operation,
     T_literal,
     T_raw_literal,
+
+    // These are used when parsing =default and =delete methods.
+    T_default,
+    T_delete,
   };
 
   Type _type;

+ 20 - 0
dtool/src/cppparser/cppExtensionType.cxx

@@ -114,6 +114,26 @@ is_trivial() const {
   return (_type == T_enum);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPExtensionType::is_default_constructible
+//       Access: Public, Virtual
+//  Description: Returns true if the type is default-constructible.
+////////////////////////////////////////////////////////////////////
+bool CPPExtensionType::
+is_default_constructible() const {
+  return (_type == T_enum);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPExtensionType::is_copy_constructible
+//       Access: Public, Virtual
+//  Description: Returns true if the type is copy-constructible.
+////////////////////////////////////////////////////////////////////
+bool CPPExtensionType::
+is_copy_constructible() const {
+  return (_type == T_enum);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPExtensionType::substitute_decl
 //       Access: Public, Virtual

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

@@ -48,6 +48,8 @@ public:
   virtual bool is_incomplete() const;
   virtual bool is_tbd() const;
   virtual bool is_trivial() const;
+  virtual bool is_default_constructible() const;
+  virtual bool is_copy_constructible() const;
 
   virtual CPPDeclaration *substitute_decl(SubstDecl &subst,
                                           CPPScope *current_scope,

+ 19 - 5
dtool/src/cppparser/cppInstance.cxx

@@ -251,12 +251,20 @@ void CPPInstance::
 set_initializer(CPPExpression *initializer) {
   if (_type->as_function_type() != (CPPFunctionType *)NULL) {
     // This is a function declaration.
-    if (initializer == (CPPExpression *)NULL) {
-      _storage_class &= ~SC_pure_virtual;
-    } else {
-      _storage_class |= SC_pure_virtual;
-    }
+    _storage_class &= ~(SC_pure_virtual | SC_defaulted | SC_deleted);
     _initializer = (CPPExpression *)NULL;
+
+    if (initializer != (CPPExpression *)NULL) {
+      if (initializer->_type == CPPExpression::T_integer) { // = 0
+        _storage_class |= SC_pure_virtual;
+
+      } else if (initializer->_type == CPPExpression::T_default) {
+        _storage_class |= SC_defaulted;
+
+      } else if (initializer->_type == CPPExpression::T_delete) {
+        _storage_class |= SC_deleted;
+      }
+    }
   } else {
     _initializer = initializer;
   }
@@ -622,6 +630,12 @@ output(ostream &out, int indent_level, CPPScope *scope, bool complete,
   if (_storage_class & SC_pure_virtual) {
     out << " = 0";
   }
+  if (_storage_class & SC_defaulted) {
+    out << " = default";
+  }
+  if (_storage_class & SC_deleted) {
+    out << " = delete";
+  }
   if (_initializer != NULL) {
     out << " = " << *_initializer;
   }

+ 4 - 0
dtool/src/cppparser/cppInstance.h

@@ -60,6 +60,10 @@ public:
     // And this is for methods tagged with __extension, which declares
     // extension methods defined separately from the source code.
     SC_extension    = 0x2000,
+
+    // These are for =default and =delete functions.
+    SC_defaulted    = 0x4000,
+    SC_deleted      = 0x8000,
   };
 
   CPPInstance(CPPType *type, const string &name, int storage_class = 0);

+ 20 - 0
dtool/src/cppparser/cppPointerType.cxx

@@ -114,6 +114,26 @@ is_trivial() const {
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPPointerType::is_default_constructible
+//       Access: Public, Virtual
+//  Description: Returns true if the type is default-constructible.
+////////////////////////////////////////////////////////////////////
+bool CPPPointerType::
+is_default_constructible() const {
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPPointerType::is_copy_constructible
+//       Access: Public, Virtual
+//  Description: Returns true if the type is copy-constructible.
+////////////////////////////////////////////////////////////////////
+bool CPPPointerType::
+is_copy_constructible() const {
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPPointerType::is_equivalent
 //       Access: Public, Virtual

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

@@ -39,6 +39,8 @@ public:
 
   virtual bool is_tbd() const;
   virtual bool is_trivial() const;
+  virtual bool is_default_constructible() const;
+  virtual bool is_copy_constructible() const;
   virtual bool is_equivalent(const CPPType &other) const;
 
   virtual void output(ostream &out, int indent_level, CPPScope *scope,

+ 20 - 0
dtool/src/cppparser/cppReferenceType.cxx

@@ -113,6 +113,26 @@ is_trivial() const {
   return false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPReferenceType::is_default_constructible
+//       Access: Public, Virtual
+//  Description: Returns true if the type is default-constructible.
+////////////////////////////////////////////////////////////////////
+bool CPPReferenceType::
+is_default_constructible() const {
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPReferenceType::is_copy_constructible
+//       Access: Public, Virtual
+//  Description: Returns true if the type is copy-constructible.
+////////////////////////////////////////////////////////////////////
+bool CPPReferenceType::
+is_copy_constructible() const {
+  return (_value_category == VC_lvalue);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPReferenceType::is_equivalent
 //       Access: Public, Virtual

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

@@ -45,6 +45,8 @@ public:
 
   virtual bool is_tbd() const;
   virtual bool is_trivial() const;
+  virtual bool is_default_constructible() const;
+  virtual bool is_copy_constructible() const;
   virtual bool is_equivalent(const CPPType &other) const;
 
   virtual void output(ostream &out, int indent_level, CPPScope *scope,

+ 20 - 0
dtool/src/cppparser/cppSimpleType.cxx

@@ -51,6 +51,26 @@ is_trivial() const {
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPSimpleType::is_default_constructible
+//       Access: Public, Virtual
+//  Description: Returns true if the type is default-constructible.
+////////////////////////////////////////////////////////////////////
+bool CPPSimpleType::
+is_default_constructible() const {
+  return (_type != T_void);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPSimpleType::is_copy_constructible
+//       Access: Public, Virtual
+//  Description: Returns true if the type is copy-constructible.
+////////////////////////////////////////////////////////////////////
+bool CPPSimpleType::
+is_copy_constructible() const {
+  return (_type != T_void);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPSimpleType::is_parameter_expr
 //       Access: Public, Virtual

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

@@ -79,6 +79,8 @@ public:
 
   virtual bool is_tbd() const;
   virtual bool is_trivial() const;
+  virtual bool is_default_constructible() const;
+  virtual bool is_copy_constructible() const;
   virtual bool is_parameter_expr() const;
 
   virtual string get_preferred_name() const;

+ 297 - 7
dtool/src/cppparser/cppStructType.cxx

@@ -190,6 +190,11 @@ is_trivial() const {
         return false;
       }
 
+      // The following checks don't apply for defaulted functions.
+      if (inst->_storage_class & CPPInstance::SC_defaulted) {
+        continue;
+      }
+
       assert(inst->_type != (CPPType *)NULL);
       CPPFunctionType *ftype = inst->_type->as_function_type();
       assert(ftype != (CPPFunctionType *)NULL);
@@ -197,7 +202,8 @@ is_trivial() const {
       if (ftype->_flags & (CPPFunctionType::F_destructor |
                            CPPFunctionType::F_move_constructor |
                            CPPFunctionType::F_copy_constructor)) {
-        // User-provided destructors and copy/move constructors are not trivial.
+        // User-provided destructors and copy/move constructors are not
+        // trivial unless they are defaulted (and not virtual).
         return false;
       }
 
@@ -223,6 +229,193 @@ is_trivial() const {
   return is_default_constructible;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPStructType::is_default_constructible
+//       Access: Public, Virtual
+//  Description: Returns true if the type is default-constructible.
+////////////////////////////////////////////////////////////////////
+bool CPPStructType::
+is_default_constructible() const {
+  return is_default_constructible(V_public);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPStructType::is_copy_constructible
+//       Access: Public, Virtual
+//  Description: Returns true if the type is copy-constructible.
+////////////////////////////////////////////////////////////////////
+bool CPPStructType::
+is_copy_constructible() const {
+  return is_copy_constructible(V_public);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPStructType::is_default_constructible
+//       Access: Public
+//  Description: Returns true if the type is default-constructible.
+////////////////////////////////////////////////////////////////////
+bool CPPStructType::
+is_default_constructible(CPPVisibility min_vis) const {
+  CPPInstance *constructor = get_default_constructor();
+  if (constructor != (CPPInstance *)NULL) {
+    // It has a default constructor.
+    if (constructor->_vis > min_vis) {
+      // Inaccessible default constructor.
+      return false;
+    }
+
+    if (constructor->_storage_class & CPPInstance::SC_deleted) {
+      // Deleted default constructor.
+      return false;
+    }
+
+    return true;
+  }
+
+  // Does it have constructors at all?  If so, no implicit one is generated.
+  if (get_constructor() != (CPPFunctionGroup *)NULL) {
+    return false;
+  }
+
+  // Implicit default constructor.  Check if the implicit default
+  // constructor is deleted.
+  Derivation::const_iterator di;
+  for (di = _derivation.begin(); di != _derivation.end(); ++di) {
+    CPPStructType *base = (*di)._base->as_struct_type();
+    if (base != NULL) {
+      if (!base->is_default_constructible(V_protected)) {
+        return false;
+      }
+    }
+  }
+
+  // Make sure all members are default-constructible or have default values.
+  CPPScope::Variables::const_iterator vi;
+  for (vi = _scope->_variables.begin(); vi != _scope->_variables.end(); ++vi) {
+    CPPInstance *instance = (*vi).second;
+    assert(instance != NULL);
+
+    if (instance->_storage_class & CPPInstance::SC_static) {
+      // Static members don't count.
+      continue;
+    }
+
+    if (instance->_initializer != (CPPExpression *)NULL) {
+      // It has a default value.
+      continue;
+    }
+
+    if (!instance->_type->is_default_constructible()) {
+      return false;
+    }
+  }
+
+  // Check that we don't have pure virtual methods.
+  CPPScope::Functions::const_iterator fi;
+  for (fi = _scope->_functions.begin();
+       fi != _scope->_functions.end();
+       ++fi) {
+    CPPFunctionGroup *fgroup = (*fi).second;
+    CPPFunctionGroup::Instances::const_iterator ii;
+    for (ii = fgroup->_instances.begin();
+         ii != fgroup->_instances.end();
+         ++ii) {
+      CPPInstance *inst = (*ii);
+      if (inst->_storage_class & CPPInstance::SC_pure_virtual) {
+        // Here's a pure virtual function.
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPStructType::is_copy_constructible
+//       Access: Public
+//  Description: Returns true if the type is copy-constructible.
+////////////////////////////////////////////////////////////////////
+bool CPPStructType::
+is_copy_constructible(CPPVisibility min_vis) const {
+  CPPInstance *constructor = get_copy_constructor();
+  if (constructor != (CPPInstance *)NULL) {
+    // It has a copy constructor.
+    if (constructor->_vis > min_vis) {
+      // Inaccessible copy constructor.
+      return false;
+    }
+
+    if (constructor->_storage_class & CPPInstance::SC_deleted) {
+      // Deleted copy constructor.
+      return false;
+    }
+
+    return true;
+  }
+
+  CPPInstance *destructor = get_destructor();
+  if (destructor != (CPPInstance *)NULL) {
+    if (destructor->_vis > min_vis) {
+      // Inaccessible destructor.
+      return false;
+    }
+
+    if (destructor->_storage_class & CPPInstance::SC_deleted) {
+      // Deleted destructor.
+      return false;
+    }
+  }
+
+  // Implicit copy constructor.  Check if the implicit copy
+  // constructor is deleted.
+  Derivation::const_iterator di;
+  for (di = _derivation.begin(); di != _derivation.end(); ++di) {
+    CPPStructType *base = (*di)._base->as_struct_type();
+    if (base != NULL) {
+      if (!base->is_copy_constructible(V_protected)) {
+        return false;
+      }
+    }
+  }
+
+  // Make sure all members are copy-constructible.
+  CPPScope::Variables::const_iterator vi;
+  for (vi = _scope->_variables.begin(); vi != _scope->_variables.end(); ++vi) {
+    CPPInstance *instance = (*vi).second;
+    assert(instance != NULL);
+
+    if (instance->_storage_class & CPPInstance::SC_static) {
+      // Static members don't count.
+      continue;
+    }
+
+    if (!instance->_type->is_copy_constructible()) {
+      return false;
+    }
+  }
+
+  // Check that we don't have pure virtual methods.
+  CPPScope::Functions::const_iterator fi;
+  for (fi = _scope->_functions.begin();
+       fi != _scope->_functions.end();
+       ++fi) {
+    CPPFunctionGroup *fgroup = (*fi).second;
+    CPPFunctionGroup::Instances::const_iterator ii;
+    for (ii = fgroup->_instances.begin();
+         ii != fgroup->_instances.end();
+         ++ii) {
+      CPPInstance *inst = (*ii);
+      if (inst->_storage_class & CPPInstance::SC_pure_virtual) {
+        // Here's a pure virtual function.
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPStructType::check_virtual
 //       Access: Public
@@ -244,7 +437,7 @@ is_trivial() const {
 //               virtual function pointer), or false otherwise.
 ////////////////////////////////////////////////////////////////////
 bool CPPStructType::
-check_virtual() {
+check_virtual() const {
   VFunctions funcs;
   get_virtual_funcs(funcs);
   return !funcs.empty();
@@ -285,9 +478,7 @@ is_incomplete() const {
 ////////////////////////////////////////////////////////////////////
 CPPFunctionGroup *CPPStructType::
 get_constructor() const {
-  // Iterate through all the functions that begin with '~' until we
-  // find one that claims to be a destructor.  In theory, there should
-  // only be one such function.
+  // Just look for the function with the same name as the class.
   CPPScope::Functions::const_iterator fi;
   fi = _scope->_functions.find(get_simple_name());
   if (fi != _scope->_functions.end()) {
@@ -297,6 +488,101 @@ get_constructor() const {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPStructType::get_default_constructor
+//       Access: Public
+//  Description: Returns the default constructor defined for the
+//               struct type, or NULL if there is none.
+////////////////////////////////////////////////////////////////////
+CPPInstance *CPPStructType::
+get_default_constructor() const {
+  CPPFunctionGroup *fgroup = get_constructor();
+  if (fgroup == (CPPFunctionGroup *)NULL) {
+    return (CPPInstance *)NULL;
+  }
+
+  CPPFunctionGroup::Instances::const_iterator ii;
+  for (ii = fgroup->_instances.begin();
+       ii != fgroup->_instances.end();
+       ++ii) {
+    CPPInstance *inst = (*ii);
+    assert(inst->_type != (CPPType *)NULL);
+
+    CPPFunctionType *ftype = inst->_type->as_function_type();
+    assert(ftype != (CPPFunctionType *)NULL);
+
+    if (ftype->_parameters->_parameters.size() == 0 ||
+        ftype->_parameters->_parameters.front()->_initializer != NULL) {
+      // It takes 0 parameters (or all parameters have default values).
+      return inst;
+    }
+  }
+
+  return (CPPInstance *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPStructType::get_copy_constructor
+//       Access: Public
+//  Description: Returns the copy constructor defined for the struct
+//               type, or NULL if no copy constructor exists.
+////////////////////////////////////////////////////////////////////
+CPPInstance *CPPStructType::
+get_copy_constructor() const {
+  CPPFunctionGroup *fgroup = get_constructor();
+  if (fgroup == (CPPFunctionGroup *)NULL) {
+    return (CPPInstance *)NULL;
+  }
+
+  CPPFunctionGroup::Instances::const_iterator ii;
+  for (ii = fgroup->_instances.begin();
+       ii != fgroup->_instances.end();
+       ++ii) {
+    CPPInstance *inst = (*ii);
+    assert(inst->_type != (CPPType *)NULL);
+
+    CPPFunctionType *ftype = inst->_type->as_function_type();
+    assert(ftype != (CPPFunctionType *)NULL);
+
+    if ((ftype->_flags & CPPFunctionType::F_copy_constructor) != 0) {
+      return inst;
+    }
+  }
+
+  return (CPPInstance *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPStructType::get_move_constructor
+//       Access: Public
+//  Description: Returns the move constructor defined for the struct
+//               type, or NULL if no move constructor exists.
+////////////////////////////////////////////////////////////////////
+CPPInstance *CPPStructType::
+get_move_constructor() const {
+  CPPFunctionGroup *fgroup = get_constructor();
+  if (fgroup == (CPPFunctionGroup *)NULL) {
+    return (CPPInstance *)NULL;
+  }
+
+  CPPFunctionGroup::Instances::const_iterator ii;
+  for (ii = fgroup->_instances.begin();
+       ii != fgroup->_instances.end();
+       ++ii) {
+    CPPInstance *inst = (*ii);
+    assert(inst->_type != (CPPType *)NULL);
+
+    CPPFunctionType *ftype = inst->_type->as_function_type();
+    assert(ftype != (CPPFunctionType *)NULL);
+
+    if ((ftype->_flags & CPPFunctionType::F_move_constructor) != 0) {
+      return inst;
+    }
+  }
+
+  return (CPPInstance *)NULL;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPStructType::get_destructor
 //       Access: Public
@@ -584,7 +870,10 @@ get_virtual_funcs(VFunctions &funcs) const {
     CPPFunctionType *base_ftype = inst->_type->as_function_type();
     assert(base_ftype != (CPPFunctionType *)NULL);
 
-    if ((base_ftype->_flags & CPPFunctionType::F_destructor) != 0) {
+    if (inst->_storage_class & CPPInstance::SC_deleted) {
+      // Ignore deleted functions.
+
+    } else if ((base_ftype->_flags & CPPFunctionType::F_destructor) != 0) {
       // Match destructor-for-destructor; don't try to match
       // destructors up by name.
       CPPInstance *destructor = get_destructor();
@@ -646,7 +935,8 @@ get_virtual_funcs(VFunctions &funcs) const {
          ii != fgroup->_instances.end();
          ++ii) {
       CPPInstance *inst = (*ii);
-      if ((inst->_storage_class & CPPInstance::SC_virtual) != 0) {
+      if ((inst->_storage_class & CPPInstance::SC_virtual) != 0 &&
+          (inst->_storage_class & CPPInstance::SC_deleted) == 0) {
         // Here's a virtual function.
         funcs.push_back(inst);
       }

+ 8 - 1
dtool/src/cppparser/cppStructType.h

@@ -46,12 +46,19 @@ public:
   CPPScope *get_scope() const;
 
   bool is_abstract() const;
-  bool check_virtual();
+  bool check_virtual() const;
   virtual bool is_fully_specified() const;
   virtual bool is_incomplete() const;
   virtual bool is_trivial() const;
+  virtual bool is_default_constructible() const;
+  virtual bool is_copy_constructible() const;
+  bool is_default_constructible(CPPVisibility min_vis) const;
+  bool is_copy_constructible(CPPVisibility min_vis) const;
 
   CPPFunctionGroup *get_constructor() const;
+  CPPInstance *get_default_constructor() const;
+  CPPInstance *get_copy_constructor() const;
+  CPPInstance *get_move_constructor() const;
   CPPInstance *get_destructor() const;
 
   virtual CPPDeclaration *

+ 20 - 0
dtool/src/cppparser/cppType.cxx

@@ -79,6 +79,26 @@ is_trivial() const {
   return false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPType::is_default_constructible
+//       Access: Public, Virtual
+//  Description: Returns true if the type is default-constructible.
+////////////////////////////////////////////////////////////////////
+bool CPPType::
+is_default_constructible() const {
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPType::is_copy_constructible
+//       Access: Public, Virtual
+//  Description: Returns true if the type is copy-constructible.
+////////////////////////////////////////////////////////////////////
+bool CPPType::
+is_copy_constructible() const {
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPType::is_parameter_expr
 //       Access: Public, Virtual

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

@@ -49,6 +49,8 @@ public:
 
   virtual bool is_tbd() const;
   virtual bool is_trivial() const;
+  virtual bool is_default_constructible() const;
+  virtual bool is_copy_constructible() const;
   virtual bool is_parameter_expr() const;
 
   bool has_typedef_name() const;

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

@@ -189,6 +189,26 @@ is_trivial() const {
   return _type->is_trivial();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPTypedefType::is_default_constructible
+//       Access: Public, Virtual
+//  Description: Returns true if the type is default-constructible.
+////////////////////////////////////////////////////////////////////
+bool CPPTypedefType::
+is_default_constructible() const {
+  return _type->is_default_constructible();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPTypedefType::is_copy_constructible
+//       Access: Public, Virtual
+//  Description: Returns true if the type is copy-constructible.
+////////////////////////////////////////////////////////////////////
+bool CPPTypedefType::
+is_copy_constructible() const {
+  return _type->is_copy_constructible();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPTypedefType::is_fully_specified
 //       Access: Public, Virtual

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

@@ -43,6 +43,8 @@ public:
   virtual bool is_incomplete() const;
   virtual bool is_tbd() const;
   virtual bool is_trivial() const;
+  virtual bool is_default_constructible() const;
+  virtual bool is_copy_constructible() const;
 
   virtual bool is_fully_specified() const;
 

+ 52 - 27
dtool/src/dtoolbase/dtoolbase_cc.h

@@ -39,6 +39,7 @@ using namespace std;
 #define FINAL
 #define OVERRIDE
 #define MOVE(x) x
+#define DEFAULT_CTOR = default
 
 #define EXPORT_TEMPLATE_CLASS(expcl, exptp, classname)
 
@@ -136,59 +137,83 @@ typedef ios::seekdir ios_seekdir;
 #if defined(__has_extension) // Clang magic.
 #  if __has_extension(cxx_constexpr)
 #    define CONSTEXPR constexpr
-#  else
-#    define CONSTEXPR INLINE
 #  endif
 #  if __has_extension(cxx_noexcept)
 #    define NOEXCEPT noexcept
-#  else
-#    define NOEXCEPT
 #  endif
 #  if __has_extension(cxx_rvalue_references) && (__cplusplus >= 201103L)
 #    define USE_MOVE_SEMANTICS
 #    define MOVE(x) move(x)
-#  else
-#    define MOVE(x) x
 #  endif
 #  if __has_extension(cxx_override_control) && (__cplusplus >= 201103L)
 #    define FINAL final
 #    define OVERRIDE override
-#  else
-#    define FINAL
-#    define OVERRIDE
 #  endif
-#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) && (__cplusplus >= 201103L)
-// noexcept was introduced in GCC 4.6, constexpr in GCC 4.7, rvalue refs in
-// GCC 4.3.  However, GCC only started defining __cplusplus properly in 4.7.
-#  define CONSTEXPR constexpr
-#  define NOEXCEPT noexcept
-#  define USE_MOVE_SEMANTICS
-#  define FINAL final
-#  define OVERRIDE override
-#  define MOVE(x) move(x)
-#elif defined(_MSC_VER) && _MSC_VER >= 1900
-// MSVC 2015 supports all of this goodness.
+#  if __has_extension(cxx_defaulted_functions)
+#     define DEFAULT_CTOR = default
+#  endif
+#elif defined(__GNUC__) && (__cplusplus >= 201103L) // GCC
+
+// GCC defines several macros which we can query.
+// List of all supported builtin macros: https://gcc.gnu.org/projects/cxx0x.html
+#  if __cpp_constexpr >= 200704
+#    define CONSTEXPR constexpr
+#  endif
+
+// Starting at GCC 4.4
+#  if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)
+#  define DEFAULT_CTOR = default
+#  endif
+
+// Starting at GCC 4.6
+#  if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+#    define NOEXCEPT noexcept
+#    define USE_MOVE_SEMANTICS
+#    define FINAL final
+#    define MOVE(x) move(x)
+#  endif
+
+// Starting at GCC 4.7
+#  if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)
+#    define OVERRIDE override
+#  endif
+
+#elif defined(_MSC_VER) && _MSC_VER >= 1900 // Visual Studio 2015
 #  define CONSTEXPR constexpr
 #  define NOEXCEPT noexcept
 #  define USE_MOVE_SEMANTICS
 #  define FINAL final
 #  define OVERRIDE override
 #  define MOVE(x) move(x)
-#elif defined(_MSC_VER) && _MSC_VER >= 1600
-// MSVC 2010 has move semantics.  Not much else.
-#  define CONSTEXPR INLINE
+#  define DEFAULT_CTOR = default
+#elif defined(_MSC_VER) && _MSC_VER >= 1600 // Visual Studio 2010
 #  define NOEXCEPT throw()
+#  define OVERRIDE override
 #  define USE_MOVE_SEMANTICS
-#  define FINAL
-#  define OVERRIDE
+#  define FINAL sealed
 #  define MOVE(x) move(x)
-#else
+#endif
+
+// Fallbacks if features are not supported
+#ifndef CONSTEXPR
 #  define CONSTEXPR INLINE
+#endif
+#ifndef NOEXCEPT
 #  define NOEXCEPT
+#endif
+#ifndef MOVE
+#  define MOVE(x) x
+#endif
+#ifndef FINAL
 #  define FINAL
+#endif
+#ifndef OVERRIDE
 #  define OVERRIDE
-#  define MOVE(x) x
 #endif
+#ifndef DEFAULT_CTOR
+#  define DEFAULT_CTOR {}
+#endif
+
 
 #if !defined(LINK_ALL_STATIC) && defined(EXPORT_TEMPLATES)
 // This macro must be used to export an instantiated template class

+ 80 - 0
dtool/src/dtoolutil/unicodeLatinMap.cxx

@@ -1306,6 +1306,74 @@ static const UnicodeLatinMap::Entry latin_map[] = {
 static const size_t latin_map_length = sizeof(latin_map) / sizeof(UnicodeLatinMap::Entry);
 #endif
 
+static const wchar_t combining_accent_map[] = {
+  0x0000, // none
+  0x0301, // acute
+  0x0000, // acute_and_dot_above
+  0x0306, // breve
+  0x0000, // breve_and_acute
+  0x0000, // breve_and_dot_below
+  0x0000, // breve_and_grave
+  0x0000, // breve_and_hook_above
+  0x0000, // breve_and_tilde
+  0x032e, // breve_below
+  0x030c, // caron
+  0x0000, // caron_and_dot_above
+  0x0327, // cedilla
+  0x0000, // cedilla_and_acute
+  0x0000, // cedilla_and_breve
+  0x0302, // circumflex
+  0x0000, // circumflex_and_acute
+  0x0000, // circumflex_and_dot_below
+  0x0000, // circumflex_and_grave
+  0x0000, // circumflex_and_hook_above
+  0x0000, // circumflex_and_tilde
+  0x032d, // circumflex_below
+  0x0326, // comma_below
+  0x0000, // curl
+  0x0308, // diaeresis
+  0x0000, // diaeresis_and_acute
+  0x0000, // diaeresis_and_caron
+  0x0000, // diaeresis_and_grave
+  0x0000, // diaeresis_and_macron
+  0x0324, // diaeresis_below
+  0x0307, // dot_above
+  0x0000, // dot_above_and_macron
+  0x0323, // dot_below
+  0x0000, // dot_below_and_dot_above
+  0x0000, // dot_below_and_macron
+  0x030b, // double_acute
+  0x030f, // double_grave
+  0x0300, // grave
+  0x0328, // hook
+  0x0309, // hook_above
+  0x031b, // horn
+  0x0000, // horn_and_acute
+  0x0000, // horn_and_dot_below
+  0x0000, // horn_and_grave
+  0x0000, // horn_and_hook_above
+  0x0000, // horn_and_tilde
+  0x0311, // inverted_breve
+  0x0000, // line_below
+  0x0304, // macron
+  0x0000, // macron_and_acute
+  0x0000, // macron_and_diaeresis
+  0x0000, // macron_and_grave
+  0x0328, // ogonek
+  0x0000, // ogonek_and_macron
+  0x030a, // ring_above
+  0x0000, // ring_above_and_acute
+  0x0325, // ring_below
+  0x0000, // stroke
+  0x0000, // stroke_and_acute
+  0x0000, // stroke_and_hook
+  0x0303, // tilde
+  0x0000, // tilde_and_acute
+  0x0000, // tilde_and_diaeresis
+  0x0000, // tilde_and_macron
+  0x0330, // tilde_below
+  0x0000, // topbar
+};
 
 ////////////////////////////////////////////////////////////////////
 //     Function: UnicodeLatinMap::look_up
@@ -1332,6 +1400,18 @@ look_up(wchar_t character) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: UnicodeLatinMap::get_combining_accent
+//       Access: Public, Static
+//  Description: Returns the unicode code point for the combining
+//               character corresponding with the given accent type,
+//               or 0 if none is recorded.
+////////////////////////////////////////////////////////////////////
+wchar_t UnicodeLatinMap::
+get_combining_accent(AccentType accent) {
+  return combining_accent_map[(size_t)accent];
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: UnicodeLatinMap::init
 //       Access: Private, Static

+ 2 - 0
dtool/src/dtoolutil/unicodeLatinMap.h

@@ -129,6 +129,8 @@ public:
 
   static const Entry *look_up(wchar_t character);
 
+  static wchar_t get_combining_accent(AccentType accent);
+
 private:
   static void init();
   static bool _initialized;

+ 4 - 0
dtool/src/interrogate/interfaceMakerPythonNative.cxx

@@ -5925,6 +5925,10 @@ write_function_instance(ostream &out, FunctionRemap *remap,
       indent(out, indent_level)
         << "return DTool_PyInit_Finalize(self, (void *)" << return_expr << ", &" << CLASS_PREFIX << make_safe_name(itype.get_scoped_name()) << ", true, false);\n";
 
+    } else if (TypeManager::is_bool(orig_type)) {
+      // It's an error return boolean, I guess.  Return 0 on success.
+      indent(out, indent_level) << "return (" << return_expr << ") ? 0 : -1;\n";
+
     } else if (TypeManager::is_integer(orig_type)) {
       if ((return_flags & RF_compare) == RF_compare) {
         // Make sure it returns -1, 0, or 1, or Python complains with:

+ 53 - 2
dtool/src/interrogate/interrogateBuilder.cxx

@@ -1134,8 +1134,8 @@ scan_function(CPPInstance *function) {
     return;
   }
 
-  if ((function->_storage_class & CPPInstance::SC_static) != 0) {
-    // The function is static, so can't be exported.
+  if ((function->_storage_class & (CPPInstance::SC_static | CPPInstance::SC_deleted)) != 0) {
+    // The function is static or deleted, so can't be exported.
     return;
   }
 
@@ -2684,6 +2684,52 @@ define_struct_type(InterrogateType &itype, CPPStructType *cpptype,
     }
   }
 
+  // See if we need to generate an implicit default constructor.
+  CPPFunctionGroup *constructor = cpptype->get_constructor();
+  if (constructor == (CPPFunctionGroup *)NULL && cpptype->is_default_constructible()) {
+    // Make a default constructor.
+    CPPType *void_type = TypeManager::get_void_type();
+    CPPParameterList *params = new CPPParameterList;
+    CPPFunctionType *ftype = new CPPFunctionType(void_type, params, CPPFunctionType::F_constructor);
+
+    // Now make up an instance for the default constructor.
+    CPPInstance *function = new CPPInstance(ftype, cpptype->get_simple_name());
+    function->_storage_class |= CPPInstance::SC_inline | CPPInstance::SC_defaulted;
+    function->_vis = V_published;
+
+    FunctionIndex index = get_function(function, "", cpptype, cpptype->get_scope(), 0);
+    if (find(itype._constructors.begin(), itype._constructors.end(),
+             index) == itype._constructors.end()) {
+      itype._constructors.push_back(index);
+    }
+  }
+
+  // See if we need to generate an implicit copy constructor.
+  CPPInstance *copy_constructor = cpptype->get_copy_constructor();
+  if (copy_constructor == (CPPInstance *)NULL &&
+      cpptype->is_copy_constructible()) {
+    // Make an implicit copy constructor.
+    CPPType *const_ref_type = TypeManager::wrap_const_reference(cpptype);
+    CPPInstance *param = new CPPInstance(const_ref_type, NULL);
+
+    CPPType *void_type = TypeManager::get_void_type();
+    CPPParameterList *params = new CPPParameterList;
+    params->_parameters.push_back(param);
+    const int flags = CPPFunctionType::F_constructor | CPPFunctionType::F_copy_constructor;
+    CPPFunctionType *ftype = new CPPFunctionType(void_type, params, flags);
+
+    // Now make up an instance for the copy constructor.
+    CPPInstance *function = new CPPInstance(ftype, cpptype->get_simple_name());
+    function->_storage_class |= CPPInstance::SC_inline | CPPInstance::SC_defaulted;
+    function->_vis = V_published;
+
+    FunctionIndex index = get_function(function, "", cpptype, cpptype->get_scope(), 0);
+    if (find(itype._constructors.begin(), itype._constructors.end(),
+             index) == itype._constructors.end()) {
+      itype._constructors.push_back(index);
+    }
+  }
+
   if ((itype._flags & InterrogateType::F_inherited_destructor) != 0) {
     // If we have inherited our virtual destructor from our base
     // class, go ahead and assign the same function index.
@@ -2821,6 +2867,11 @@ define_method(CPPInstance *function, InterrogateType &itype,
     return;
   }
 
+  if (function->_storage_class & CPPInstance::SC_deleted) {
+    // It was explicitly marked as deleted.
+    return;
+  }
+
   // As a special kludgey extension, we consider a public static
   // method called "get_class_type()" to be marked published, even if
   // it is not.  This allows us to export all of the TypeHandle system

+ 3 - 2
dtool/src/parser-inc/Eigen/Dense

@@ -1,4 +1,5 @@
 namespace Eigen {
-   template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
-   class Matrix;
+ template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
+ class Matrix {
+ };
 };

+ 11 - 0
dtool/src/parser-inc/iostream

@@ -59,6 +59,8 @@ __published:
 protected:
   // Force this to be a non-trivial type.
   ios_base() {};
+private:
+  ios_base(const ios_base &);
 };
 class ios : public ios_base {
 __published:
@@ -69,6 +71,9 @@ __published:
   bool fail() const;
   bool bad() const;
   void clear();
+
+protected:
+  ios();
 };
 
 // We actually want to wrap streampos as streamoff.
@@ -76,6 +81,8 @@ __published:
 
 class ostream : virtual public ios {
 __published:
+  ostream(const ostream&) = delete;
+
   void put(char c);
   void flush();
   streampos tellp();
@@ -84,6 +91,8 @@ __published:
 };
 class istream : virtual public ios {
 __published:
+  istream(const istream&) = delete;
+
   int get();
   streampos tellg();
   void seekg(streampos pos);
@@ -91,6 +100,8 @@ __published:
 };
 class iostream : public istream, public ostream {
 __published:
+  iostream(const iostream&) = delete;
+
   void flush();
 };
 

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

@@ -644,7 +644,7 @@ add_shapes_from_collision_solids(CollisionNode *cnode) {
     // CollisionBox
     else if (CollisionBox::get_class_type() == type) {
       CPT(CollisionBox) box = DCAST(CollisionBox, solid);
-      CPT(TransformState) ts = TransformState::make_pos(box->get_approx_center());
+      CPT(TransformState) ts = TransformState::make_pos(box->get_center());
 
       add_shape(BulletBoxShape::make_from_solid(box), ts);
     }

+ 24 - 14
panda/src/collide/collisionBox.I

@@ -131,23 +131,33 @@ get_center() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: CollisionBox::get_dimensions
+//     Function: CollisionBox::get_min
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE LVector3 CollisionBox::
-get_dimensions() const {
-  return _max - _min;
+INLINE const LPoint3 &CollisionBox::
+get_min() const {
+  return _min;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: CollisionBox::get_radius
+//     Function: CollisionBox::get_max
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE PN_stdfloat CollisionBox::
-get_radius() const {
-  return _radius;
+INLINE const LPoint3 &CollisionBox::
+get_max() const {
+  return _max;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CollisionBox::get_dimensions
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE LVector3 CollisionBox::
+get_dimensions() const {
+  return _max - _min;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -155,7 +165,7 @@ get_radius() const {
 //       Access: Published
 //  Description: Returns 8: the number of vertices of a rectangular solid.
 ////////////////////////////////////////////////////////////////////
-INLINE_MATHUTIL int CollisionBox::
+INLINE int CollisionBox::
 get_num_points() const {
   return 8;
 }
@@ -165,7 +175,7 @@ get_num_points() const {
 //       Access: Published
 //  Description: Returns the nth vertex of the OBB.
 ////////////////////////////////////////////////////////////////////
-INLINE_MATHUTIL LPoint3 CollisionBox::
+INLINE LPoint3 CollisionBox::
 get_point(int n) const {
   nassertr(n >= 0 && n < 8, LPoint3::zero());
   return _vertex[n];
@@ -177,7 +187,7 @@ get_point(int n) const {
 //       Access: Published
 //  Description: Returns the nth vertex of the Axis Aligned Bounding Box.
 ////////////////////////////////////////////////////////////////////
-INLINE_MATHUTIL LPoint3 CollisionBox::
+INLINE LPoint3 CollisionBox::
 get_point_aabb(int n) const {
   nassertr(n >= 0 && n < 8, LPoint3::zero());
   
@@ -192,7 +202,7 @@ get_point_aabb(int n) const {
 //       Access: Published
 //  Description: Returns 6: the number of faces of a rectangular solid.
 ////////////////////////////////////////////////////////////////////
-INLINE_MATHUTIL int CollisionBox::
+INLINE int CollisionBox::
 get_num_planes() const {
   return 6;
 }
@@ -202,7 +212,7 @@ get_num_planes() const {
 //       Access: Published
 //  Description: Returns the nth face of the rectangular solid.
 ////////////////////////////////////////////////////////////////////
-INLINE_MATHUTIL LPlane CollisionBox::
+INLINE LPlane CollisionBox::
 get_plane(int n) const {
   nassertr(n >= 0 && n < 6, LPlane());
   return _planes[n];
@@ -213,7 +223,7 @@ get_plane(int n) const {
 //       Access: Published
 //  Description: Creates the nth face of the rectangular solid.
 ////////////////////////////////////////////////////////////////////
-INLINE_MATHUTIL LPlane CollisionBox::
+INLINE LPlane CollisionBox::
 set_plane(int n) const {
   nassertr(n >= 0 && n < 6, LPlane());
   return LPlane(get_point(plane_def[n][0]),

+ 61 - 38
panda/src/collide/collisionBox.cxx

@@ -175,36 +175,6 @@ get_collision_origin() const {
   return _center;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: CollisionBox::get_min
-//       Access: Public, Virtual
-//  Description: 
-////////////////////////////////////////////////////////////////////
-LPoint3 CollisionBox::
-get_min() const {
-  return _min;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: CollisionBox::get_max
-//       Access: Public, Virtual
-//  Description: 
-////////////////////////////////////////////////////////////////////
-LPoint3 CollisionBox::
-get_max() const {
-  return _max;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: CollisionBox::get_approx_center
-//       Access: Public, Virtual
-//  Description: 
-////////////////////////////////////////////////////////////////////
-LPoint3 CollisionBox::
-get_approx_center() const {
-  return (_min + _max) * 0.5f;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionBox::get_volume_pcollector
 //       Access: Public, Virtual
@@ -442,9 +412,14 @@ test_intersection_from_sphere(const CollisionEntry &entry) const {
     into_depth = max_dist - orig_dist;
   }
 
+  // Clamp the surface point to the box bounds.
+  LPoint3 surface = from_center - normal * dist;
+  surface = surface.fmax(_min);
+  surface = surface.fmin(_max);
+
   new_entry->set_surface_normal(normal);
-  new_entry->set_surface_point(from_center - normal * dist);
-  new_entry->set_interior_point(from_center - normal * (dist + into_depth));
+  new_entry->set_surface_point(surface);
+  new_entry->set_interior_point(surface - normal * into_depth);
   new_entry->set_contact_pos(contact_point);
   new_entry->set_contact_normal(plane.get_normal());
   new_entry->set_t(actual_t);
@@ -655,56 +630,83 @@ test_intersection_from_box(const CollisionEntry &entry) const {
   box_z /= l;
 
   PN_stdfloat r1, r2;
+  PN_stdfloat min_pen = 0;
+  PN_stdfloat pen;
+  int axis = 0;
 
   // SAT test for the three axes of the into cube.
   r1 = into_extents[0];
   r2 = cabs(box_x[0] * from_extents[0]) +
        cabs(box_y[0] * from_extents[1]) +
        cabs(box_z[0] * from_extents[2]);
-  if (cabs(diff[0]) > r1 + r2) {
+  pen = r1 + r2 - cabs(diff[0]);
+  if (pen < 0) {
     return NULL;
   }
+  min_pen = pen;
 
   r1 = into_extents[1];
   r2 = cabs(box_x[1] * from_extents[0]) +
        cabs(box_y[1] * from_extents[1]) +
        cabs(box_z[1] * from_extents[2]);
-  if (cabs(diff[1]) > r1 + r2) {
+  pen = r1 + r2 - cabs(diff[1]);
+  if (pen < 0) {
     return NULL;
   }
+  if (pen < min_pen) {
+    min_pen = pen;
+    axis = 1;
+  }
 
   r1 = into_extents[2];
   r2 = cabs(box_x[2] * from_extents[0]) +
        cabs(box_y[2] * from_extents[1]) +
        cabs(box_z[2] * from_extents[2]);
-  if (cabs(diff[2]) > r1 + r2) {
+  pen = r1 + r2 - cabs(diff[2]);
+  if (pen < 0) {
     return NULL;
   }
+  if (pen < min_pen) {
+    min_pen = pen;
+    axis = 2;
+  }
 
   // SAT test for the three axes of the from cube.
   r1 = cabs(box_x[0] * into_extents[0]) +
        cabs(box_x[1] * into_extents[1]) +
        cabs(box_x[2] * into_extents[2]);
   r2 = from_extents[0];
-  if (cabs(diff.dot(box_x)) > r1 + r2) {
+  pen = r1 + r2 - cabs(diff.dot(box_x));
+  if (pen < 0) {
     return NULL;
   }
+  if (pen < min_pen) {
+    min_pen = pen;
+  }
 
   r1 = cabs(box_y[0] * into_extents[0]) +
        cabs(box_y[1] * into_extents[1]) +
        cabs(box_y[2] * into_extents[2]);
   r2 = from_extents[1];
-  if (cabs(diff.dot(box_y)) > r1 + r2) {
+  pen = r1 + r2 - cabs(diff.dot(box_y));
+  if (pen < 0) {
     return NULL;
   }
+  if (pen < min_pen) {
+    min_pen = pen;
+  }
 
   r1 = cabs(box_z[0] * into_extents[0]) +
        cabs(box_z[1] * into_extents[1]) +
        cabs(box_z[2] * into_extents[2]);
   r2 = from_extents[2];
-  if (cabs(diff.dot(box_z)) > r1 + r2) {
+  pen = r1 + r2 - cabs(diff.dot(box_z));
+  if (pen < 0) {
     return NULL;
   }
+  if (pen < min_pen) {
+    min_pen = pen;
+  }
 
   // SAT test of the nine cross products.
   r1 = into_extents[1] * cabs(box_x[2]) + into_extents[2] * cabs(box_x[1]);
@@ -768,8 +770,29 @@ test_intersection_from_box(const CollisionEntry &entry) const {
   }
   PT(CollisionEntry) new_entry = new CollisionEntry(entry);
 
+  // This isn't always the correct surface point.  However, it seems to
+  // be enough to let the pusher do the right thing.
+  LPoint3 surface(
+    min(max(diff[0], -into_extents[0]), into_extents[0]),
+    min(max(diff[1], -into_extents[1]), into_extents[1]),
+    min(max(diff[2], -into_extents[2]), into_extents[2]));
+
+  // Create the normal along the axis of least penetration.
+  LVector3 normal(0);
+  PN_stdfloat diff_axis = diff[axis];
+  int sign = (diff_axis >= 0) ? 1 : -1;
+  normal[axis] = sign;
+  surface[axis] = into_extents[axis] * sign;
+
+  new_entry->set_surface_point(surface + _center);
+
+  // Does not generate the correct depth.  Needs fixing.
+  new_entry->set_interior_point(surface + _center + normal * -min_pen);
+
   if (has_effective_normal() && box->get_respect_effective_normal()) {
     new_entry->set_surface_normal(get_effective_normal());
+  } else {
+    new_entry->set_surface_normal(normal);
   }
 
   return new_entry;

+ 14 - 11
panda/src/collide/collisionBox.h

@@ -50,26 +50,29 @@ public:
   virtual PStatCollector &get_test_pcollector();
 
   virtual void output(ostream &out) const;
-  
-  virtual LPoint3 get_approx_center() const;
-  virtual LPoint3 get_min() const;
-  virtual LPoint3 get_max() const;
 
   INLINE static void flush_level();
   void setup_box();
 
 PUBLISHED:
-  INLINE_MATHUTIL int get_num_points() const;
-  INLINE_MATHUTIL LPoint3 get_point_aabb(int n) const;
-  INLINE_MATHUTIL LPoint3 get_point(int n) const;
-  INLINE_MATHUTIL int get_num_planes() const;
-  INLINE_MATHUTIL LPlane set_plane(int n) const;
-  INLINE_MATHUTIL LPlane get_plane(int n) const;
+  INLINE int get_num_points() const;
+  INLINE LPoint3 get_point_aabb(int n) const;
+  INLINE LPoint3 get_point(int n) const;
+  INLINE int get_num_planes() const;
+  INLINE LPlane set_plane(int n) const;
+  INLINE LPlane get_plane(int n) const;
   INLINE void set_center(const LPoint3 &center);
   INLINE void set_center(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z);
   INLINE const LPoint3 &get_center() const;
+  INLINE const LPoint3 &get_min() const;
+  INLINE const LPoint3 &get_max() const;
   INLINE LVector3 get_dimensions() const;
-  INLINE PN_stdfloat get_radius() const;
+
+PUBLISHED:
+  MAKE_PROPERTY(center, get_center);
+  MAKE_PROPERTY(min, get_min);
+  MAKE_PROPERTY(max, get_max);
+  MAKE_PROPERTY(dimensions, get_dimensions);
 
 protected:
   virtual PT(BoundingVolume) compute_internal_bounds() const;

+ 11 - 0
panda/src/collide/collisionEntry.h

@@ -97,6 +97,17 @@ PUBLISHED:
   void output(ostream &out) const;
   void write(ostream &out, int indent_level = 0) const;
 
+PUBLISHED:
+  MAKE_PROPERTY(from, get_from);
+  MAKE_PROPERTY(into, get_into);
+  MAKE_PROPERTY(from_node, get_from_node);
+  MAKE_PROPERTY(into_node, get_into_node);
+  MAKE_PROPERTY(from_node_path, get_from_node_path);
+  MAKE_PROPERTY(into_node_path, get_into_node_path);
+
+  MAKE_PROPERTY(t, get_t, set_t);
+  MAKE_PROPERTY(respect_prev_transform, get_respect_prev_transform);
+
 public:
   INLINE CPT(TransformState) get_wrt_space() const;
   INLINE CPT(TransformState) get_inv_wrt_space() const;

+ 5 - 0
panda/src/collide/collisionHandlerFloor.h

@@ -42,6 +42,11 @@ PUBLISHED:
   INLINE void set_max_velocity(PN_stdfloat max_vel);
   INLINE PN_stdfloat get_max_velocity() const;
 
+PUBLISHED:
+  MAKE_PROPERTY(offset, get_offset, set_offset);
+  MAKE_PROPERTY(reach, get_reach, set_reach);
+  MAKE_PROPERTY(max_velocity, get_max_velocity, set_max_velocity);
+
 protected:
   PN_stdfloat set_highest_collision(const NodePath &target_node_path, const NodePath &from_node_path, const Entries &entries);
   virtual bool handle_entries();

+ 11 - 0
panda/src/collide/collisionHandlerGravity.h

@@ -57,6 +57,17 @@ PUBLISHED:
   INLINE void set_legacy_mode(bool legacy_mode);
   INLINE bool get_legacy_mode() const;
 
+PUBLISHED:
+  MAKE_PROPERTY(offset, get_offset, set_offset);
+  MAKE_PROPERTY(reach, get_reach, set_reach);
+  MAKE_PROPERTY(airborne_height, get_airborne_height);
+  MAKE_PROPERTY(on_ground, is_on_ground);
+  MAKE_PROPERTY(impact_velocity, get_impact_velocity);
+  MAKE_PROPERTY(contact_normal, get_contact_normal);
+  MAKE_PROPERTY(velocity, get_velocity, set_velocity);
+  MAKE_PROPERTY(gravity, get_gravity, set_gravity);
+  MAKE_PROPERTY(max_velocity, get_max_velocity, set_max_velocity);
+
 protected:
   PN_stdfloat set_highest_collision(const NodePath &target_node_path, const NodePath &from_node_path, const Entries &entries);
   virtual bool handle_entries();

+ 3 - 0
panda/src/collide/collisionHandlerPhysical.h

@@ -54,6 +54,9 @@ PUBLISHED:
   INLINE bool has_center() const;
   INLINE bool has_contact() const;
 
+PUBLISHED:
+  MAKE_PROPERTY2(center, has_center, get_center, set_center, clear_center);
+
 protected:
   bool _has_contact; // Are we in contact with anything?
 

+ 3 - 0
panda/src/collide/collisionHandlerPusher.h

@@ -34,6 +34,9 @@ PUBLISHED:
   INLINE void set_horizontal(bool flag);
   INLINE bool get_horizontal() const;
 
+PUBLISHED:
+  MAKE_PROPERTY(horizontal, get_horizontal, set_horizontal);
+
 protected:
   virtual bool handle_entries();
   virtual void apply_net_shove(

+ 5 - 0
panda/src/collide/collisionParabola.h

@@ -63,6 +63,11 @@ PUBLISHED:
   INLINE void set_t2(PN_stdfloat t2);
   INLINE PN_stdfloat get_t2() const;
 
+PUBLISHED:
+  MAKE_PROPERTY(parabola, get_parabola, set_parabola);
+  MAKE_PROPERTY(t1, get_t1, set_t1);
+  MAKE_PROPERTY(t2, get_t2, set_t2);
+
 protected:
   virtual PT(BoundingVolume) compute_internal_bounds() const;
 

+ 4 - 0
panda/src/collide/collisionPlane.h

@@ -57,6 +57,10 @@ PUBLISHED:
 
   INLINE void flip();
 
+PUBLISHED:
+  MAKE_PROPERTY(normal, get_normal);
+  MAKE_PROPERTY(plane, get_plane, set_plane);
+
 protected:
   virtual PT(BoundingVolume) compute_internal_bounds() const;
 

+ 4 - 0
panda/src/collide/collisionPolygon.h

@@ -61,6 +61,10 @@ PUBLISHED:
   bool is_valid() const;
   bool is_concave() const;
 
+PUBLISHED:
+  MAKE_PROPERTY(valid, is_valid);
+  MAKE_PROPERTY(concave, is_concave);
+
 public:
   virtual void xform(const LMatrix4 &mat);
 

+ 4 - 0
panda/src/collide/collisionSegment.h

@@ -64,6 +64,10 @@ PUBLISHED:
   bool set_from_lens(LensNode *camera, const LPoint2 &point);
   INLINE bool set_from_lens(LensNode *camera, PN_stdfloat px, PN_stdfloat py);
 
+PUBLISHED:
+  MAKE_PROPERTY(point_a, get_point_a, set_point_a);
+  MAKE_PROPERTY(point_b, get_point_b, set_point_b);
+
 protected:
   virtual PT(BoundingVolume) compute_internal_bounds() const;
 

+ 44 - 91
panda/src/collide/collisionSphere.cxx

@@ -298,100 +298,50 @@ test_intersection_from_box(const CollisionEntry &entry) const {
   const CollisionBox *box;
   DCAST_INTO_R(box, entry.get_from(), 0);
 
-  CPT(TransformState) wrt_space = entry.get_wrt_space();
-  CPT(TransformState) wrt_prev_space = entry.get_wrt_prev_space();
-
-  const LMatrix4 &wrt_mat = wrt_space->get_mat();
-
-  CollisionBox local_b( *box );
-  local_b.xform( wrt_mat );
-
-  LPoint3 from_center = local_b.get_center();
-
-  LPoint3 orig_center = get_center();
-  LPoint3 to_center = orig_center;
-  LPoint3 contact_point(from_center);
-  PN_stdfloat actual_t = 1.0f;
-
-  PN_stdfloat to_radius = get_radius();
-  PN_stdfloat to_radius_2 = to_radius * to_radius;
-
-  int ip;
-  PN_stdfloat max_dist = 0.0f;
-  PN_stdfloat dist = 0.0f; // initial assignment to squelch silly compiler warning
-  bool intersect;
-  LPlane plane;
-  LVector3 normal;
-
-  for (ip = 0, intersect=false; ip < 6 && !intersect; ip++) {
-    plane = local_b.get_plane( ip );
-    if (local_b.get_plane_points(ip).size() < 3) {
-      continue;
-    }
-    normal = (has_effective_normal() && box->get_respect_effective_normal()) ? get_effective_normal() : plane.get_normal();
-    
-    #ifndef NDEBUG
-    /*
-    if (!IS_THRESHOLD_EQUAL(normal.length_squared(), 1.0f, 0.001), NULL) {
-      collide_cat.info()
-      << "polygon being collided with " << entry.get_into_node_path()
-      << " has normal " << normal << " of length " << normal.length()
-      << "\n";
-      normal.normalize();
-    }
-    */
-    #endif
-
-    // The nearest point within the plane to our center is the
-    // intersection of the line (center, center - normal) with the plane.
+  // Instead of transforming the box into the sphere's coordinate space,
+  // we do it the other way around.  It's easier that way.
+  const LMatrix4 &wrt_mat = entry.get_inv_wrt_mat();
 
-    if (!plane.intersects_line(dist, to_center, -(plane.get_normal()))) {
-      // No intersection with plane?  This means the plane's effective
-      // normal was within the plane itself.  A useless polygon.
-      continue;
-    }
+  LPoint3 center = wrt_mat.xform_point(_center);
+  PN_stdfloat radius_sq = wrt_mat.xform_vec(LVector3(0, 0, _radius)).length_squared();
 
-    if (dist > to_radius || dist < -to_radius) {
-      // No intersection with the plane.
-      continue;
-    }
+  LPoint3 box_min = box->get_min();
+  LPoint3 box_max = box->get_max();
 
-    LPoint2 p = local_b.to_2d(to_center - dist * plane.get_normal(), ip);
-    PN_stdfloat edge_dist = 0.0f;
+  // Arvo's algorithm.
+  PN_stdfloat d = 0;
+  PN_stdfloat s;
 
-    edge_dist = local_b.dist_to_polygon(p, local_b.get_plane_points(ip));
+  if (center[0] < box_min[0]) {
+    s = center[0] - box_min[0];
+    d += s * s;
 
-    if(edge_dist < 0) {
-      intersect = true;
-      continue;
-    }
+  } else if (center[0] > box_max[0]) {
+    s = center[0] - box_max[0];
+    d += s * s;
+  }
 
-    if((edge_dist > 0) && 
-      ((edge_dist * edge_dist + dist * dist) > to_radius_2)) {
-      // No intersection; the circle is outside the polygon.
-      continue;
-    }
+  if (center[1] < box_min[1]) {
+    s = center[1] - box_min[1];
+    d += s * s;
 
-    // The sphere appears to intersect the polygon.  If the edge is less
-    // than to_radius away, the sphere may be resting on an edge of
-    // the polygon.  Determine how far the center of the sphere must
-    // remain from the plane, based on its distance from the nearest
-    // edge.
+  } else if (center[1] > box_max[1]) {
+    s = center[1] - box_max[1];
+    d += s * s;
+  }
 
-    max_dist = to_radius;
-    if (edge_dist >= 0.0f) {
-      PN_stdfloat max_dist_2 = max(to_radius_2 - edge_dist * edge_dist, (PN_stdfloat)0.0);
-      max_dist = csqrt(max_dist_2);
-    }
+  if (center[2] < box_min[2]) {
+    s = center[2] - box_min[2];
+    d += s * s;
 
-    if (dist > max_dist) {
-      // There's no intersection: the sphere is hanging off the edge.
-      continue;
-    }
-    intersect = true;
+  } else if (center[2] > box_max[2]) {
+    s = center[2] - box_max[2];
+    d += s * s;
   }
-  if( !intersect )
+
+  if (d > radius_sq) {
     return NULL;
+  }
 
   if (collide_cat.is_debug()) {
     collide_cat.debug()
@@ -401,14 +351,17 @@ test_intersection_from_box(const CollisionEntry &entry) const {
 
   PT(CollisionEntry) new_entry = new CollisionEntry(entry);
 
-  PN_stdfloat into_depth = max_dist - dist;
-
-  new_entry->set_surface_normal(normal);
-  new_entry->set_surface_point(to_center - normal * dist);
-  new_entry->set_interior_point(to_center - normal * (dist + into_depth));
-  new_entry->set_contact_pos(contact_point);
-  new_entry->set_contact_normal(plane.get_normal());
-  new_entry->set_t(actual_t);
+  // To get the interior point, clamp the sphere center to the AABB.
+  LPoint3 interior = entry.get_wrt_mat().xform_point(center.fmax(box_min).fmin(box_max));
+  new_entry->set_interior_point(interior);
+
+  // Now extrapolate the surface point and normal from that.
+  LVector3 normal = interior - _center;
+  normal.normalize();
+  new_entry->set_surface_point(_center + normal * _radius);
+  new_entry->set_surface_normal(
+    (has_effective_normal() && box->get_respect_effective_normal())
+    ? get_effective_normal() : normal);
 
   return new_entry;
 }

+ 4 - 0
panda/src/collide/collisionSphere.h

@@ -58,6 +58,10 @@ PUBLISHED:
   INLINE void set_radius(PN_stdfloat radius);
   INLINE PN_stdfloat get_radius() const;
 
+PUBLISHED:
+  MAKE_PROPERTY(center, get_center, set_center);
+  MAKE_PROPERTY(radius, get_radius, set_radius);
+
 protected:
   virtual PT(BoundingVolume) compute_internal_bounds() const;
 

+ 4 - 0
panda/src/collide/collisionTraverser.h

@@ -53,6 +53,8 @@ PUBLISHED:
 
   INLINE void set_respect_prev_transform(bool flag);
   INLINE bool get_respect_prev_transform() const;
+  MAKE_PROPERTY(respect_preV_transform, get_respect_prev_transform,
+                                        set_respect_prev_transform);
 
   void add_collider(const NodePath &collider, CollisionHandler *handler);
   bool remove_collider(const NodePath &collider);
@@ -70,6 +72,8 @@ PUBLISHED:
   INLINE bool has_recorder() const;
   INLINE CollisionRecorder *get_recorder() const;
   INLINE void clear_recorder();
+  MAKE_PROPERTY2(recorder, has_recorder, get_recorder,
+                           set_recorder, clear_recorder);
 
   CollisionVisualizer *show_collisions(const NodePath &root);
   void hide_collisions();

+ 5 - 0
panda/src/collide/collisionTube.h

@@ -65,6 +65,11 @@ PUBLISHED:
   INLINE void set_radius(PN_stdfloat radius);
   INLINE PN_stdfloat get_radius() const;
 
+PUBLISHED:
+  MAKE_PROPERTY(point_a, get_point_a, set_point_a);
+  MAKE_PROPERTY(point_b, get_point_b, set_point_b);
+  MAKE_PROPERTY(radius, get_radius, set_radius);
+
 protected:
   virtual PT(BoundingVolume) compute_internal_bounds() const;
 

+ 4 - 0
panda/src/collide/collisionVisualizer.h

@@ -47,6 +47,10 @@ PUBLISHED:
 
   void clear();
 
+PUBLISHED:
+  MAKE_PROPERTY(point_scale, get_point_scale, set_point_scale);
+  MAKE_PROPERTY(normal_scale, get_normal_scale, set_normal_scale);
+
 public:
   // from parent class PandaNode.
   virtual PandaNode *make_copy() const;

+ 6 - 2
panda/src/cull/cullBinStateSorted.I

@@ -33,9 +33,13 @@ CullBinStateSorted(const string &name, GraphicsStateGuardianBase *gsg,
 ////////////////////////////////////////////////////////////////////
 INLINE CullBinStateSorted::ObjectData::
 ObjectData(CullableObject *object) :
-  _object(object),
-  _format(object->_munged_data->get_format())
+  _object(object)
 {
+  if (object->_munged_data == NULL) {
+    _format = NULL;
+  } else {
+    _format = object->_munged_data->get_format();
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

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

@@ -1067,6 +1067,18 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
                   spc[0],spc[1],spc[2],spc[3]);
     return &t;
   }
+  case Shader::SMO_attr_material2: {
+    const MaterialAttrib *target_material = (const MaterialAttrib *)
+      _target_rs->get_attrib_def(MaterialAttrib::get_class_slot());
+    if (target_material->is_off()) {
+      t = LMatrix4(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
+      return &t;
+    }
+    Material *m = target_material->get_material();
+    t.set_row(0, m->get_base_color());
+    t.set_row(3, LVecBase4(m->get_metallic(), m->get_refractive_index(), 0, m->get_roughness()));
+    return &t;
+  }
   case Shader::SMO_attr_color: {
     const ColorAttrib *target_color = (const ColorAttrib *)
       _target_rs->get_attrib_def(ColorAttrib::get_class_slot());
@@ -1483,6 +1495,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
 const LMatrix4 *GraphicsStateGuardian::
 fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) {
   // This system is not ideal.  It will be improved in the future.
+  static const CPT_InternalName IN_color("color");
   static const CPT_InternalName IN_ambient("ambient");
   static const CPT_InternalName IN_diffuse("diffuse");
   static const CPT_InternalName IN_specular("specular");
@@ -1498,7 +1511,15 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t)
   static const CPT_InternalName IN_quadraticAttenuation("quadraticAttenuation");
   static const CPT_InternalName IN_shadowMatrix("shadowMatrix");
 
-  if (attrib == IN_ambient) {
+  if (attrib == IN_color) {
+    Light *light = np.node()->as_light();
+    nassertr(light != (Light *)NULL, &LMatrix4::ident_mat());
+    LColor c = light->get_color();
+    c.componentwise_mult(_light_color_scale);
+    t.set_row(3, c);
+    return &t;
+
+  } else if (attrib == IN_ambient) {
     Light *light = np.node()->as_light();
     nassertr(light != (Light *)NULL, &LMatrix4::ident_mat());
     if (np.node()->is_of_type(AmbientLight::get_class_type())) {

+ 92 - 0
panda/src/egg/eggMaterial.I

@@ -13,6 +13,53 @@
 ////////////////////////////////////////////////////////////////////
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggMaterial::set_base
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void EggMaterial::
+set_base(const LColor &base) {
+  _base = base;
+  _flags |= F_base;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMaterial::clear_base
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void EggMaterial::
+clear_base() {
+  _flags &= ~F_base;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMaterial::has_base
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool EggMaterial::
+has_base() const {
+  return (_flags & F_base) != 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMaterial::get_base
+//       Access: Public
+//  Description: It is legal to call this even if has_base() returns
+//               false.  If so, it simply returns the default base
+//               color.
+////////////////////////////////////////////////////////////////////
+INLINE LColor EggMaterial::
+get_base() const {
+  if (has_base()) {
+    return _base;
+  } else {
+    return LColor(1.0, 1.0, 1.0, 1.0);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggMaterial::set_diff
 //       Access: Public
@@ -336,6 +383,51 @@ get_metallic() const {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggMaterial::set_ior
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void EggMaterial::
+set_ior(double ior) {
+  _ior = ior;
+  _flags |= F_ior;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMaterial::clear_ior
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void EggMaterial::
+clear_ior() {
+  _flags &= ~F_ior;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMaterial::has_ior
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool EggMaterial::
+has_ior() const {
+  return (_flags & F_ior) != 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMaterial::get_ior
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE double EggMaterial::
+get_ior() const {
+  if (has_ior()) {
+    return _ior;
+  } else {
+    return 1.0;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggMaterial::set_local
 //       Access: Public

+ 25 - 0
panda/src/egg/eggMaterial.cxx

@@ -39,6 +39,7 @@ EggMaterial(const string &mref_name)
 EggMaterial::
 EggMaterial(const EggMaterial &copy)
   : EggNode(copy),
+    _base(copy._base),
     _diff(copy._diff),
     _amb(copy._amb),
     _emit(copy._emit),
@@ -46,6 +47,7 @@ EggMaterial(const EggMaterial &copy)
     _shininess(copy._shininess),
     _roughness(copy._roughness),
     _metallic(copy._metallic),
+    _ior(copy._ior),
     _local(copy._local),
     _flags(copy._flags)
 {
@@ -62,6 +64,19 @@ void EggMaterial::
 write(ostream &out, int indent_level) const {
   write_header(out, indent_level, "<Material>");
 
+  if (has_base()) {
+    indent(out, indent_level + 2)
+      << "<Scalar> baser { " << get_base()[0] << " }\n";
+    indent(out, indent_level + 2)
+      << "<Scalar> baseg { " << get_base()[1] << " }\n";
+    indent(out, indent_level + 2)
+      << "<Scalar> baseb { " << get_base()[2] << " }\n";
+    if (get_base()[3] != 1.0) {
+      indent(out, indent_level + 2)
+        << "<Scalar> basea { " << get_base()[3] << " }\n";
+    }
+  }
+
   if (has_diff()) {
     indent(out, indent_level + 2)
       << "<Scalar> diffr { " << get_diff()[0] << " }\n";
@@ -129,6 +144,11 @@ write(ostream &out, int indent_level) const {
       << "<Scalar> metallic { " << get_metallic() << " }\n";
   }
 
+  if (has_ior()) {
+    indent(out, indent_level + 2)
+      << "<Scalar> ior { " << get_ior() << " }\n";
+  }
+
   if (has_local()) {
     indent(out, indent_level + 2)
       << "<Scalar> local { " << get_local() << " }\n";
@@ -159,6 +179,7 @@ bool EggMaterial::
 is_equivalent_to(const EggMaterial &other, int eq) const {
   if (eq & E_attributes) {
     if (_flags != other._flags ||
+        (has_base() && get_base() != other.get_base()) ||
         (has_diff() && get_diff() != other.get_diff()) ||
         (has_amb() && get_amb() != other.get_amb()) ||
         (has_emit() && get_emit() != other.get_emit()) ||
@@ -166,6 +187,7 @@ is_equivalent_to(const EggMaterial &other, int eq) const {
         (has_shininess() && get_shininess() != other.get_shininess()) ||
         (has_roughness() && get_roughness() != other.get_roughness()) ||
         (has_metallic() && get_metallic() != other.get_metallic()) ||
+        (has_ior() && get_ior() != other.get_ior()) ||
         (has_local() && get_local() != other.get_local())) {
       return false;
     }
@@ -216,6 +238,9 @@ sorts_less_than(const EggMaterial &other, int eq) const {
     if (has_metallic() && get_metallic() != other.get_metallic()) {
       return get_metallic() < other.get_metallic();
     }
+    if (has_ior() && get_ior() != other.get_ior()) {
+      return get_ior() < other.get_ior();
+    }
     if (has_local() && get_local() != other.get_local()) {
       return get_local() < other.get_local();
     }

+ 24 - 8
panda/src/egg/eggMaterial.h

@@ -40,6 +40,11 @@ PUBLISHED:
   bool is_equivalent_to(const EggMaterial &other, int eq) const;
   bool sorts_less_than(const EggMaterial &other, int eq) const;
 
+  INLINE void set_base(const LColor &base);
+  INLINE void clear_base();
+  INLINE bool has_base() const;
+  INLINE LColor get_base() const;
+
   INLINE void set_diff(const LColor &diff);
   INLINE void clear_diff();
   INLINE bool has_diff() const;
@@ -75,12 +80,18 @@ PUBLISHED:
   INLINE bool has_metallic() const;
   INLINE double get_metallic() const;
 
+  INLINE void set_ior(double ior);
+  INLINE void clear_ior();
+  INLINE bool has_ior() const;
+  INLINE double get_ior() const;
+
   INLINE void set_local(bool local);
   INLINE void clear_local();
   INLINE bool has_local() const;
   INLINE bool get_local() const;
 
 PUBLISHED:
+  MAKE_PROPERTY2(base, has_base, get_base, set_base, clear_base);
   MAKE_PROPERTY2(diff, has_diff, get_diff, set_diff, clear_diff);
   MAKE_PROPERTY2(amb, has_amb, get_amb, set_amb, clear_amb);
   MAKE_PROPERTY2(emit, has_emit, get_emit, set_emit, clear_emit);
@@ -88,21 +99,25 @@ PUBLISHED:
   MAKE_PROPERTY2(shininess, has_shininess, get_shininess, set_shininess, clear_shininess);
   MAKE_PROPERTY2(roughness, has_roughness, get_roughness, set_roughness, clear_roughness);
   MAKE_PROPERTY2(metallic, has_metallic, get_metallic, set_metallic, clear_metallic);
+  MAKE_PROPERTY2(ior, has_ior, get_ior, set_ior, clear_ior);
 
   MAKE_PROPERTY2(local, has_local, get_local, set_local, clear_local);
 
 private:
   enum Flags {
-    F_diff      = 0x001,
-    F_amb       = 0x002,
-    F_emit      = 0x004,
-    F_spec      = 0x008,
-    F_shininess = 0x010,
-    F_roughness = 0x020,
-    F_metallic  = 0x040,
-    F_local     = 0x080
+    F_base      = 0x001,
+    F_diff      = 0x002,
+    F_amb       = 0x004,
+    F_emit      = 0x008,
+    F_spec      = 0x010,
+    F_shininess = 0x020,
+    F_roughness = 0x040,
+    F_metallic  = 0x080,
+    F_ior       = 0x100,
+    F_local     = 0x200
   };
 
+  LColor _base;
   LColor _diff;
   LColor _amb;
   LColor _emit;
@@ -110,6 +125,7 @@ private:
   double _shininess;
   double _roughness;
   double _metallic;
+  double _ior;
   bool _local;
   int _flags;
 

+ 21 - 1
panda/src/egg/parser.cxx.prebuilt

@@ -2933,7 +2933,24 @@ yyreduce:
   string name = (yyvsp[(3) - (6)]._string);
   double value = (yyvsp[(5) - (6)]._number);
 
-  if (cmp_nocase_uh(name, "diffr") == 0) {
+  if (cmp_nocase_uh(name, "baser") == 0) {
+    LColor base = material->get_base();
+    base[0] = value;
+    material->set_base(base);
+  } else if (cmp_nocase_uh(name, "baseg") == 0) {
+    LColor base = material->get_base();
+    base[1] = value;
+    material->set_base(base);
+  } else if (cmp_nocase_uh(name, "baseb") == 0) {
+    LColor base = material->get_base();
+    base[2] = value;
+    material->set_base(base);
+  } else if (cmp_nocase_uh(name, "basea") == 0) {
+    LColor base = material->get_base();
+    base[3] = value;
+    material->set_base(base);
+
+  } else if (cmp_nocase_uh(name, "diffr") == 0) {
     LColor diff = material->get_diff();
     diff[0] = value;
     material->set_diff(diff);
@@ -3010,6 +3027,9 @@ yyreduce:
   } else if (cmp_nocase_uh(name, "metallic") == 0) {
     material->set_metallic(value);
 
+  } else if (cmp_nocase_uh(name, "ior") == 0) {
+    material->set_ior(value);
+
   } else if (cmp_nocase_uh(name, "local") == 0) {
     material->set_local(value != 0.0);
 

+ 21 - 1
panda/src/egg/parser.yxx

@@ -757,7 +757,24 @@ material_body:
   string name = $3;
   double value = $<_number>5;
 
-  if (cmp_nocase_uh(name, "diffr") == 0) {
+  if (cmp_nocase_uh(name, "baser") == 0) {
+    LColor base = material->get_base();
+    base[0] = value;
+    material->set_base(base);
+  } else if (cmp_nocase_uh(name, "baseg") == 0) {
+    LColor base = material->get_base();
+    base[1] = value;
+    material->set_base(base);
+  } else if (cmp_nocase_uh(name, "baseb") == 0) {
+    LColor base = material->get_base();
+    base[2] = value;
+    material->set_base(base);
+  } else if (cmp_nocase_uh(name, "basea") == 0) {
+    LColor base = material->get_base();
+    base[3] = value;
+    material->set_base(base);
+
+  } else if (cmp_nocase_uh(name, "diffr") == 0) {
     LColor diff = material->get_diff();
     diff[0] = value;
     material->set_diff(diff);
@@ -834,6 +851,9 @@ material_body:
   } else if (cmp_nocase_uh(name, "metallic") == 0) {
     material->set_metallic(value);
 
+  } else if (cmp_nocase_uh(name, "ior") == 0) {
+    material->set_ior(value);
+
   } else if (cmp_nocase_uh(name, "local") == 0) {
     material->set_local(value != 0.0);
 

+ 6 - 0
panda/src/egg2pg/eggRenderState.cxx

@@ -495,6 +495,9 @@ get_material_attrib(const EggMaterial *egg_mat, bool bface) {
   // Ok, this is the first time we've seen this particular
   // EggMaterial.  Create a new Material that matches it.
   PT(Material) mat = new Material(egg_mat->get_name());
+  if (egg_mat->has_base()) {
+    mat->set_base_color(egg_mat->get_base());
+  }
   if (egg_mat->has_diff()) {
     mat->set_diffuse(egg_mat->get_diff());
     // By default, ambient is the same as diffuse, if diffuse is
@@ -519,6 +522,9 @@ get_material_attrib(const EggMaterial *egg_mat, bool bface) {
   if (egg_mat->has_metallic()) {
     mat->set_metallic(egg_mat->get_metallic());
   }
+  if (egg_mat->has_ior()) {
+    mat->set_refractive_index(egg_mat->get_ior());
+  }
   if (egg_mat->has_local()) {
     mat->set_local(egg_mat->get_local());
   }

+ 8 - 0
panda/src/egg2pg/eggSaver.cxx

@@ -1031,6 +1031,10 @@ EggMaterial *EggSaver::
 get_egg_material(Material *mat) {
   if (mat != (Material *)NULL) {
     EggMaterial temp(mat->get_name());
+    if (mat->has_base_color()) {
+      temp.set_base(mat->get_base_color());
+    }
+
     if (mat->has_ambient()) {
       temp.set_amb(mat->get_ambient());
     }
@@ -1057,6 +1061,10 @@ get_egg_material(Material *mat) {
       temp.set_metallic(mat->get_metallic());
     }
 
+    if (mat->has_refractive_index()) {
+      temp.set_ior(mat->get_refractive_index());
+    }
+
     temp.set_local(mat->get_local());
 
     return _materials.create_unique_material(temp, ~EggMaterial::E_mref_name);

+ 28 - 0
panda/src/express/ordered_vector.I

@@ -694,6 +694,34 @@ pop_back() {
   _vector.pop_back();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: ordered_vector::resize
+//       Access: Public
+//  Description: Resizes the vector to contain n elements.  This
+//               should not be used except to populate the vector
+//               for the first time.
+////////////////////////////////////////////////////////////////////
+template<class Key, class Compare, class Vector>
+INLINE void ordered_vector<Key, Compare, Vector>::
+resize(SIZE_TYPE n) {
+  TAU_PROFILE("ordered_vector::resize()", " ", TAU_USER);
+  _vector.resize(n);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ordered_vector::resize
+//       Access: Public
+//  Description: Resizes the vector to contain n elements.  This
+//               should not be used except to populate the vector
+//               for the first time.
+////////////////////////////////////////////////////////////////////
+template<class Key, class Compare, class Vector>
+INLINE void ordered_vector<Key, Compare, Vector>::
+resize(SIZE_TYPE n, const VALUE_TYPE &value) {
+  TAU_PROFILE("ordered_vector::resize()", " ", TAU_USER);
+  _vector.resize(n, value);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: ordered_vector::nci
 //       Access: Private

+ 2 - 0
panda/src/express/ordered_vector.h

@@ -219,6 +219,8 @@ public:
 
   INLINE void push_back(const VALUE_TYPE &key);
   INLINE void pop_back();
+  INLINE void resize(SIZE_TYPE n);
+  INLINE void resize(SIZE_TYPE n, const VALUE_TYPE &value);
 
 private:
   INLINE ITERATOR nci(CONST_ITERATOR i);

+ 5 - 5
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -6749,7 +6749,7 @@ do_issue_material() {
 
   call_glMaterialfv(face, GL_SPECULAR, material->get_specular());
   call_glMaterialfv(face, GL_EMISSION, material->get_emission());
-  glMaterialf(face, GL_SHININESS, min(material->get_shininess(), (PN_stdfloat)128.0));
+  glMaterialf(face, GL_SHININESS, max(min(material->get_shininess(), (PN_stdfloat)128), (PN_stdfloat)0));
 
   if (material->has_ambient() && material->has_diffuse()) {
     // The material has both an ambient and diffuse specified.  This
@@ -11419,7 +11419,7 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) {
     }
 
 #ifndef OPENGLES // OpenGL ES doesn't have GL_TEXTURE_MAX_LEVEL.
-    if (_supports_texture_lod) {
+    if (is_at_least_gl_version(1, 2)) {
       // By the time we get here, we have a pretty good prediction for
       // the number of mipmaps we're going to have, so tell the GL that's
       // all it's going to get.
@@ -11934,7 +11934,7 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
               << "No mipmap level " << n << " defined for " << tex->get_name()
               << "\n";
 #ifndef OPENGLES
-            if (_supports_texture_lod) {
+            if (is_at_least_gl_version(1, 2)) {
               // Tell the GL we have no more mipmaps for it to use.
               glTexParameteri(texture_target, GL_TEXTURE_MAX_LEVEL, n - mipmap_bias);
             }
@@ -12154,7 +12154,7 @@ upload_simple_texture(CLP(TextureContext) *gtc) {
 
 #ifndef OPENGLES
   // Turn off mipmaps for the simple texture.
-  if (tex->uses_mipmaps() && _supports_texture_lod) {
+  if (tex->uses_mipmaps() && is_at_least_gl_version(1, 2)) {
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
   }
 #endif
@@ -12820,7 +12820,7 @@ do_extract_texture_data(CLP(TextureContext) *gtc) {
     GLint num_expected_levels = tex->get_expected_num_mipmap_levels();
     GLint highest_level = num_expected_levels;
 #ifndef OPENGLES
-    if (_supports_texture_lod) {
+    if (is_at_least_gl_version(1, 2)) {
       glGetTexParameteriv(target, GL_TEXTURE_MAX_LEVEL, &highest_level);
       highest_level = min(highest_level, num_expected_levels);
     }

+ 61 - 1
panda/src/glstuff/glShaderContext_src.cxx

@@ -687,6 +687,15 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
   _glgsg->_glGetActiveUniform(_glsl_program, i, name_buflen, NULL, &param_size, &param_type, name_buffer);
   GLint p = _glgsg->_glGetUniformLocation(_glsl_program, name_buffer);
 
+
+  // Some NVidia drivers (361.43 for example) (incorrectly) include "internal" uniforms in 
+  // the list starting with "_main_" (for example, "_main_0_gp5fp[0]")
+  // we need to skip those, because we don't know anything about them
+  if (strncmp(name_buffer, "_main_", 6) == 0) {
+    GLCAT.warning() << "Ignoring uniform " << name_buffer << " which may be generated by buggy Nvidia driver.\n";
+    return;
+  }
+
   if (GLCAT.is_debug()) {
     GLCAT.debug()
       << "Active uniform " << name_buffer << " with size " << param_size
@@ -905,7 +914,19 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       bind._arg[1] = NULL;
       bind._dep[1] = Shader::SSD_NONE;
 
-      if (noprefix == "Material.ambient") {
+      if (noprefix == "Material.baseColor") {
+        if (param_type != GL_FLOAT_VEC4) {
+          GLCAT.error()
+            << "p3d_Material.baseColor should be vec4\n";
+        }
+        bind._part[0] = Shader::SMO_attr_material2;
+        bind._piece = Shader::SMP_row0;
+        bind._dep[0] |= Shader::SSD_color;
+        _shader->_mat_spec.push_back(bind);
+        _shader->_mat_deps |= bind._dep[0];
+        return;
+
+      } else if (noprefix == "Material.ambient") {
         if (param_type != GL_FLOAT_VEC4) {
           GLCAT.error()
             << "p3d_Material.ambient should be vec4\n";
@@ -954,6 +975,39 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         _shader->_mat_spec.push_back(bind);
         _shader->_mat_deps |= bind._dep[0];
         return;
+
+      } else if (noprefix == "Material.roughness") {
+        if (param_type != GL_FLOAT) {
+          GLCAT.error()
+            << "p3d_Material.roughness should be float\n";
+        }
+        bind._part[0] = Shader::SMO_attr_material2;
+        bind._piece = Shader::SMP_cell15;
+        _shader->_mat_spec.push_back(bind);
+        _shader->_mat_deps |= bind._dep[0];
+        return;
+
+      } else if (noprefix == "Material.metallic") {
+        if (param_type != GL_FLOAT && param_type != GL_BOOL) {
+          GLCAT.error()
+            << "p3d_Material.metallic should be bool or float\n";
+        }
+        bind._part[0] = Shader::SMO_attr_material2;
+        bind._piece = Shader::SMP_row3x1;
+        _shader->_mat_spec.push_back(bind);
+        _shader->_mat_deps |= bind._dep[0];
+        return;
+
+      } else if (noprefix == "Material.refractiveIndex") {
+        if (param_type != GL_FLOAT) {
+          GLCAT.error()
+            << "p3d_Material.refractiveIndex should be float\n";
+        }
+        bind._part[0] = Shader::SMO_attr_material2;
+        bind._piece = Shader::SMP_cell13;
+        _shader->_mat_spec.push_back(bind);
+        _shader->_mat_deps |= bind._dep[0];
+        return;
       }
     }
     if (noprefix == "ColorScale") {
@@ -1982,6 +2036,12 @@ issue_parameters(int altered) {
       case Shader::SMP_cell15:
         _glgsg->_glUniform1fv(p, 1, data+15);
         continue;
+      case Shader::SMP_cell14:
+        _glgsg->_glUniform1fv(p, 1, data+14);
+        continue;
+      case Shader::SMP_cell13:
+        _glgsg->_glUniform1fv(p, 1, data+13);
+        continue;
       }
     }
   }

+ 54 - 31
panda/src/gobj/material.I

@@ -20,6 +20,7 @@
 ////////////////////////////////////////////////////////////////////
 INLINE Material::
 Material(const string &name) : Namable(name) {
+  _base_color.set(1.0f, 1.0f, 1.0f, 1.0f);
   _ambient.set(1.0f, 1.0f, 1.0f, 1.0f);
   _diffuse.set(1.0f, 1.0f, 1.0f, 1.0f);
   _specular.set(0.0f, 0.0f, 0.0f, 1.0f);
@@ -27,6 +28,7 @@ Material(const string &name) : Namable(name) {
   _shininess = 0;
   _roughness = 1;
   _metallic = 0;
+  _refractive_index = 1;
   _flags = 0;
 }
 
@@ -62,6 +64,33 @@ get_default() {
   return _default;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Material::has_base_color
+//       Access: Published
+//  Description: Returns true if the base color has been explicitly
+//               set for this material, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool Material::
+has_base_color() const {
+  return (_flags & F_base_color) != 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Material::get_base_color
+//       Access: Published
+//  Description: Returns the base_color color setting, if it has been
+//               set.  If neither the base color nor the metallic
+//               have been set, this returns the diffuse color.
+////////////////////////////////////////////////////////////////////
+INLINE const LColor &Material::
+get_base_color() const {
+  if (!has_base_color() && !has_metallic()) {
+    return _diffuse;
+  } else {
+    return _base_color;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Material::has_ambient
 //       Access: Published
@@ -96,7 +125,7 @@ clear_ambient() {
     nassertv(!is_attrib_locked());
   }
   _flags &= ~F_ambient;
-  _ambient.set(0.0f, 0.0f, 0.0f, 0.0f);
+  _ambient = _base_color;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -133,7 +162,7 @@ clear_diffuse() {
     nassertv(!is_attrib_locked());
   }
   _flags &= ~F_diffuse;
-  _diffuse.set(1.0f, 1.0f, 1.0f, 1.0f);
+  _diffuse = _base_color * (1 - _metallic);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -159,20 +188,6 @@ get_specular() const {
   return _specular;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: Material::clear_specular
-//       Access: Published
-//  Description: Removes the explicit specular color from the material.
-////////////////////////////////////////////////////////////////////
-INLINE void Material::
-clear_specular() {
-  if (enforce_attrib_lock) {
-    nassertv(!is_attrib_locked());
-  }
-  _flags &= ~F_specular;
-  _specular.set(0.0f, 0.0f, 0.0f, 0.0f);
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: Material::has_emission
 //       Access: Published
@@ -220,6 +235,17 @@ get_shininess() const {
   return _shininess;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Material::has_roughness
+//       Access: Published
+//  Description: Returns true if the roughness has been explicitly
+//               set for this material, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool Material::
+has_roughness() const {
+  return (_flags & F_roughness) != 0;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Material::has_metallic
 //       Access: Published
@@ -243,28 +269,25 @@ get_metallic() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: Material::clear_metallic
+//     Function: Material::has_refractive_index
 //       Access: Published
-//  Description: Removes the explicit metallic setting from the material.
+//  Description: Returns true if a refractive index has explicitly
+//               been specified for this material.
 ////////////////////////////////////////////////////////////////////
-INLINE void Material::
-clear_metallic() {
-  if (enforce_attrib_lock) {
-    nassertv(!is_attrib_locked());
-  }
-  _flags &= ~F_metallic;
-  _metallic = 0;
+INLINE bool Material::
+has_refractive_index() const {
+  return (_flags & F_refractive_index) != 0;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: Material::has_roughness
+//     Function: Material::get_refractive_index
 //       Access: Published
-//  Description: Returns true if the roughness has been explicitly
-//               set for this material, false otherwise.
+//  Description: Returns the index of refraction, or 1 if none has
+//               been set for this material.
 ////////////////////////////////////////////////////////////////////
-INLINE bool Material::
-has_roughness() const {
-  return (_flags & F_roughness) != 0;
+INLINE PN_stdfloat Material::
+get_refractive_index() const {
+  return _refractive_index;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 252 - 33
panda/src/gobj/material.cxx

@@ -31,6 +31,7 @@ PT(Material) Material::_default;
 void Material::
 operator = (const Material &copy) {
   Namable::operator = (copy);
+  _base_color = copy._base_color;
   _ambient = copy._ambient;
   _diffuse = copy._diffuse;
   _specular = copy._specular;
@@ -38,9 +39,80 @@ operator = (const Material &copy) {
   _shininess = copy._shininess;
   _roughness = copy._roughness;
   _metallic = copy._metallic;
+  _refractive_index = copy._refractive_index;
   _flags = copy._flags & (~F_attrib_lock);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Material::set_base_color
+//       Access: Published
+//  Description: Specifies the base color of the material.  In
+//               conjunction with set_metallic, this is an alternate
+//               way to specify the color of a material.  For
+//               dielectrics, this will determine the value of the
+//               diffuse color, and for metals, this will determine
+//               the value of the specular color.
+//
+//               Setting this will clear an explicit specular,
+//               diffuse or ambient color assignment.
+//
+//               If this is not set, the object color will be used.
+////////////////////////////////////////////////////////////////////
+void Material::
+set_base_color(const LColor &color) {
+  if (enforce_attrib_lock) {
+    if ((_flags & F_base_color) == 0) {
+      nassertv(!is_attrib_locked());
+    }
+  }
+  _base_color = color;
+  _flags |= F_base_color | F_metallic;
+  _flags &= ~(F_ambient | F_diffuse | F_specular);
+
+  // Recalculate the diffuse and specular colors.
+  _ambient = _base_color;
+  _diffuse = _base_color * (1 - _metallic);
+
+  PN_stdfloat f0 = 0;
+  if (_refractive_index >= 1) {
+    f0 = (_refractive_index - 1) / (_refractive_index + 1);
+    f0 *= f0;
+    f0 *= (1 - _metallic);
+  }
+  _specular.set(f0, f0, f0, 0);
+  _specular += _base_color * _metallic;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Material::clear_base_color
+//       Access: Published
+//  Description: Removes the explicit base_color color from the material.
+////////////////////////////////////////////////////////////////////
+void Material::
+clear_base_color() {
+  if (enforce_attrib_lock) {
+    nassertv(!is_attrib_locked());
+  }
+  _flags &= ~F_base_color;
+  _base_color.set(0.0f, 0.0f, 0.0f, 0.0f);
+
+  if ((_flags & F_ambient) == 0) {
+    _ambient.set(0, 0, 0, 0);
+  }
+  if ((_flags & F_diffuse) == 0) {
+    _diffuse.set(0, 0, 0, 0);
+  }
+  if ((_flags & F_specular) == 0) {
+    // Recalculate the specular color.
+    PN_stdfloat f0 = 0;
+    if (_refractive_index >= 1) {
+      f0 = (_refractive_index - 1) / (_refractive_index + 1);
+      f0 *= f0;
+    }
+    _specular.set(f0, f0, f0, 0);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Material::set_ambient
 //       Access: Published
@@ -92,7 +164,7 @@ set_diffuse(const LColor &color) {
 ////////////////////////////////////////////////////////////////////
 //     Function: Material::set_specular
 //       Access: Published
-//  Description: Specifies the diffuse color setting of the material.
+//  Description: Specifies the specular color setting of the material.
 //               This will be multiplied by any lights in effect on
 //               the material to compute the color of specular
 //               highlights on the object.
@@ -100,7 +172,9 @@ set_diffuse(const LColor &color) {
 //               This is the highlight color of an object: the color
 //               of small highlight reflections.
 //
-//               If this is not set, highlights will not appear.
+//               If this is not set, the specular color is taken from
+//               the index of refraction, which is 1 by default
+//               (meaning no specular reflections are generated).
 ////////////////////////////////////////////////////////////////////
 void Material::
 set_specular(const LColor &color) {
@@ -113,6 +187,29 @@ set_specular(const LColor &color) {
   _flags |= F_specular;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Material::clear_specular
+//       Access: Published
+//  Description: Removes the explicit specular color from the material.
+////////////////////////////////////////////////////////////////////
+void Material::
+clear_specular() {
+  if (enforce_attrib_lock) {
+    nassertv(!is_attrib_locked());
+  }
+  _flags &= ~F_specular;
+
+  // Recalculate the specular color from the refractive index.
+  PN_stdfloat f0 = 0;
+  if (_refractive_index >= 1) {
+    f0 = (_refractive_index - 1) / (_refractive_index + 1);
+    f0 *= f0;
+    f0 *= (1 - _metallic);
+  }
+  _specular.set(f0, f0, f0, 0);
+  _specular += _base_color * _metallic;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Material::set_emission
 //       Access: Published
@@ -211,8 +308,10 @@ set_roughness(PN_stdfloat roughness) {
 //  Description: Sets the metallic setting of the material, which is
 //               is used for physically-based rendering models.
 //               This is usually 0 for dielectric materials and 1
-//               for metals.  It usually does not make sense to set
-//               this to a value other than 0 or 1.
+//               for metals.  It really does not make sense to set
+//               this to a value other than 0 or 1, but it is
+//               nonetheless a float for compatibility with tools
+//               that allow setting this to values other than 0 or 1.
 ////////////////////////////////////////////////////////////////////
 void Material::
 set_metallic(PN_stdfloat metallic) {
@@ -223,6 +322,80 @@ set_metallic(PN_stdfloat metallic) {
   }
   _metallic = metallic;
   _flags |= F_metallic;
+
+  // Recalculate the diffuse and specular.
+  if ((_flags & F_diffuse) == 0) {
+    _diffuse = _base_color * (1 - _metallic);
+  }
+  if ((_flags & F_specular) == 0) {
+    // Recalculate the specular color.
+    PN_stdfloat f0 = 0;
+    if (_refractive_index >= 1) {
+      f0 = (_refractive_index - 1) / (_refractive_index + 1);
+      f0 *= f0;
+      f0 *= (1 - _metallic);
+    }
+    _specular.set(f0, f0, f0, 0);
+    _specular += _base_color * _metallic;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Material::clear_metallic
+//       Access: Published
+//  Description: Removes the explicit metallic setting from the material.
+////////////////////////////////////////////////////////////////////
+void Material::
+clear_metallic() {
+  if (enforce_attrib_lock) {
+    nassertv(!is_attrib_locked());
+  }
+  _flags &= ~F_metallic;
+  _metallic = 0;
+
+  // If we had a base color, recalculate the diffuse and specular.
+  if (_flags & F_base_color) {
+    if ((_flags & F_diffuse) == 0) {
+      _diffuse = _base_color;
+    }
+    if ((_flags & F_specular) == 0) {
+      // Recalculate the specular color.
+      PN_stdfloat f0 = 0;
+      if (_refractive_index >= 1) {
+        f0 = (_refractive_index - 1) / (_refractive_index + 1);
+        f0 *= f0;
+      }
+      _specular.set(f0, f0, f0, 0);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Material::set_refractive_index
+//       Access: Published
+//  Description: Sets the index of refraction of the material, which
+//               is used to determine the specular color in absence
+//               of an explicit specular color assignment.
+//               This is usually 1.5 for dielectric materials.  It
+//               is not very useful for metals, since they cannot
+//               be described as easily with a single number.
+//
+//               Should be 1 or higher.  The default is 1.
+////////////////////////////////////////////////////////////////////
+void Material::
+set_refractive_index(PN_stdfloat refractive_index) {
+  _refractive_index = refractive_index;
+  _flags |= F_refractive_index;
+
+  if ((_flags & F_specular) == 0) {
+    // Recalculate the specular color.
+    PN_stdfloat f0 = 0;
+    if (_refractive_index >= 1) {
+      f0 = (_refractive_index - 1) / (_refractive_index + 1);
+      f0 *= f0;
+    }
+    _specular.set(f0, f0, f0, 0);
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -239,6 +412,9 @@ compare_to(const Material &other) const {
   if (_flags != other._flags) {
     return _flags - other._flags;
   }
+  if (has_base_color() && get_base_color() != other.get_base_color()) {
+    return get_base_color().compare_to(other.get_base_color());
+  }
   if (has_ambient() && get_ambient() != other.get_ambient()) {
     return get_ambient().compare_to(other.get_ambient());
   }
@@ -254,6 +430,12 @@ compare_to(const Material &other) const {
   if (get_shininess() != other.get_shininess()) {
     return get_shininess() < other.get_shininess() ? -1 : 1;
   }
+  if (get_metallic() != other.get_metallic()) {
+    return get_metallic() < other.get_metallic() ? -1 : 1;
+  }
+  if (get_refractive_index() != other.get_refractive_index()) {
+    return get_refractive_index() < other.get_refractive_index() ? -1 : 1;
+  }
 
   return strcmp(get_name().c_str(), other.get_name().c_str());
 }
@@ -266,14 +448,21 @@ compare_to(const Material &other) const {
 void Material::
 output(ostream &out) const {
   out << "Material " << get_name();
-  if (has_ambient()) {
-    out << " a(" << get_ambient() << ")";
-  }
-  if (has_diffuse()) {
-    out << " d(" << get_diffuse() << ")";
+  if (has_base_color()) {
+    out << " c(" << get_base_color() << ")";
+  } else {
+    if (has_ambient()) {
+      out << " a(" << get_ambient() << ")";
+    }
+    if (has_diffuse()) {
+      out << " d(" << get_diffuse() << ")";
+    }
+    if (has_specular()) {
+      out << " s(" << get_specular() << ")";
+    }
   }
-  if (has_specular()) {
-    out << " s(" << get_specular() << ")";
+  if (has_refractive_index()) {
+    out << " ior" << get_refractive_index();
   }
   if (has_emission()) {
     out << " e(" << get_emission() << ")";
@@ -283,7 +472,7 @@ output(ostream &out) const {
   } else {
     out << " s" << get_shininess();
   }
-  if (has_metallic()) {
+  if (_flags & F_metallic) {
     out << " m" << _metallic;
   }
   out << " l" << get_local()
@@ -298,6 +487,9 @@ output(ostream &out) const {
 void Material::
 write(ostream &out, int indent_level) const {
   indent(out, indent_level) << "Material " << get_name() << "\n";
+  if (has_base_color()) {
+    indent(out, indent_level + 2) << "base_color = " << get_ambient() << "\n";
+  }
   if (has_ambient()) {
     indent(out, indent_level + 2) << "ambient = " << get_ambient() << "\n";
   }
@@ -306,6 +498,8 @@ write(ostream &out, int indent_level) const {
   }
   if (has_specular()) {
     indent(out, indent_level + 2) << "specular = " << get_specular() << "\n";
+  } else {
+    indent(out, indent_level + 2) << "refractive_index = " << get_refractive_index() << "\n";
   }
   if (has_emission()) {
     indent(out, indent_level + 2) << "emission = " << get_emission() << "\n";
@@ -343,11 +537,19 @@ register_with_read_factory() {
 void Material::
 write_datagram(BamWriter *manager, Datagram &me) {
   me.add_string(get_name());
-  _ambient.write_datagram(me);
-  _diffuse.write_datagram(me);
-  _specular.write_datagram(me);
+
+  me.add_int32(_flags);
+
+  if (_flags & F_metallic) {
+    // Metalness workflow.
+    _base_color.write_datagram(me);
+    me.add_stdfloat(_metallic);
+  } else {
+    _ambient.write_datagram(me);
+    _diffuse.write_datagram(me);
+    _specular.write_datagram(me);
+  }
   _emission.write_datagram(me);
-  me.add_stdfloat(_shininess);
 
   if (_flags & F_roughness) {
     me.add_stdfloat(_roughness);
@@ -355,11 +557,7 @@ write_datagram(BamWriter *manager, Datagram &me) {
     me.add_stdfloat(_shininess);
   }
 
-  me.add_int32(_flags);
-
-  if (_flags & F_metallic) {
-    me.add_stdfloat(_metallic);
-  }
+  me.add_stdfloat(_refractive_index);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -389,19 +587,40 @@ make_Material(const FactoryParams &params) {
 void Material::
 fillin(DatagramIterator &scan, BamReader *manager) {
   set_name(scan.get_string());
-  _ambient.read_datagram(scan);
-  _diffuse.read_datagram(scan);
-  _specular.read_datagram(scan);
-  _emission.read_datagram(scan);
-  _shininess = scan.get_stdfloat();
-  _flags = scan.get_int32();
 
-  if (_flags & F_roughness) {
-    // The shininess we read is actually a roughness value.
-    set_roughness(_shininess);
-  }
+  if (manager->get_file_minor_ver() >= 39) {
+    _flags = scan.get_int32();
 
-  if (_flags & F_metallic) {
-    _metallic = scan.get_stdfloat();
+    if (_flags & F_metallic) {
+      // Metalness workflow: read base color and metallic
+      _base_color.read_datagram(scan);
+      set_metallic(scan.get_stdfloat());
+
+    } else {
+      _ambient.read_datagram(scan);
+      _diffuse.read_datagram(scan);
+      _specular.read_datagram(scan);
+    }
+    _emission.read_datagram(scan);
+
+    if (_flags & F_roughness) {
+      set_roughness(scan.get_stdfloat());
+    } else {
+      _shininess = scan.get_stdfloat();
+    }
+    _refractive_index = scan.get_stdfloat();
+
+  } else {
+    _ambient.read_datagram(scan);
+    _diffuse.read_datagram(scan);
+    _specular.read_datagram(scan);
+    _emission.read_datagram(scan);
+    _shininess = scan.get_stdfloat();
+    _flags = scan.get_int32();
+
+    if (_flags & F_roughness) {
+      // The shininess we read is actually a roughness value.
+      set_roughness(_shininess);
+    }
   }
 }

+ 31 - 2
panda/src/gobj/material.h

@@ -30,6 +30,18 @@ class FactoryParams;
 // Description : Defines the way an object appears in the presence of
 //               lighting.  A material is only necessary if lighting
 //               is to be enabled; otherwise, the material isn't used.
+//
+//               There are two workflows that are supported: the
+//               "classic" workflow of providing separate ambient,
+//               diffuse and specular colors, and the "metalness"
+//               workflow, in which a base color is specified along
+//               with a "metallic" value that indicates whether the
+//               material is a metal or a dielectric.
+//
+//               The size of the specular highlight can be specified
+//               by either specifying the specular exponent (shininess)
+//               or by specifying a roughness value that in perceptually
+//               linear in the range of 0-1.
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_GOBJ Material : public TypedWritableReferenceCount, public Namable {
 PUBLISHED:
@@ -40,6 +52,11 @@ PUBLISHED:
 
   INLINE static Material *get_default();
 
+  INLINE bool has_base_color() const;
+  INLINE const LColor &get_base_color() const;
+  void set_base_color(const LColor &color);
+  void clear_base_color();
+
   INLINE bool has_ambient() const;
   INLINE const LColor &get_ambient() const;
   void set_ambient(const LColor &color);
@@ -53,7 +70,7 @@ PUBLISHED:
   INLINE bool has_specular() const;
   INLINE const LColor &get_specular() const;
   void set_specular(const LColor &color);
-  INLINE void clear_specular();
+  void clear_specular();
 
   INLINE bool has_emission() const;
   INLINE const LColor &get_emission() const;
@@ -70,7 +87,11 @@ PUBLISHED:
   INLINE bool has_metallic() const;
   INLINE PN_stdfloat get_metallic() const;
   void set_metallic(PN_stdfloat metallic);
-  INLINE void clear_metallic();
+  void clear_metallic();
+
+  INLINE bool has_refractive_index() const;
+  INLINE PN_stdfloat get_refractive_index() const;
+  void set_refractive_index(PN_stdfloat refractive_index);
 
   INLINE bool get_local() const;
   INLINE void set_local(bool local);
@@ -90,6 +111,8 @@ PUBLISHED:
   INLINE void set_attrib_lock();
 
 PUBLISHED:
+  MAKE_PROPERTY2(base_color, has_base_color, get_base_color,
+                             set_base_color, clear_base_color);
   MAKE_PROPERTY2(ambient, has_ambient, get_ambient,
                           set_ambient, clear_ambient);
   MAKE_PROPERTY2(diffuse, has_diffuse, get_diffuse,
@@ -102,11 +125,14 @@ PUBLISHED:
   MAKE_PROPERTY(shininess, get_shininess, set_shininess);
   MAKE_PROPERTY(roughness, get_roughness, set_roughness);
   MAKE_PROPERTY(metallic, get_metallic, set_metallic);
+  MAKE_PROPERTY(refractive_index, get_refractive_index,
+                                  set_refractive_index);
 
   MAKE_PROPERTY(local, get_local, set_local);
   MAKE_PROPERTY(twoside, get_twoside, set_twoside);
 
 private:
+  LColor _base_color;
   LColor _ambient;
   LColor _diffuse;
   LColor _specular;
@@ -114,6 +140,7 @@ private:
   PN_stdfloat _shininess;
   PN_stdfloat _roughness;
   PN_stdfloat _metallic;
+  PN_stdfloat _refractive_index;
 
   static PT(Material) _default;
 
@@ -127,6 +154,8 @@ private:
     F_attrib_lock = 0x040,
     F_roughness   = 0x080,
     F_metallic    = 0x100,
+    F_base_color  = 0x200,
+    F_refractive_index = 0x400,
   };
   int _flags;
 

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

@@ -405,7 +405,7 @@ cp_dependency(ShaderMatInput inp) {
   if (inp == SMO_INVALID) {
     return SSD_NONE;
   }
-  if (inp == SMO_attr_material) {
+  if (inp == SMO_attr_material || inp == SMO_attr_material2) {
     dep |= SSD_material;
   }
   if (inp == SMO_attr_color) {

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

@@ -194,6 +194,9 @@ public:
 
     SMO_inv_texmat_i,
 
+    // Additional properties for PBR materials
+    SMO_attr_material2,
+
     SMO_INVALID
   };
 
@@ -272,6 +275,8 @@ public:
     SMP_upper3x3,
     SMP_transpose3x3,
     SMP_cell15,
+    SMP_cell14,
+    SMP_cell13,
   };
 
   enum ShaderStateDep {

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

@@ -489,7 +489,7 @@ read(const Filename &fullpath, const Filename &alpha_fullpath,
 size_t Texture::
 estimate_texture_memory() const {
   CDReader cdata(_cycler);
-  size_t pixels = cdata->_x_size * cdata->_y_size;
+  size_t pixels = cdata->_x_size * cdata->_y_size * cdata->_z_size;
 
   size_t bpp = 4;
   switch (cdata->_format) {
@@ -503,6 +503,7 @@ estimate_texture_memory() const {
   case Texture::F_blue:
   case Texture::F_luminance:
   case Texture::F_sluminance:
+  case Texture::F_r8i:
     bpp = 1;
     break;
 
@@ -519,6 +520,8 @@ estimate_texture_memory() const {
   case Texture::F_rgb5:
   case Texture::F_rgba5:
   case Texture::F_srgb:
+    // Most of the above formats have only 3 bytes, but they are most likely to
+    // get padded by the driver
     bpp = 4;
     break;
 
@@ -536,9 +539,15 @@ estimate_texture_memory() const {
     break;
 
   case Texture::F_depth_component:
+  case Texture::F_depth_component16:
     bpp = 2;
     break;
 
+  case Texture::F_depth_component24: // Gets padded
+  case Texture::F_depth_component32:
+    bpp = 4;
+    break;
+
   case Texture::F_rgba12:
   case Texture::F_rgb12:
     bpp = 8;
@@ -552,7 +561,6 @@ estimate_texture_memory() const {
     break;
 
   case Texture::F_r16:
-  case Texture::F_r8i:
   case Texture::F_rg8i:
     bpp = 2;
     break;
@@ -564,17 +572,16 @@ estimate_texture_memory() const {
     break;
 
   case Texture::F_r32i:
-    bpp = 4;
-    break;
-
   case Texture::F_r32:
     bpp = 4;
     break;
+
   case Texture::F_rg32:
     bpp = 8;
     break;
+
   case Texture::F_rgb32:
-    bpp = 12;
+    bpp = 16;
     break;
 
   case Texture::F_r11_g11_b10:
@@ -582,6 +589,8 @@ estimate_texture_memory() const {
     break;
 
   default:
+    gobj_cat.warning() << "Unhandled format in estimate_texture_memory(): "
+                       << cdata->_format << "\n";
     break;
   }
 

+ 6 - 6
panda/src/gobj/texturePool.cxx

@@ -341,7 +341,7 @@ ns_load_texture(const Filename &orig_filename, int primary_file_num_channels,
 
   if (store_record && tex->is_cacheable()) {
     // Store the on-disk cache record for next time.
-    record->set_data(tex, tex);
+    record->set_data(tex);
     cache->store(record);
   }
 
@@ -473,7 +473,7 @@ ns_load_texture(const Filename &orig_filename,
 
   if (store_record && tex->is_cacheable()) {
     // Store the on-disk cache record for next time.
-    record->set_data(tex, tex);
+    record->set_data(tex);
     cache->store(record);
   }
 
@@ -585,7 +585,7 @@ ns_load_3d_texture(const Filename &filename_pattern,
 
   if (store_record && tex->is_cacheable()) {
     // Store the on-disk cache record for next time.
-    record->set_data(tex, tex);
+    record->set_data(tex);
     cache->store(record);
   }
 
@@ -691,7 +691,7 @@ ns_load_2d_texture_array(const Filename &filename_pattern,
 
   if (store_record && tex->is_cacheable()) {
     // Store the on-disk cache record for next time.
-    record->set_data(tex, tex);
+    record->set_data(tex);
     cache->store(record);
   }
 
@@ -790,7 +790,7 @@ ns_load_cube_map(const Filename &filename_pattern, bool read_mipmaps,
 
   if (store_record && tex->is_cacheable()) {
     // Store the on-disk cache record for next time.
-    record->set_data(tex, tex);
+    record->set_data(tex);
     cache->store(record);
   }
 
@@ -1166,7 +1166,7 @@ try_load_cache(PT(Texture) &tex, BamCache *cache, const Filename &filename,
                   // from the cache.  To keep the cache current,
                   // rewrite it to the cache now, in its newly
                   // compressed form.
-                  record->set_data(tex, tex);
+                  record->set_data(tex);
                   cache->store(record);
                   compressed_cache_record = true;
                 }

+ 20 - 36
panda/src/linmath/lpoint2_src.I

@@ -14,49 +14,21 @@
 
 
 ////////////////////////////////////////////////////////////////////
-//     Function: LPoint2::Default Constructor
+//     Function: LPoint2::Constructor
 //       Access: Public
-//  Description:
+//  Description: Constructs a new LPoint2 from a LVecBase2
 ////////////////////////////////////////////////////////////////////
 INLINE_LINMATH FLOATNAME(LPoint2)::
-FLOATNAME(LPoint2)() {
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: LPoint2::Copy Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LPoint2)::
-FLOATNAME(LPoint2)(const FLOATNAME(LVecBase2) &copy) : FLOATNAME(LVecBase2)(copy) {
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: LPoint2::Copy Assignment Operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LPoint2) &FLOATNAME(LPoint2)::
-operator = (const FLOATNAME(LVecBase2) &copy) {
-  FLOATNAME(LVecBase2)::operator = (copy);
-  return *this;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: LPoint2::Copy Fill Operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LPoint2) &FLOATNAME(LPoint2)::
-operator = (FLOATTYPE fill_value) {
-  FLOATNAME(LVecBase2)::operator = (fill_value);
-  return *this;
+FLOATNAME(LPoint2)(const FLOATNAME(LVecBase2)& copy) :
+  FLOATNAME(LVecBase2)(copy)
+{
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: LPoint2::Constructor
 //       Access: Public
-//  Description:
+//  Description: Constructs a new LPoint2 all components set to the
+//               fill value.
 ////////////////////////////////////////////////////////////////////
 INLINE_LINMATH FLOATNAME(LPoint2)::
 FLOATNAME(LPoint2)(FLOATTYPE fill_value) :
@@ -67,7 +39,7 @@ FLOATNAME(LPoint2)(FLOATTYPE fill_value) :
 ////////////////////////////////////////////////////////////////////
 //     Function: LPoint2::Constructor
 //       Access: Public
-//  Description:
+//  Description: Constructs a new LPoint2 with the given components
 ////////////////////////////////////////////////////////////////////
 INLINE_LINMATH FLOATNAME(LPoint2)::
 FLOATNAME(LPoint2)(FLOATTYPE x, FLOATTYPE y) :
@@ -186,6 +158,18 @@ operator / (FLOATTYPE scalar) const {
 }
 
 #ifndef FLOATTYPE_IS_INT
+////////////////////////////////////////////////////////////////////
+//     Function: LPoint2::normalized
+//       Access: Published
+//  Description: Normalizes the vector and returns the normalized
+//               vector as a copy. If the vector was a zero-length
+//               vector, a zero length vector will be returned.
+////////////////////////////////////////////////////////////////////
+INLINE_LINMATH FLOATNAME(LPoint2) FLOATNAME(LPoint2)::
+normalized() const {
+  return FLOATNAME(LVecBase2)::normalized();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: LPoint2::project
 //       Access: Published

+ 4 - 4
panda/src/linmath/lpoint2_src.h

@@ -19,10 +19,9 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_LINMATH FLOATNAME(LPoint2) : public FLOATNAME(LVecBase2) {
 PUBLISHED:
-  INLINE_LINMATH FLOATNAME(LPoint2)();
-  INLINE_LINMATH FLOATNAME(LPoint2)(const FLOATNAME(LVecBase2) &copy);
-  INLINE_LINMATH FLOATNAME(LPoint2) &operator = (const FLOATNAME(LVecBase2) &copy);
-  INLINE_LINMATH FLOATNAME(LPoint2) &operator = (FLOATTYPE fill_value);
+
+  INLINE_LINMATH FLOATNAME(LPoint2)() DEFAULT_CTOR;
+  INLINE_LINMATH FLOATNAME(LPoint2)(const FLOATNAME(LVecBase2)& copy);
   INLINE_LINMATH FLOATNAME(LPoint2)(FLOATTYPE fill_value);
   INLINE_LINMATH FLOATNAME(LPoint2)(FLOATTYPE x, FLOATTYPE y);
 
@@ -51,6 +50,7 @@ PUBLISHED:
   INLINE_LINMATH FLOATNAME(LPoint2) operator / (FLOATTYPE scalar) const;
 
 #ifndef FLOATTYPE_IS_INT
+  INLINE_LINMATH FLOATNAME(LPoint2) normalized() const;
   INLINE_LINMATH FLOATNAME(LPoint2) project(const FLOATNAME(LVecBase2) &onto) const;
 #endif
 

+ 12 - 31
panda/src/linmath/lpoint3_src.I

@@ -13,15 +13,6 @@
 ////////////////////////////////////////////////////////////////////
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: LPoint3::Default Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LPoint3)::
-FLOATNAME(LPoint3)() {
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: LPoint3::Copy Constructor
 //       Access: Public
@@ -31,28 +22,6 @@ INLINE_LINMATH FLOATNAME(LPoint3)::
 FLOATNAME(LPoint3)(const FLOATNAME(LVecBase3) &copy) : FLOATNAME(LVecBase3)(copy) {
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: LPoint3::Copy Assignment Operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LPoint3) &FLOATNAME(LPoint3)::
-operator = (const FLOATNAME(LVecBase3) &copy) {
-  FLOATNAME(LVecBase3)::operator = (copy);
-  return *this;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: LPoint3::Copy Fill Operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LPoint3) &FLOATNAME(LPoint3)::
-operator = (FLOATTYPE fill_value) {
-  FLOATNAME(LVecBase3)::operator = (fill_value);
-  return *this;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: LPoint3::Constructor
 //       Access: Public
@@ -230,6 +199,18 @@ cross(const FLOATNAME(LVecBase3) &other) const {
 }
 
 #ifndef FLOATTYPE_IS_INT
+////////////////////////////////////////////////////////////////////
+//     Function: LPoint3::normalized
+//       Access: Published
+//  Description: Normalizes the vector and returns the normalized
+//               vector as a copy. If the vector was a zero-length
+//               vector, a zero length vector will be returned.
+////////////////////////////////////////////////////////////////////
+INLINE_LINMATH FLOATNAME(LPoint3) FLOATNAME(LPoint3)::
+normalized() const {
+  return FLOATNAME(LVecBase3)::normalized();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: LPoint3::project
 //       Access: Published

+ 2 - 3
panda/src/linmath/lpoint3_src.h

@@ -24,10 +24,8 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_LINMATH FLOATNAME(LPoint3) : public FLOATNAME(LVecBase3) {
 PUBLISHED:
-  INLINE_LINMATH FLOATNAME(LPoint3)();
+  INLINE_LINMATH FLOATNAME(LPoint3)() DEFAULT_CTOR;
   INLINE_LINMATH FLOATNAME(LPoint3)(const FLOATNAME(LVecBase3) &copy);
-  INLINE_LINMATH FLOATNAME(LPoint3) &operator = (const FLOATNAME(LVecBase3) &copy);
-  INLINE_LINMATH FLOATNAME(LPoint3) &operator = (FLOATTYPE fill_value);
   INLINE_LINMATH FLOATNAME(LPoint3)(FLOATTYPE fill_value);
   INLINE_LINMATH FLOATNAME(LPoint3)(FLOATTYPE x, FLOATTYPE y, FLOATTYPE z);
   INLINE_LINMATH FLOATNAME(LPoint3)(const FLOATNAME(LVecBase2) &copy, FLOATTYPE z);
@@ -61,6 +59,7 @@ PUBLISHED:
   INLINE_LINMATH FLOATNAME(LPoint3) cross(const FLOATNAME(LVecBase3) &other) const;
 
 #ifndef FLOATTYPE_IS_INT
+  INLINE_LINMATH FLOATNAME(LPoint3) normalized() const;
   INLINE_LINMATH FLOATNAME(LPoint3) project(const FLOATNAME(LVecBase3) &onto) const;
 #endif
 

+ 13 - 31
panda/src/linmath/lpoint4_src.I

@@ -13,15 +13,6 @@
 ////////////////////////////////////////////////////////////////////
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: LPoint4::Default Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LPoint4)::
-FLOATNAME(LPoint4)() {
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: LPoint4::Copy Constructor
 //       Access: Public
@@ -31,28 +22,6 @@ INLINE_LINMATH FLOATNAME(LPoint4)::
 FLOATNAME(LPoint4)(const FLOATNAME(LVecBase4) &copy) : FLOATNAME(LVecBase4)(copy) {
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: LPoint4::Copy Assignment Operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LPoint4) &FLOATNAME(LPoint4)::
-operator = (const FLOATNAME(LVecBase4) &copy) {
-  FLOATNAME(LVecBase4)::operator = (copy);
-  return *this;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: LPoint4::Copy Fill Operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LPoint4) &FLOATNAME(LPoint4)::
-operator = (FLOATTYPE fill_value) {
-  FLOATNAME(LVecBase4)::operator = (fill_value);
-  return *this;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: LPoint4::Constructor
 //       Access: Public
@@ -217,6 +186,19 @@ operator / (FLOATTYPE scalar) const {
 }
 
 #ifndef FLOATTYPE_IS_INT
+
+////////////////////////////////////////////////////////////////////
+//     Function: LPoint4::normalized
+//       Access: Published
+//  Description: Normalizes the vector and returns the normalized
+//               vector as a copy. If the vector was a zero-length
+//               vector, a zero length vector will be returned.
+////////////////////////////////////////////////////////////////////
+INLINE_LINMATH FLOATNAME(LPoint4) FLOATNAME(LPoint4)::
+normalized() const {
+  return FLOATNAME(LVecBase4)::normalized();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: LPoint4::project
 //       Access: Published

+ 2 - 3
panda/src/linmath/lpoint4_src.h

@@ -18,10 +18,8 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_LINMATH FLOATNAME(LPoint4) : public FLOATNAME(LVecBase4) {
 PUBLISHED:
-  INLINE_LINMATH FLOATNAME(LPoint4)();
+  INLINE_LINMATH FLOATNAME(LPoint4)() DEFAULT_CTOR;
   INLINE_LINMATH FLOATNAME(LPoint4)(const FLOATNAME(LVecBase4) &copy);
-  INLINE_LINMATH FLOATNAME(LPoint4) &operator = (const FLOATNAME(LVecBase4) &copy);
-  INLINE_LINMATH FLOATNAME(LPoint4) &operator = (FLOATTYPE fill_value);
   INLINE_LINMATH FLOATNAME(LPoint4)(FLOATTYPE fill_value);
   INLINE_LINMATH FLOATNAME(LPoint4)(FLOATTYPE x, FLOATTYPE y, FLOATTYPE z, FLOATTYPE w);
   INLINE_LINMATH FLOATNAME(LPoint4)(const FLOATNAME(LVecBase3) &copy, FLOATTYPE w);
@@ -53,6 +51,7 @@ PUBLISHED:
   INLINE_LINMATH FLOATNAME(LPoint4) operator / (FLOATTYPE scalar) const;
 
 #ifndef FLOATTYPE_IS_INT
+  INLINE_LINMATH FLOATNAME(LPoint4) normalized() const;
   INLINE_LINMATH FLOATNAME(LPoint4) project(const FLOATNAME(LVecBase4) &onto) const;
 #endif
 

+ 19 - 54
panda/src/linmath/lvecBase2_src.I

@@ -12,48 +12,6 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-
-////////////////////////////////////////////////////////////////////
-//     Function: LVecBase2::Default Constructor
-//       Access: Published
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LVecBase2)::
-FLOATNAME(LVecBase2)() {
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: LVecBase2::Copy Constructor
-//       Access: Published
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LVecBase2)::
-FLOATNAME(LVecBase2)(const FLOATNAME(LVecBase2) &copy) : _v(copy._v) {
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: LVecBase2::Copy Assignment Operator
-//       Access: Published
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LVecBase2) &FLOATNAME(LVecBase2)::
-operator = (const FLOATNAME(LVecBase2) &copy) {
-  TAU_PROFILE("void LVecBase2::operator = (LVecBase2 &)", " ", TAU_USER);
-  _v = copy._v;
-  return *this;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: LVecBase2::Fill Assignment Operator
-//       Access: Published
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LVecBase2) &FLOATNAME(LVecBase2)::
-operator = (FLOATTYPE fill_value) {
-  fill(fill_value);
-  return *this;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: LVecBase2::Constructor
 //       Access: Published
@@ -107,15 +65,6 @@ unit_y() {
   return _unit_y;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: LVecBase2::Destructor
-//       Access: Published
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LVecBase2)::
-~FLOATNAME(LVecBase2)() {
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: LVecBase2::Indexing Operator
 //       Access: Published
@@ -143,7 +92,7 @@ operator [](int i) {
 //       Access: Published, Static
 //  Description: Returns 2: the number of components of a LVecBase2.
 ////////////////////////////////////////////////////////////////////
-INLINE_LINMATH int FLOATNAME(LVecBase2)::
+CONSTEXPR int FLOATNAME(LVecBase2)::
 size() {
   return 2;
 }
@@ -274,8 +223,8 @@ get_data() const {
 //       Access: Published
 //  Description: Returns the number of elements in the vector, two.
 ////////////////////////////////////////////////////////////////////
-INLINE_LINMATH int FLOATNAME(LVecBase2)::
-get_num_components() const {
+CONSTEXPR int FLOATNAME(LVecBase2)::
+get_num_components() {
   return 2;
 }
 
@@ -418,6 +367,22 @@ normalize() {
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: LVecBase2::normalized
+//       Access: Published
+//  Description: Normalizes the vector and returns the normalized
+//               vector as a copy. If the vector was a zero-length
+//               vector, a zero length vector will be returned.
+////////////////////////////////////////////////////////////////////
+INLINE_LINMATH FLOATNAME(LVecBase2) FLOATNAME(LVecBase2)::
+normalized() const {
+  FLOATTYPE l2 = length_squared();
+  if (l2 == (FLOATTYPE)0.0f) {
+    return FLOATNAME(LVecBase2)(0.0f);
+  }
+  return (*this) / csqrt(l2);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: LVecBase2::project
 //       Access: Published

+ 11 - 10
panda/src/linmath/lvecBase2_src.h

@@ -34,38 +34,38 @@ PUBLISHED:
 #endif
   };
 
-  INLINE_LINMATH FLOATNAME(LVecBase2)();
-  INLINE_LINMATH FLOATNAME(LVecBase2)(const FLOATNAME(LVecBase2) &copy);
-  INLINE_LINMATH FLOATNAME(LVecBase2) &operator = (const FLOATNAME(LVecBase2) &copy);
-  INLINE_LINMATH FLOATNAME(LVecBase2) &operator = (FLOATTYPE fill_value);
+  INLINE_LINMATH FLOATNAME(LVecBase2)() DEFAULT_CTOR;
   INLINE_LINMATH FLOATNAME(LVecBase2)(FLOATTYPE fill_value);
   INLINE_LINMATH FLOATNAME(LVecBase2)(FLOATTYPE x, FLOATTYPE y);
+
   ALLOC_DELETED_CHAIN(FLOATNAME(LVecBase2));
 
   INLINE_LINMATH static const FLOATNAME(LVecBase2) &zero();
   INLINE_LINMATH static const FLOATNAME(LVecBase2) &unit_x();
   INLINE_LINMATH static const FLOATNAME(LVecBase2) &unit_y();
 
-  INLINE_LINMATH ~FLOATNAME(LVecBase2)();
-
   EXTENSION(INLINE_LINMATH PyObject *__reduce__(PyObject *self) const);
   EXTENSION(INLINE_LINMATH PyObject *__getattr__(PyObject *self, const string &attr_name) const);
   EXTENSION(INLINE_LINMATH int __setattr__(PyObject *self, const string &attr_name, PyObject *assign));
 
   INLINE_LINMATH FLOATTYPE operator [](int i) const;
   INLINE_LINMATH FLOATTYPE &operator [](int i);
-  INLINE_LINMATH static int size();
+  CONSTEXPR static int size();
 
   INLINE_LINMATH bool is_nan() const;
 
   INLINE_LINMATH FLOATTYPE get_cell(int i) const;
+  INLINE_LINMATH void set_cell(int i, FLOATTYPE value);
+
   INLINE_LINMATH FLOATTYPE get_x() const;
   INLINE_LINMATH FLOATTYPE get_y() const;
-
-  INLINE_LINMATH void set_cell(int i, FLOATTYPE value);
   INLINE_LINMATH void set_x(FLOATTYPE value);
   INLINE_LINMATH void set_y(FLOATTYPE value);
 
+PUBLISHED:
+  MAKE_PROPERTY(x, get_x, set_x);
+  MAKE_PROPERTY(y, get_y, set_y);
+
   // These next functions add to an existing value.
   // i.e. foo.set_x(foo.get_x() + value)
   // These are useful to reduce overhead in scripting
@@ -75,7 +75,7 @@ PUBLISHED:
   INLINE_LINMATH void add_y(FLOATTYPE value);
 
   INLINE_LINMATH const FLOATTYPE *get_data() const;
-  INLINE_LINMATH int get_num_components() const;
+  CONSTEXPR static int get_num_components();
 
 public:
   INLINE_LINMATH iterator begin();
@@ -94,6 +94,7 @@ PUBLISHED:
 #ifndef FLOATTYPE_IS_INT
   INLINE_LINMATH FLOATTYPE length() const;
   INLINE_LINMATH bool normalize();
+  INLINE_LINMATH FLOATNAME(LVecBase2) normalized() const;
   INLINE_LINMATH FLOATNAME(LVecBase2) project(const FLOATNAME(LVecBase2) &onto) const;
 #endif
 

+ 19 - 53
panda/src/linmath/lvecBase3_src.I

@@ -13,47 +13,6 @@
 ////////////////////////////////////////////////////////////////////
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: LVecBase3::Default Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LVecBase3)::
-FLOATNAME(LVecBase3)() {
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: LVecBase3::Copy Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LVecBase3)::
-FLOATNAME(LVecBase3)(const FLOATNAME(LVecBase3) &copy) : _v(copy._v) {
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: LVecBase3::Copy Assignment Operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LVecBase3) &FLOATNAME(LVecBase3)::
-operator = (const FLOATNAME(LVecBase3) &copy) {
-  TAU_PROFILE("void LVecBase3::operator =(LVecBase3 &)", " ", TAU_USER);
-  _v = copy._v;
-  return *this;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: LVecBase3::Fill Assignment Operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LVecBase3) &FLOATNAME(LVecBase3)::
-operator = (FLOATTYPE fill_value) {
-  fill(fill_value);
-  return *this;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: LVecBase3::Constructor
 //       Access: Public
@@ -128,15 +87,6 @@ unit_z() {
   return _unit_z;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: LVecBase3::Destructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LVecBase3)::
-~FLOATNAME(LVecBase3)() {
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: LVecBase3::Indexing Operator
 //       Access: Public
@@ -164,7 +114,7 @@ operator [](int i) {
 //       Access: Public, Static
 //  Description: Returns 3: the number of components of a LVecBase3.
 ////////////////////////////////////////////////////////////////////
-INLINE_LINMATH int FLOATNAME(LVecBase3)::
+CONSTEXPR int FLOATNAME(LVecBase3)::
 size() {
   return 3;
 }
@@ -358,8 +308,8 @@ get_data() const {
 //       Access: Public
 //  Description: Returns the number of elements in the vector, three.
 ////////////////////////////////////////////////////////////////////
-INLINE_LINMATH int FLOATNAME(LVecBase3)::
-get_num_components() const {
+CONSTEXPR int FLOATNAME(LVecBase3)::
+get_num_components() {
   return 3;
 }
 
@@ -509,6 +459,22 @@ normalize() {
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: LVecBase3::normalized
+//       Access: Published
+//  Description: Normalizes the vector and returns the normalized
+//               vector as a copy. If the vector was a zero-length
+//               vector, a zero length vector will be returned.
+////////////////////////////////////////////////////////////////////
+INLINE_LINMATH FLOATNAME(LVecBase3) FLOATNAME(LVecBase3)::
+normalized() const {
+  FLOATTYPE l2 = length_squared();
+  if (l2 == (FLOATTYPE)0.0f) {
+    return FLOATNAME(LVecBase3)(0.0f);
+  }
+  return (*this) / csqrt(l2);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: LVecBase3::project
 //       Access: Published

+ 10 - 8
panda/src/linmath/lvecBase3_src.h

@@ -34,10 +34,7 @@ PUBLISHED:
 #endif
   };
 
-  INLINE_LINMATH FLOATNAME(LVecBase3)();
-  INLINE_LINMATH FLOATNAME(LVecBase3)(const FLOATNAME(LVecBase3) &copy);
-  INLINE_LINMATH FLOATNAME(LVecBase3) &operator = (const FLOATNAME(LVecBase3) &copy);
-  INLINE_LINMATH FLOATNAME(LVecBase3) &operator = (FLOATTYPE fill_value);
+  INLINE_LINMATH FLOATNAME(LVecBase3)() DEFAULT_CTOR;
   INLINE_LINMATH FLOATNAME(LVecBase3)(FLOATTYPE fill_value);
   INLINE_LINMATH FLOATNAME(LVecBase3)(FLOATTYPE x, FLOATTYPE y, FLOATTYPE z);
   INLINE_LINMATH FLOATNAME(LVecBase3)(const FLOATNAME(LVecBase2) &copy, FLOATTYPE z);
@@ -48,15 +45,13 @@ PUBLISHED:
   INLINE_LINMATH static const FLOATNAME(LVecBase3) &unit_y();
   INLINE_LINMATH static const FLOATNAME(LVecBase3) &unit_z();
 
-  INLINE_LINMATH ~FLOATNAME(LVecBase3)();
-
   EXTENSION(INLINE_LINMATH PyObject *__reduce__(PyObject *self) const);
   EXTENSION(INLINE_LINMATH PyObject *__getattr__(PyObject *self, const string &attr_name) const);
   EXTENSION(INLINE_LINMATH int __setattr__(PyObject *self, const string &attr_name, PyObject *assign));
 
   INLINE_LINMATH FLOATTYPE operator [](int i) const;
   INLINE_LINMATH FLOATTYPE &operator [](int i);
-  INLINE_LINMATH static int size();
+  CONSTEXPR static int size();
 
   INLINE_LINMATH bool is_nan() const;
 
@@ -74,6 +69,12 @@ PUBLISHED:
   INLINE_LINMATH FLOATNAME(LVecBase2) get_xz() const;
   INLINE_LINMATH FLOATNAME(LVecBase2) get_yz() const;
 
+PUBLISHED:
+  MAKE_PROPERTY(x, get_x, set_x);
+  MAKE_PROPERTY(y, get_y, set_y);
+  MAKE_PROPERTY(z, get_z, set_z);
+  MAKE_PROPERTY(xy, get_xy);
+
   // These next functions add to an existing value.
   // i.e. foo.set_x(foo.get_x() + value)
   // These are useful to reduce overhead in scripting
@@ -84,7 +85,7 @@ PUBLISHED:
   INLINE_LINMATH void add_z(FLOATTYPE value);
 
   INLINE_LINMATH const FLOATTYPE *get_data() const;
-  INLINE_LINMATH int get_num_components() const;
+  CONSTEXPR static int get_num_components();
 
 public:
   INLINE_LINMATH iterator begin();
@@ -103,6 +104,7 @@ PUBLISHED:
 #ifndef FLOATTYPE_IS_INT
   INLINE_LINMATH FLOATTYPE length() const;
   INLINE_LINMATH bool normalize();
+  INLINE_LINMATH FLOATNAME(LVecBase3) normalized() const;
   INLINE_LINMATH FLOATNAME(LVecBase3) project(const FLOATNAME(LVecBase3) &onto) const;
 #endif
 

+ 42 - 108
panda/src/linmath/lvecBase4_src.I

@@ -13,24 +13,6 @@
 ////////////////////////////////////////////////////////////////////
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: LVecBase4::Default Constructor
-//       Access: Published
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LVecBase4)::
-FLOATNAME(LVecBase4)() {
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: LVecBase4::Copy Constructor
-//       Access: Published
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LVecBase4)::
-FLOATNAME(LVecBase4)(const FLOATNAME(LVecBase4) &copy) : _v(copy._v) {
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: LVecBase4::Copy Constructor
 //       Access: Public
@@ -41,40 +23,6 @@ FLOATNAME(LVecBase4)(const FLOATNAME(UnalignedLVecBase4) &copy) {
   set(copy[0], copy[1], copy[2], copy[3]);
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: LVecBase4::Copy Assignment Operator
-//       Access: Published
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LVecBase4) &FLOATNAME(LVecBase4)::
-operator = (const FLOATNAME(LVecBase4) &copy) {
-  TAU_PROFILE("void LVecBase4::operator = (LVecBase4 &)", " ", TAU_USER);
-  _v = copy._v;
-  return *this;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: LVecBase4::Copy Assignment Operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LVecBase4) &FLOATNAME(LVecBase4)::
-operator = (const FLOATNAME(UnalignedLVecBase4) &copy) {
-  set(copy[0], copy[1], copy[2], copy[3]);
-  return *this;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: LVecBase4::Fill Assignment Operator
-//       Access: Published
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LVecBase4) &FLOATNAME(LVecBase4)::
-operator = (FLOATTYPE fill_value) {
-  fill(fill_value);
-  return *this;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: LVecBase4::Constructor
 //       Access: Published
@@ -128,15 +76,6 @@ FLOATNAME(LVecBase4)(const FLOATNAME(LVector3) &vector) {
   set(vector[0], vector[1], vector[2], 0);
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: LVecBase4::Destructor
-//       Access: Published
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LVecBase4)::
-~FLOATNAME(LVecBase4)() {
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: LVecBase4::zero Named Constructor
 //       Access: Published
@@ -214,7 +153,7 @@ operator [](int i) {
 //       Access: Published, Static
 //  Description: Returns 4: the number of components of a LVecBase4.
 ////////////////////////////////////////////////////////////////////
-INLINE_LINMATH int FLOATNAME(LVecBase4)::
+CONSTEXPR int FLOATNAME(LVecBase4)::
 size() {
   return 4;
 }
@@ -286,6 +225,26 @@ get_w() const {
   return _v(3);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: LVecBase4::get_xyz
+//       Access: Published
+//  Description: Returns the x, y and z component of this vector
+////////////////////////////////////////////////////////////////////
+INLINE_LINMATH FLOATNAME(LVecBase3) FLOATNAME(LVecBase4)::
+get_xyz() const {
+  return FLOATNAME(LVecBase3)(_v(0), _v(1), _v(2));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LVecBase4::get_xy
+//       Access: Published
+//  Description: Returns the x and y component of this vector
+////////////////////////////////////////////////////////////////////
+INLINE_LINMATH FLOATNAME(LVecBase2) FLOATNAME(LVecBase4)::
+get_xy() const {
+  return FLOATNAME(LVecBase2)(_v(0), _v(1));
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: LVecBase4::set_cell
 //       Access: Published
@@ -405,8 +364,8 @@ get_data() const {
 //       Access: Published
 //  Description: Returns the number of elements in the vector, four.
 ////////////////////////////////////////////////////////////////////
-INLINE_LINMATH int FLOATNAME(LVecBase4)::
-get_num_components() const {
+CONSTEXPR int FLOATNAME(LVecBase4)::
+get_num_components() {
   return 4;
 }
 
@@ -559,6 +518,22 @@ normalize() {
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: LVecBase4::normalized
+//       Access: Published
+//  Description: Normalizes the vector and returns the normalized
+//               vector as a copy. If the vector was a zero-length
+//               vector, a zero length vector will be returned.
+////////////////////////////////////////////////////////////////////
+INLINE_LINMATH FLOATNAME(LVecBase4) FLOATNAME(LVecBase4)::
+normalized() const {
+  FLOATTYPE l2 = length_squared();
+  if (l2 == (FLOATTYPE)0.0f) {
+    return FLOATNAME(LVecBase4)(0.0f);
+  }
+  return (*this) / csqrt(l2);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: LVecBase4::project
 //       Access: Published
@@ -1107,15 +1082,6 @@ read_datagram(DatagramIterator &source) {
 #endif
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: UnalignedLVecBase4::Default Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(UnalignedLVecBase4)::
-FLOATNAME(UnalignedLVecBase4)() {
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: UnalignedLVecBase4::Copy Constructor
 //       Access: Public
@@ -1126,38 +1092,6 @@ FLOATNAME(UnalignedLVecBase4)(const FLOATNAME(LVecBase4) &copy) {
   set(copy[0], copy[1], copy[2], copy[3]);
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: UnalignedLVecBase4::Copy Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(UnalignedLVecBase4)::
-FLOATNAME(UnalignedLVecBase4)(const FLOATNAME(UnalignedLVecBase4) &copy) : _v(copy._v) {
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: UnalignedLVecBase4::Copy Assignment Operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(UnalignedLVecBase4) &FLOATNAME(UnalignedLVecBase4)::
-operator = (const FLOATNAME(LVecBase4) &copy) {
-  set(copy[0], copy[1], copy[2], copy[3]);
-  return *this;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: UnalignedLVecBase4::Copy Assignment Operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(UnalignedLVecBase4) &FLOATNAME(UnalignedLVecBase4)::
-operator = (const FLOATNAME(UnalignedLVecBase4) &copy) {
-  TAU_PROFILE("void UnalignedLVecBase4::operator =(UnalignedLVecBase4 &)", " ", TAU_USER);
-  _v = copy._v;
-  return *this;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: UnalignedLVecBase4::Constructor
 //       Access: Public
@@ -1210,7 +1144,7 @@ operator [](int i) {
 //       Access: Public, Static
 //  Description: Returns 4: the number of components of a LVecBase4.
 ////////////////////////////////////////////////////////////////////
-INLINE_LINMATH int FLOATNAME(UnalignedLVecBase4)::
+CONSTEXPR int FLOATNAME(UnalignedLVecBase4)::
 size() {
   return 4;
 }
@@ -1232,7 +1166,7 @@ get_data() const {
 //       Access: Public
 //  Description: Returns the number of elements in the vector, 4.
 ////////////////////////////////////////////////////////////////////
-INLINE_LINMATH int FLOATNAME(UnalignedLVecBase4)::
-get_num_components() const {
+CONSTEXPR int FLOATNAME(UnalignedLVecBase4)::
+get_num_components() {
   return 4;
 }

+ 20 - 17
panda/src/linmath/lvecBase4_src.h

@@ -39,14 +39,10 @@ PUBLISHED:
 #endif
   };
 
-  INLINE_LINMATH FLOATNAME(LVecBase4)();
-  INLINE_LINMATH FLOATNAME(LVecBase4)(const FLOATNAME(LVecBase4) &copy);
-  INLINE_LINMATH FLOATNAME(LVecBase4)(const FLOATNAME(UnalignedLVecBase4) &copy);
-  INLINE_LINMATH FLOATNAME(LVecBase4) &operator = (const FLOATNAME(LVecBase4) &copy);
-  INLINE_LINMATH FLOATNAME(LVecBase4) &operator = (const FLOATNAME(UnalignedLVecBase4) &copy);
-  INLINE_LINMATH FLOATNAME(LVecBase4) &operator = (FLOATTYPE fill_value);
+  INLINE_LINMATH FLOATNAME(LVecBase4)() DEFAULT_CTOR;
   INLINE_LINMATH FLOATNAME(LVecBase4)(FLOATTYPE fill_value);
   INLINE_LINMATH FLOATNAME(LVecBase4)(FLOATTYPE x, FLOATTYPE y, FLOATTYPE z, FLOATTYPE w);
+  INLINE_LINMATH FLOATNAME(LVecBase4)(const FLOATNAME(UnalignedLVecBase4) &copy);
   INLINE_LINMATH FLOATNAME(LVecBase4)(const FLOATNAME(LVecBase3) &copy, FLOATTYPE w);
   INLINE_LINMATH FLOATNAME(LVecBase4)(const FLOATNAME(LPoint3) &point);
   INLINE_LINMATH FLOATNAME(LVecBase4)(const FLOATNAME(LVector3) &vector);
@@ -58,30 +54,39 @@ PUBLISHED:
   INLINE_LINMATH static const FLOATNAME(LVecBase4) &unit_z();
   INLINE_LINMATH static const FLOATNAME(LVecBase4) &unit_w();
 
-  INLINE_LINMATH ~FLOATNAME(LVecBase4)();
-
   EXTENSION(INLINE_LINMATH PyObject *__reduce__(PyObject *self) const);
   EXTENSION(INLINE_LINMATH PyObject *__getattr__(PyObject *self, const string &attr_name) const);
   EXTENSION(INLINE_LINMATH int __setattr__(PyObject *self, const string &attr_name, PyObject *assign));
 
   INLINE_LINMATH FLOATTYPE operator [](int i) const;
   INLINE_LINMATH FLOATTYPE &operator [](int i);
-  INLINE_LINMATH static int size();
+  CONSTEXPR static int size();
 
   INLINE_LINMATH bool is_nan() const;
 
   INLINE_LINMATH FLOATTYPE get_cell(int i) const;
+  INLINE_LINMATH void set_cell(int i, FLOATTYPE value);
+
   INLINE_LINMATH FLOATTYPE get_x() const;
   INLINE_LINMATH FLOATTYPE get_y() const;
   INLINE_LINMATH FLOATTYPE get_z() const;
   INLINE_LINMATH FLOATTYPE get_w() const;
 
-  INLINE_LINMATH void set_cell(int i, FLOATTYPE value);
+  INLINE_LINMATH FLOATNAME(LVecBase3) get_xyz() const;
+  INLINE_LINMATH FLOATNAME(LVecBase2) get_xy() const;
+
   INLINE_LINMATH void set_x(FLOATTYPE value);
   INLINE_LINMATH void set_y(FLOATTYPE value);
   INLINE_LINMATH void set_z(FLOATTYPE value);
   INLINE_LINMATH void set_w(FLOATTYPE value);
 
+PUBLISHED:
+  MAKE_PROPERTY(x, get_x, set_x);
+  MAKE_PROPERTY(y, get_y, set_y);
+  MAKE_PROPERTY(z, get_z, set_z);
+  MAKE_PROPERTY(xy, get_xy);
+  MAKE_PROPERTY(xyz, get_xyz);
+
   // These next functions add to an existing value.
   // i.e. foo.set_x(foo.get_x() + value)
   // These are useful to reduce overhead in scripting
@@ -93,7 +98,7 @@ PUBLISHED:
   INLINE_LINMATH void add_w(FLOATTYPE value);
 
   INLINE_LINMATH const FLOATTYPE *get_data() const;
-  INLINE_LINMATH int get_num_components() const;
+  CONSTEXPR static int get_num_components();
   INLINE_LINMATH void extract_data(float*){};
 
 public:
@@ -113,6 +118,7 @@ PUBLISHED:
 #ifndef FLOATTYPE_IS_INT
   INLINE_LINMATH FLOATTYPE length() const;
   INLINE_LINMATH bool normalize();
+  INLINE_LINMATH FLOATNAME(LVecBase4) normalized() const;
   INLINE_LINMATH FLOATNAME(LVecBase4) project(const FLOATNAME(LVecBase4) &onto) const;
 #endif
 
@@ -223,21 +229,18 @@ PUBLISHED:
 #endif
   };
 
-  INLINE_LINMATH FLOATNAME(UnalignedLVecBase4)();
+  INLINE_LINMATH FLOATNAME(UnalignedLVecBase4)() DEFAULT_CTOR;
   INLINE_LINMATH FLOATNAME(UnalignedLVecBase4)(const FLOATNAME(LVecBase4) &copy);
-  INLINE_LINMATH FLOATNAME(UnalignedLVecBase4)(const FLOATNAME(UnalignedLVecBase4) &copy);
-  INLINE_LINMATH FLOATNAME(UnalignedLVecBase4) &operator = (const FLOATNAME(LVecBase4) &copy);
-  INLINE_LINMATH FLOATNAME(UnalignedLVecBase4) &operator = (const FLOATNAME(UnalignedLVecBase4) &copy);
   INLINE_LINMATH FLOATNAME(UnalignedLVecBase4)(FLOATTYPE x, FLOATTYPE y, FLOATTYPE z, FLOATTYPE w);
 
   INLINE_LINMATH void set(FLOATTYPE x, FLOATTYPE y, FLOATTYPE z, FLOATTYPE w);
 
   INLINE_LINMATH FLOATTYPE operator [](int i) const;
   INLINE_LINMATH FLOATTYPE &operator [](int i);
-  INLINE_LINMATH static int size();
+  CONSTEXPR static int size();
 
   INLINE_LINMATH const FLOATTYPE *get_data() const;
-  INLINE_LINMATH int get_num_components() const;
+  CONSTEXPR static int get_num_components();
 
 public:
   typedef FLOATTYPE numeric_type;

+ 19 - 34
panda/src/linmath/lvector2_src.I

@@ -12,50 +12,23 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-////////////////////////////////////////////////////////////////////
-//     Function: LVector2::Default Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LVector2)::
-FLOATNAME(LVector2)() {
-}
 
 ////////////////////////////////////////////////////////////////////
-//     Function: LVector2::Copy Constructor
+//     Function: LVector2::Constructor
 //       Access: Public
-//  Description:
+//  Description: Constructs a new LVector2 from a LVecBase2
 ////////////////////////////////////////////////////////////////////
 INLINE_LINMATH FLOATNAME(LVector2)::
-FLOATNAME(LVector2)(const FLOATNAME(LVecBase2) &copy) : FLOATNAME(LVecBase2)(copy) {
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: LVector2::Copy Assignment Operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LVector2) &FLOATNAME(LVector2)::
-operator = (const FLOATNAME(LVecBase2) &copy) {
-  FLOATNAME(LVecBase2)::operator = (copy);
-  return *this;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: LVector2::Copy Fill Operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LVector2) &FLOATNAME(LVector2)::
-operator = (FLOATTYPE fill_value) {
-  FLOATNAME(LVecBase2)::operator = (fill_value);
-  return *this;
+FLOATNAME(LVector2)(const FLOATNAME(LVecBase2)& copy) :
+  FLOATNAME(LVecBase2)(copy)
+{
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: LVector2::Constructor
 //       Access: Public
-//  Description:
+//  Description: Constructs a new LVector2 with all components set
+//               to the fill value.
 ////////////////////////////////////////////////////////////////////
 INLINE_LINMATH FLOATNAME(LVector2)::
 FLOATNAME(LVector2)(FLOATTYPE fill_value) :
@@ -175,6 +148,18 @@ operator / (FLOATTYPE scalar) const {
 }
 
 #ifndef FLOATTYPE_IS_INT
+////////////////////////////////////////////////////////////////////
+//     Function: LVector2::normalized
+//       Access: Published
+//  Description: Normalizes the vector and returns the normalized
+//               vector as a copy. If the vector was a zero-length
+//               vector, a zero length vector will be returned.
+////////////////////////////////////////////////////////////////////
+INLINE_LINMATH FLOATNAME(LVector2) FLOATNAME(LVector2)::
+normalized() const {
+  return FLOATNAME(LVecBase2)::normalized();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: LVector2::project
 //       Access: Published

+ 4 - 4
panda/src/linmath/lvector2_src.h

@@ -18,10 +18,9 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_LINMATH FLOATNAME(LVector2) : public FLOATNAME(LVecBase2) {
 PUBLISHED:
-  INLINE_LINMATH FLOATNAME(LVector2)();
-  INLINE_LINMATH FLOATNAME(LVector2)(const FLOATNAME(LVecBase2) &copy);
-  INLINE_LINMATH FLOATNAME(LVector2) &operator = (const FLOATNAME(LVecBase2) &copy);
-  INLINE_LINMATH FLOATNAME(LVector2) &operator = (FLOATTYPE fill_value);
+
+  INLINE_LINMATH FLOATNAME(LVector2)() DEFAULT_CTOR;
+  INLINE_LINMATH FLOATNAME(LVector2)(const FLOATNAME(LVecBase2)& copy);
   INLINE_LINMATH FLOATNAME(LVector2)(FLOATTYPE fill_value);
   INLINE_LINMATH FLOATNAME(LVector2)(FLOATTYPE x, FLOATTYPE y);
 
@@ -44,6 +43,7 @@ PUBLISHED:
   INLINE_LINMATH FLOATNAME(LVector2) operator / (FLOATTYPE scalar) const;
 
 #ifndef FLOATTYPE_IS_INT
+  INLINE_LINMATH FLOATNAME(LVector2) normalized() const;
   INLINE_LINMATH FLOATNAME(LVector2) project(const FLOATNAME(LVecBase2) &onto) const;
   INLINE_LINMATH FLOATTYPE signed_angle_rad(const FLOATNAME(LVector2) &other) const;
   INLINE_LINMATH FLOATTYPE signed_angle_deg(const FLOATNAME(LVector2) &other) const;

+ 13 - 30
panda/src/linmath/lvector3_src.I

@@ -13,15 +13,6 @@
 ////////////////////////////////////////////////////////////////////
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: LVector3::Default Constructor
-//       Access: Published
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LVector3)::
-FLOATNAME(LVector3)() {
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: LVector3::Copy Constructor
 //       Access: Published
@@ -31,27 +22,6 @@ INLINE_LINMATH FLOATNAME(LVector3)::
 FLOATNAME(LVector3)(const FLOATNAME(LVecBase3) &copy) : FLOATNAME(LVecBase3)(copy) {
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: LVector3::Copy Assignment Operator
-//       Access: Published
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LVector3) &FLOATNAME(LVector3)::
-operator = (const FLOATNAME(LVecBase3) &copy) {
-  FLOATNAME(LVecBase3)::operator = (copy);
-  return *this;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: LVector3::Copy Fill Operator
-//       Access: Published
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LVector3) &FLOATNAME(LVector3)::
-operator = (FLOATTYPE fill_value) {
-  FLOATNAME(LVecBase3)::operator = (fill_value);
-  return *this;
-}
 
 ////////////////////////////////////////////////////////////////////
 //     Function: LVector3::Constructor
@@ -220,6 +190,19 @@ cross(const FLOATNAME(LVecBase3) &other) const {
 }
 
 #ifndef FLOATTYPE_IS_INT
+
+////////////////////////////////////////////////////////////////////
+//     Function: LVector3::normalized
+//       Access: Published
+//  Description: Normalizes the vector and returns the normalized
+//               vector as a copy. If the vector was a zero-length
+//               vector, a zero length vector will be returned.
+////////////////////////////////////////////////////////////////////
+INLINE_LINMATH FLOATNAME(LVector3) FLOATNAME(LVector3)::
+normalized() const {
+  return FLOATNAME(LVecBase3)::normalized();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: LVector3::project
 //       Access: Published

+ 2 - 3
panda/src/linmath/lvector3_src.h

@@ -24,10 +24,8 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_LINMATH FLOATNAME(LVector3) : public FLOATNAME(LVecBase3) {
 PUBLISHED:
-  INLINE_LINMATH FLOATNAME(LVector3)();
+  INLINE_LINMATH FLOATNAME(LVector3)() DEFAULT_CTOR;
   INLINE_LINMATH FLOATNAME(LVector3)(const FLOATNAME(LVecBase3) &copy);
-  INLINE_LINMATH FLOATNAME(LVector3) &operator = (const FLOATNAME(LVecBase3) &copy);
-  INLINE_LINMATH FLOATNAME(LVector3) &operator = (FLOATTYPE fill_value);
   INLINE_LINMATH FLOATNAME(LVector3)(FLOATTYPE fill_value);
   INLINE_LINMATH FLOATNAME(LVector3)(FLOATTYPE x, FLOATTYPE y, FLOATTYPE z);
   INLINE_LINMATH FLOATNAME(LVector3)(const FLOATNAME(LVecBase2) &copy, FLOATTYPE z);
@@ -55,6 +53,7 @@ PUBLISHED:
   INLINE_LINMATH FLOATNAME(LVector3) cross(const FLOATNAME(LVecBase3) &other) const;
 
 #ifndef FLOATTYPE_IS_INT
+  INLINE_LINMATH FLOATNAME(LVector3) normalized() const;
   INLINE_LINMATH FLOATNAME(LVector3) project(const FLOATNAME(LVecBase3) &onto) const;
   INLINE_LINMATH FLOATTYPE angle_rad(const FLOATNAME(LVector3) &other) const;
   INLINE_LINMATH FLOATTYPE angle_deg(const FLOATNAME(LVector3) &other) const;

+ 13 - 31
panda/src/linmath/lvector4_src.I

@@ -13,15 +13,6 @@
 ////////////////////////////////////////////////////////////////////
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: LVector4::Default Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LVector4)::
-FLOATNAME(LVector4)() {
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: LVector4::Copy Constructor
 //       Access: Public
@@ -31,28 +22,6 @@ INLINE_LINMATH FLOATNAME(LVector4)::
 FLOATNAME(LVector4)(const FLOATNAME(LVecBase4) &copy) : FLOATNAME(LVecBase4)(copy) {
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: LVector4::Copy Assignment Operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LVector4) &FLOATNAME(LVector4)::
-operator = (const FLOATNAME(LVecBase4) &copy) {
-  FLOATNAME(LVecBase4)::operator = (copy);
-  return *this;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: LVector4::Copy Fill Operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE_LINMATH FLOATNAME(LVector4) &FLOATNAME(LVector4)::
-operator = (FLOATTYPE fill_value) {
-  FLOATNAME(LVecBase4)::operator = (fill_value);
-  return *this;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: LVector4::Constructor
 //       Access: Public
@@ -207,6 +176,19 @@ operator / (FLOATTYPE scalar) const {
 }
 
 #ifndef FLOATTYPE_IS_INT
+
+////////////////////////////////////////////////////////////////////
+//     Function: LVector4::normalized
+//       Access: Published
+//  Description: Normalizes the vector and returns the normalized
+//               vector as a copy. If the vector was a zero-length
+//               vector, a zero length vector will be returned.
+////////////////////////////////////////////////////////////////////
+INLINE_LINMATH FLOATNAME(LVector4) FLOATNAME(LVector4)::
+normalized() const {
+  return FLOATNAME(LVecBase4)::normalized();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: LVector4::project
 //       Access: Published

+ 2 - 3
panda/src/linmath/lvector4_src.h

@@ -18,10 +18,8 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_LINMATH FLOATNAME(LVector4) : public FLOATNAME(LVecBase4) {
 PUBLISHED:
-  INLINE_LINMATH FLOATNAME(LVector4)();
+  INLINE_LINMATH FLOATNAME(LVector4)() DEFAULT_CTOR;
   INLINE_LINMATH FLOATNAME(LVector4)(const FLOATNAME(LVecBase4) &copy);
-  INLINE_LINMATH FLOATNAME(LVector4) &operator = (const FLOATNAME(LVecBase4) &copy);
-  INLINE_LINMATH FLOATNAME(LVector4) &operator = (FLOATTYPE fill_value);
   INLINE_LINMATH FLOATNAME(LVector4)(FLOATTYPE fill_value);
   INLINE_LINMATH FLOATNAME(LVector4)(FLOATTYPE x, FLOATTYPE y, FLOATTYPE z, FLOATTYPE w);
   INLINE_LINMATH FLOATNAME(LVector4)(const FLOATNAME(LVecBase3) &copy, FLOATTYPE w);
@@ -47,6 +45,7 @@ PUBLISHED:
   INLINE_LINMATH FLOATNAME(LVector4) operator / (FLOATTYPE scalar) const;
 
 #ifndef FLOATTYPE_IS_INT
+  INLINE_LINMATH FLOATNAME(LVector4) normalized() const;
   INLINE_LINMATH FLOATNAME(LVector4) project(const FLOATNAME(LVecBase4) &onto) const;
 #endif
 

+ 69 - 54
panda/src/pgraph/clipPlaneAttrib.cxx

@@ -960,12 +960,7 @@ write_datagram(BamWriter *manager, Datagram &dg) {
   // write the off planes pointers if any
   Planes::const_iterator fi;
   for (fi = _off_planes.begin(); fi != _off_planes.end(); ++fi) {
-    NodePath plane = (*fi);
-
-    // Since we can't write out a NodePath, we write out just the
-    // plain PandaNode.  The user can use the AttribNodeRegistry on
-    // re-read if there is any ambiguity that needs to be resolved.
-    manager->write_pointer(dg, plane.node());
+    (*fi).write_datagram(manager, dg);
   }
 
   // write the number of on planes
@@ -973,8 +968,7 @@ write_datagram(BamWriter *manager, Datagram &dg) {
   // write the on planes pointers if any
   Planes::const_iterator nti;
   for (nti = _on_planes.begin(); nti != _on_planes.end(); ++nti) {
-    NodePath plane = (*nti);
-    manager->write_pointer(dg, plane.node());
+    (*nti).write_datagram(manager, dg);
   }
 }
 
@@ -990,38 +984,62 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) {
   int pi = RenderAttrib::complete_pointers(p_list, manager);
   AttribNodeRegistry *areg = AttribNodeRegistry::get_global_ptr();
 
-  Planes::iterator ci = _off_planes.begin();
-  while (ci != _off_planes.end()) {
-    PandaNode *node;
-    DCAST_INTO_R(node, p_list[pi++], pi);
-    
-    // We go through some effort to look up the node in the registry
-    // without creating a NodePath around it first (which would up,
-    // and then down, the reference count, possibly deleting the
-    // node).
-    int ni = areg->find_node(node->get_type(), node->get_name());
-    if (ni != -1) {
-      (*ci) = areg->get_node(ni);
-    } else {
-      (*ci) = NodePath(node);
+  if (manager->get_file_minor_ver() >= 40) {
+    for (int i = 0; i < _off_planes.size(); ++i) {
+      pi += _off_planes[i].complete_pointers(p_list + pi, manager);
+
+      int n = areg->find_node(_off_planes[i]);
+      if (n != -1) {
+        // If it's in the registry, replace it.
+        _off_planes[i] = areg->get_node(n);
+      }
     }
-    ++ci;
-  }
-  _off_planes.sort();
 
-  ci = _on_planes.begin();
-  while (ci != _on_planes.end()) {
-    PandaNode *node;
-    DCAST_INTO_R(node, p_list[pi++], pi);
+    for (int i = 0; i < _on_planes.size(); ++i) {
+      pi += _on_planes[i].complete_pointers(p_list + pi, manager);
 
-    int ni = areg->find_node(node->get_type(), node->get_name());
-    if (ni != -1) {
-      (*ci) = areg->get_node(ni);
-    } else {
-      (*ci) = NodePath(node);
+      int n = areg->find_node(_on_planes[i]);
+      if (n != -1) {
+        // If it's in the registry, replace it.
+        _on_planes[i] = areg->get_node(n);
+      }
+    }
+
+  } else {
+    Planes::iterator ci = _off_planes.begin();
+    while (ci != _off_planes.end()) {
+      PandaNode *node;
+      DCAST_INTO_R(node, p_list[pi++], pi);
+
+      // We go through some effort to look up the node in the registry
+      // without creating a NodePath around it first (which would up,
+      // and then down, the reference count, possibly deleting the
+      // node).
+      int ni = areg->find_node(node->get_type(), node->get_name());
+      if (ni != -1) {
+        (*ci) = areg->get_node(ni);
+      } else {
+        (*ci) = NodePath(node);
+      }
+      ++ci;
+    }
+
+    ci = _on_planes.begin();
+    while (ci != _on_planes.end()) {
+      PandaNode *node;
+      DCAST_INTO_R(node, p_list[pi++], pi);
+
+      int ni = areg->find_node(node->get_type(), node->get_name());
+      if (ni != -1) {
+        (*ci) = areg->get_node(ni);
+      } else {
+        (*ci) = NodePath(node);
+      }
+      ++ci;
     }
-    ++ci;
   }
+
+  _off_planes.sort();
   _on_planes.sort();
 
   return pi;
@@ -1073,31 +1091,28 @@ void ClipPlaneAttrib::
 fillin(DatagramIterator &scan, BamReader *manager) {
   RenderAttrib::fillin(scan, manager);
 
-  // We cheat a little bit here.  In the middle of bam version 4.10,
-  // we completely redefined the bam storage definition for
-  // ClipPlaneAttribs, without bothering to up the bam version or even to
-  // attempt to read the old definition.  We get away with this,
-  // knowing that the egg loader doesn't create ClipPlaneAttribs, and
-  // hence no old bam files have the old definition for ClipPlaneAttrib
-  // within them.
-
   _off_all_planes = scan.get_bool();
 
   int num_off_planes = scan.get_uint16();
-    
+
   // Push back an empty NodePath for each off Plane for now, until we
   // get the actual list of pointers later in complete_pointers().
-  _off_planes.reserve(num_off_planes);
-  int i;
-  for (i = 0; i < num_off_planes; i++) {
-    manager->read_pointer(scan);
-    _off_planes.push_back(NodePath());
+  _off_planes.resize(num_off_planes);
+  if (manager->get_file_minor_ver() >= 40) {
+    for (int i = 0; i < num_off_planes; i++) {
+      _off_planes[i].fillin(scan, manager);
+    }
+  } else {
+    manager->read_pointers(scan, num_off_planes);
   }
-    
+
   int num_on_planes = scan.get_uint16();
-  _on_planes.reserve(num_on_planes);
-  for (i = 0; i < num_on_planes; i++) {
-    manager->read_pointer(scan);
-    _on_planes.push_back(NodePath());
+  _on_planes.resize(num_on_planes);
+  if (manager->get_file_minor_ver() >= 40) {
+    for (int i = 0; i < num_on_planes; i++) {
+      manager->read_pointer(scan);
+    }
+  } else {
+    manager->read_pointers(scan, num_on_planes);
   }
 }

+ 30 - 1
panda/src/pgraph/light.I

@@ -45,7 +45,9 @@ CData(const Light::CData &copy) :
 ////////////////////////////////////////////////////////////////////
 INLINE Light::
 Light() :
-  _priority(0)
+  _priority(0),
+  _has_color_temperature(true),
+  _color_temperature(6500)
 {
 }
 
@@ -57,6 +59,8 @@ Light() :
 INLINE Light::
 Light(const Light &copy) :
   _priority(copy._priority),
+  _has_color_temperature(copy._has_color_temperature),
+  _color_temperature(copy._color_temperature),
   _cycler(copy._cycler)
 {
 }
@@ -81,9 +85,34 @@ INLINE void Light::
 set_color(const LColor &color) {
   CDWriter cdata(_cycler);
   cdata->_color = color;
+  _has_color_temperature = false;
   mark_viz_stale();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Light::has_color_temperature
+//       Access: Published
+//  Description: Returns true if the color was specified as a
+//               temperature in kelvins, and get_color_temperature
+//               is defined.
+////////////////////////////////////////////////////////////////////
+INLINE bool Light::
+has_color_temperature() const {
+  return _has_color_temperature;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Light::get_color_temperature
+//       Access: Published
+//  Description: Returns the basic color temperature of the light,
+//               assuming has_color_temperature() returns true.
+////////////////////////////////////////////////////////////////////
+INLINE PN_stdfloat Light::
+get_color_temperature() const {
+  nassertr(_has_color_temperature, _color_temperature);
+  return _color_temperature;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Light::set_priority
 //       Access: Published

+ 80 - 2
panda/src/pgraph/light.cxx

@@ -76,6 +76,70 @@ is_ambient_light() const {
   return false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Light::set_color_temperature
+//       Access: Published
+//  Description: Sets the color temperature of the light in kelvins.
+//               This will recalculate the light's color.
+//
+//               The default value is 6500 K, corresponding to a
+//               perfectly white light assuming a D65 white point.
+////////////////////////////////////////////////////////////////////
+void Light::
+set_color_temperature(PN_stdfloat temperature) {
+  if (_has_color_temperature && _color_temperature == temperature) {
+    return;
+  }
+
+  _has_color_temperature = true;
+  _color_temperature = temperature;
+
+  // Recalculate the color.
+  PN_stdfloat x, y;
+
+  if (temperature == 6500) {
+    // sRGB D65 white point.
+    x = 0.31271;
+    y = 0.32902;
+
+  } else {
+    PN_stdfloat mm = 1000.0 / temperature;
+    PN_stdfloat mm2 = mm * mm;
+    PN_stdfloat mm3 = mm2 * mm;
+
+    if (temperature < 4000) {
+      x = -0.2661239 * mm3 - 0.2343580 * mm2 + 0.8776956 * mm + 0.179910;
+    } else {
+      x = -3.0258469 * mm3 + 2.1070379 * mm2 + 0.2226347 * mm + 0.240390;
+    }
+
+    PN_stdfloat x2 = x * x;
+    PN_stdfloat x3 = x2 * x;
+    if (temperature < 2222) {
+      y = -1.1063814 * x3 - 1.34811020 * x2 + 2.18555832 * x - 0.20219683;
+    } else if (temperature < 4000) {
+      y = -0.9549476 * x3 - 1.37418593 * x2 + 2.09137015 * x - 0.16748867;
+    } else {
+      y =  3.0817580 * x3 - 5.87338670 * x2 + 3.75112997 * x - 0.37001483;
+    }
+  }
+
+  // xyY to XYZ, assuming Y=1.
+  LVecBase3 xyz(x / y, 1, (1 - x - y) / y);
+
+  // Convert XYZ to linearized sRGB.
+  const static LMatrix3 xyz_to_rgb(
+    3.2406255, -0.9689307, 0.0557101,
+    -1.537208, 1.8757561, -0.2040211,
+    -0.4986286, 0.0415175, 1.0569959);
+
+  LColor color(xyz_to_rgb.xform(xyz), 1);
+
+  CDWriter cdata(_cycler);
+  cdata->_color = color;
+  mark_viz_stale();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Light::get_exponent
 //       Access: Public, Virtual
@@ -175,7 +239,12 @@ fill_viz_geom(GeomNode *) {
 ////////////////////////////////////////////////////////////////////
 void Light::
 write_datagram(BamWriter *manager, Datagram &dg) {
-  manager->write_cdata(dg, _cycler);
+  dg.add_bool(_has_color_temperature);
+  if (_has_color_temperature) {
+    dg.add_stdfloat(_color_temperature);
+  } else {
+    manager->write_cdata(dg, _cycler);
+  }
   dg.add_int32(_priority);
 }
 
@@ -188,6 +257,15 @@ write_datagram(BamWriter *manager, Datagram &dg) {
 ////////////////////////////////////////////////////////////////////
 void Light::
 fillin(DatagramIterator &scan, BamReader *manager) {
-  manager->read_cdata(scan, _cycler);
+  if (manager->get_file_minor_ver() >= 39) {
+    _has_color_temperature = scan.get_bool();
+  } else {
+    _has_color_temperature = false;
+  }
+  if (_has_color_temperature) {
+    set_color_temperature(scan.get_stdfloat());
+  } else {
+    manager->read_cdata(scan, _cycler);
+  }
   _priority = scan.get_int32();
 }

+ 11 - 0
panda/src/pgraph/light.h

@@ -52,6 +52,12 @@ PUBLISHED:
   INLINE void set_color(const LColor &color);
   MAKE_PROPERTY(color, get_color, set_color);
 
+  INLINE bool has_color_temperature() const;
+  INLINE PN_stdfloat get_color_temperature() const;
+  void set_color_temperature(PN_stdfloat temperature);
+  MAKE_PROPERTY(color_temperature, get_color_temperature,
+                                   set_color_temperature);
+
   virtual PN_stdfloat get_exponent() const;
   virtual const LColor &get_specular_color() const;
   virtual const LVecBase3 &get_attenuation() const;
@@ -98,6 +104,11 @@ private:
   int _priority;
   static UpdateSeq _sort_seq;
 
+  // The color temperature is not cycled either, because we only need
+  // to pass down the computed color anyway.
+  bool _has_color_temperature;
+  PN_stdfloat _color_temperature;
+
   // This is the data that must be cycled between pipeline stages.
   class EXPCL_PANDA_PGRAPH CData : public CycleData {
   public:

+ 104 - 62
panda/src/pgraph/lightAttrib.cxx

@@ -990,12 +990,7 @@ write_datagram(BamWriter *manager, Datagram &dg) {
   // write the off lights pointers if any
   Lights::const_iterator fi;
   for (fi = _off_lights.begin(); fi != _off_lights.end(); ++fi) {
-    NodePath light = (*fi);
-
-    // Since we can't write out a NodePath, we write out just the
-    // plain PandaNode.  The user can use the AttribNodeRegistry on
-    // re-read if there is any ambiguity that needs to be resolved.
-    manager->write_pointer(dg, light.node());
+    (*fi).write_datagram(manager, dg);
   }
 
   // write the number of on lights
@@ -1003,8 +998,7 @@ write_datagram(BamWriter *manager, Datagram &dg) {
   // write the on lights pointers if any
   Lights::const_iterator nti;
   for (nti = _on_lights.begin(); nti != _on_lights.end(); ++nti) {
-    NodePath light = (*nti);
-    manager->write_pointer(dg, light.node());
+    (*nti).write_datagram(manager, dg);
   }
 }
 
@@ -1019,22 +1013,33 @@ int LightAttrib::
 complete_pointers(TypedWritable **p_list, BamReader *manager) {
   int pi = RenderAttrib::complete_pointers(p_list, manager);
 
-  BamAuxData *aux = (BamAuxData *)manager->get_aux_data(this, "lights");
-  nassertr(aux != NULL, pi);
+  if (manager->get_file_minor_ver() >= 40) {
+    for (int i = 0; i < _off_lights.size(); ++i) {
+      pi += _off_lights[i].complete_pointers(p_list + pi, manager);
+    }
 
-  int i;
-  aux->_off_list.reserve(aux->_num_off_lights);
-  for (i = 0; i < aux->_num_off_lights; ++i) {
-    PandaNode *node;
-    DCAST_INTO_R(node, p_list[pi++], pi);
-    aux->_off_list.push_back(node);
-  }
+    for (int i = 0; i < _on_lights.size(); ++i) {
+      pi += _on_lights[i].complete_pointers(p_list + pi, manager);
+    }
 
-  aux->_on_list.reserve(aux->_num_on_lights);
-  for (i = 0; i < aux->_num_on_lights; ++i) {
-    PandaNode *node;
-    DCAST_INTO_R(node, p_list[pi++], pi);
-    aux->_on_list.push_back(node);
+  } else {
+    BamAuxData *aux = (BamAuxData *)manager->get_aux_data(this, "lights");
+    nassertr(aux != NULL, pi);
+
+    int i;
+    aux->_off_list.reserve(aux->_num_off_lights);
+    for (i = 0; i < aux->_num_off_lights; ++i) {
+      PandaNode *node;
+      DCAST_INTO_R(node, p_list[pi++], pi);
+      aux->_off_list.push_back(node);
+    }
+
+    aux->_on_list.reserve(aux->_num_on_lights);
+    for (i = 0; i < aux->_num_on_lights; ++i) {
+      PandaNode *node;
+      DCAST_INTO_R(node, p_list[pi++], pi);
+      aux->_on_list.push_back(node);
+    }
   }
 
   return pi;
@@ -1049,43 +1054,68 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) {
 ////////////////////////////////////////////////////////////////////
 void LightAttrib::
 finalize(BamReader *manager) {
-  // Now it's safe to convert our saved PandaNodes into NodePaths.
-  BamAuxData *aux = (BamAuxData *)manager->get_aux_data(this, "lights");
-  nassertv(aux != NULL);
-  nassertv(aux->_num_off_lights == (int)aux->_off_list.size());
-  nassertv(aux->_num_on_lights == (int)aux->_on_list.size());
-
-  AttribNodeRegistry *areg = AttribNodeRegistry::get_global_ptr();
-
-  _off_lights.reserve(aux->_off_list.size());
-  NodeList::iterator ni;
-  for (ni = aux->_off_list.begin(); ni != aux->_off_list.end(); ++ni) {
-    PandaNode *node = (*ni);
-    int n = areg->find_node(node->get_type(), node->get_name());
-    if (n != -1) {
-      // If it's in the registry, add that NodePath.
-      _off_lights.push_back(areg->get_node(n));
-    } else {
-      // Otherwise, add any arbitrary NodePath.  Complain if it's
-      // ambiguous.
-      _off_lights.push_back(NodePath(node));
+  if (manager->get_file_minor_ver() >= 40) {
+    AttribNodeRegistry *areg = AttribNodeRegistry::get_global_ptr();
+
+    // Check if any of the nodes we loaded are mentioned in the
+    // AttribNodeRegistry.  If so, replace them.
+    for (int i = 0; i < _off_lights.size(); ++i) {
+      int n = areg->find_node(_off_lights[i]);
+      if (n != -1) {
+        // If it's in the registry, replace it.
+        _off_lights[i] = areg->get_node(n);
+      }
     }
-  }
-  _off_lights.sort();
 
-  _on_lights.reserve(aux->_on_list.size());
-  for (ni = aux->_on_list.begin(); ni != aux->_on_list.end(); ++ni) {
-    PandaNode *node = (*ni);
-    int n = areg->find_node(node->get_type(), node->get_name());
-    if (n != -1) {
-      // If it's in the registry, add that NodePath.
-      _on_lights.push_back(areg->get_node(n));
-    } else {
-      // Otherwise, add any arbitrary NodePath.  Complain if it's
-      // ambiguous.
-      _on_lights.push_back(NodePath(node));
+    for (int i = 0; i < _on_lights.size(); ++i) {
+      int n = areg->find_node(_on_lights[i]);
+      if (n != -1) {
+        // If it's in the registry, replace it.
+        _on_lights[i] = areg->get_node(n);
+      }
+    }
+
+  } else {
+    // Now it's safe to convert our saved PandaNodes into NodePaths.
+    BamAuxData *aux = (BamAuxData *)manager->get_aux_data(this, "lights");
+    nassertv(aux != NULL);
+    nassertv(aux->_num_off_lights == (int)aux->_off_list.size());
+    nassertv(aux->_num_on_lights == (int)aux->_on_list.size());
+
+    AttribNodeRegistry *areg = AttribNodeRegistry::get_global_ptr();
+
+    _off_lights.reserve(aux->_off_list.size());
+    NodeList::iterator ni;
+    for (ni = aux->_off_list.begin(); ni != aux->_off_list.end(); ++ni) {
+      PandaNode *node = (*ni);
+      int n = areg->find_node(node->get_type(), node->get_name());
+      if (n != -1) {
+        // If it's in the registry, add that NodePath.
+        _off_lights.push_back(areg->get_node(n));
+      } else {
+        // Otherwise, add any arbitrary NodePath.  Complain if it's
+        // ambiguous.
+        _off_lights.push_back(NodePath(node));
+      }
+    }
+
+    _on_lights.reserve(aux->_on_list.size());
+    for (ni = aux->_on_list.begin(); ni != aux->_on_list.end(); ++ni) {
+      PandaNode *node = (*ni);
+      int n = areg->find_node(node->get_type(), node->get_name());
+      if (n != -1) {
+        // If it's in the registry, add that NodePath.
+        _on_lights.push_back(areg->get_node(n));
+      } else {
+        // Otherwise, add any arbitrary NodePath.  Complain if it's
+        // ambiguous.
+        _on_lights.push_back(NodePath(node));
+      }
     }
   }
+
+  // Now that the NodePaths have been filled in, we can sort the list.
+  _off_lights.sort();
   _on_lights.sort();
 }
 
@@ -1124,12 +1154,24 @@ fillin(DatagramIterator &scan, BamReader *manager) {
 
   _off_all_lights = scan.get_bool();
 
-  BamAuxData *aux = new BamAuxData;
-  manager->set_aux_data(this, "lights", aux);
+  if (manager->get_file_minor_ver() >= 40) {
+    _off_lights.resize(scan.get_uint16());
+    for (int i = 0; i < _off_lights.size(); ++i) {
+      _off_lights[i].fillin(scan, manager);
+    }
 
-  aux->_num_off_lights = scan.get_uint16();
-  manager->read_pointers(scan, aux->_num_off_lights);
-    
-  aux->_num_on_lights = scan.get_uint16();
-  manager->read_pointers(scan, aux->_num_on_lights);
+    _on_lights.resize(scan.get_uint16());
+    for (int i = 0; i < _on_lights.size(); ++i) {
+      _on_lights[i].fillin(scan, manager);
+    }
+  } else {
+    BamAuxData *aux = new BamAuxData;
+    manager->set_aux_data(this, "lights", aux);
+
+    aux->_num_off_lights = scan.get_uint16();
+    manager->read_pointers(scan, aux->_num_off_lights);
+
+    aux->_num_on_lights = scan.get_uint16();
+    manager->read_pointers(scan, aux->_num_on_lights);
+  }
 }

+ 1 - 1
panda/src/pgraph/loader.cxx

@@ -357,7 +357,7 @@ try_load_file(const Filename &pathname, const LoaderOptions &options,
     if (result != (PandaNode *)NULL) {
       if (record != (BamCacheRecord *)NULL) {
         // Store the loaded model in the model cache.
-        record->set_data(result, result);
+        record->set_data(result);
         cache->store(record);
       }
 

+ 134 - 0
panda/src/pgraph/nodePath.cxx

@@ -6345,6 +6345,10 @@ write_bam_file(const Filename &filename) const {
   bool okflag = false;
 
   if (bam_file.open_write(filename)) {
+    // Tell the BamWriter which node is the root node, for making
+    // NodePaths relative to when writing them out to the file.
+    bam_file.get_writer()->set_root_node(node());
+
     if (bam_file.write_object(node())) {
       okflag = true;
     }
@@ -6368,6 +6372,10 @@ write_bam_stream(ostream &out) const {
   bool okflag = false;
 
   if (bam_file.open_write(out)) {
+    // Tell the BamWriter which node is the root node, for making
+    // NodePaths relative to when writing them out to the file.
+    bam_file.get_writer()->set_root_node(node());
+
     if (bam_file.write_object(node())) {
       okflag = true;
     }
@@ -6434,6 +6442,10 @@ encode_to_bam_stream(string &data, BamWriter *writer) const {
     num_nodes = 1;
   }
 
+  // Tell the BamWriter which node is the root node, for making
+  // NodePaths relative to when writing them out to the file.
+  writer->set_root_node(node());
+
   // Write an initial Datagram to represent the error type and
   // number of nodes.
   Datagram dg;
@@ -7451,3 +7463,125 @@ r_find_all_materials(PandaNode *node, const RenderState *state,
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::write_datagram
+//       Access: Public
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void NodePath::
+write_datagram(BamWriter *manager, Datagram &dg) const {
+  PandaNode *root = DCAST(PandaNode, manager->get_root_node());
+
+  // We have no root node to measure from.
+  if (root == (PandaNode *)NULL || root == node()) {
+    manager->write_pointer(dg, node());
+    manager->write_pointer(dg, NULL);
+    return;
+  }
+
+  Thread *current_thread = Thread::get_current_thread();
+  int pipeline_stage = current_thread->get_pipeline_stage();
+
+  // Record the chain of nodes from the root to this node.
+  pvector<PandaNode *> path;
+  NodePathComponent *comp = _head;
+  while (comp != NULL) {
+    PandaNode *node = comp->get_node();
+    path.push_back(node);
+
+    if (node == root) {
+      break;
+    }
+
+    comp = comp->get_next(pipeline_stage, current_thread);
+  }
+
+  if (comp == (NodePathComponent *)NULL) {
+    // We did not encounter the root node.  Not much we can do.
+    manager->write_pointer(dg, node());
+    manager->write_pointer(dg, NULL);
+    return;
+  }
+
+  // Write out the nodes in reverse order, for fast reconstructing.
+  for (int i = path.size() - 1; i >= 0; --i) {
+    manager->write_pointer(dg, path[i]);
+  }
+  manager->write_pointer(dg, NULL);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::complete_pointers
+//       Access: Public
+//  Description: Receives an array of pointers, one for each time
+//               manager->read_pointer() was called in fillin().
+//               Returns the number of pointers processed.
+////////////////////////////////////////////////////////////////////
+int NodePath::
+complete_pointers(TypedWritable **p_list, BamReader *manager) {
+  int pi = 0;
+  PT(PandaNode) node = DCAST(PandaNode, p_list[pi++]);
+  if (node.is_null()) {
+    // An empty NodePath.
+    _head = (NodePathComponent *)NULL;
+    return pi;
+  }
+
+  Thread *current_thread = Thread::get_current_thread();
+  int pipeline_stage = current_thread->get_pipeline_stage();
+
+  // Take an arbitrary path to the root of the NodePath.  This probably
+  // won't be ambiguous, as this is usually the root of the model or scene
+  // we are currently loading.
+  PT(NodePathComponent) comp = node->get_generic_component(false, pipeline_stage, current_thread);
+  nassertd(!comp.is_null()) {
+    while (p_list[pi++]) {}
+    return pi;
+  }
+
+  // Build up the chain of NodePathComponents leading up to this node.
+  while (p_list[pi] != NULL) {
+    PT(PandaNode) node = DCAST(PandaNode, p_list[pi++]);
+
+    LightReMutexHolder holder(node->_paths_lock);
+
+    // First, walk through the list of NodePathComponents we already
+    // have on the child, looking for one that already exists,
+    // referencing the indicated parent component.
+    PandaNode::Paths::const_iterator it;
+    for (it = node->_paths.begin(); it != node->_paths.end(); ++it) {
+      if ((*it)->get_next(pipeline_stage, current_thread) == comp) {
+        // If we already have such a component, use that.
+        comp = (*it);
+        break;
+      }
+    }
+
+    if (it == node->_paths.end()) {
+      // We don't already have a NodePathComponent referring to this
+      // parent-child relationship.  Create a new one.  Note that we can't
+      // verify that they are actually related because we may not have
+      // completed the node's pointers yet, so we trust that the .bam is right.
+      comp = new NodePathComponent(node, comp, pipeline_stage, current_thread);
+      node->_paths.insert(comp);
+    }
+  }
+  // One more for the final NULL node.
+  ++pi;
+
+  _head = comp;
+  return pi;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::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 NodePath.
+////////////////////////////////////////////////////////////////////
+void NodePath::
+fillin(DatagramIterator &scan, BamReader *manager) {
+  while(manager->read_pointer(scan)) {};
+}

+ 5 - 0
panda/src/pgraph/nodePath.h

@@ -994,6 +994,11 @@ private:
   static PStatCollector _get_transform_pcollector;
   static PStatCollector _verify_complete_pcollector;
 
+public:
+  void write_datagram(BamWriter *manager, Datagram &dg) const;
+  int complete_pointers(TypedWritable **plist, BamReader *manager);
+  void fillin(DatagramIterator &scan, BamReader *manager);
+
 public:
   static TypeHandle get_class_type() {
     return _type_handle;

+ 1 - 0
panda/src/pgraph/nodePathComponent.h

@@ -129,6 +129,7 @@ public:
 private:
   static TypeHandle _type_handle;
   friend class PandaNode;
+  friend class NodePath;
 };
 
 INLINE ostream &operator << (ostream &out, const NodePathComponent &comp);

+ 33 - 18
panda/src/pgraph/occluderEffect.cxx

@@ -169,8 +169,7 @@ write_datagram(BamWriter *manager, Datagram &dg) {
   // write the on occluders pointers if any
   Occluders::const_iterator nti;
   for (nti = _on_occluders.begin(); nti != _on_occluders.end(); ++nti) {
-    NodePath occluder = (*nti);
-    manager->write_pointer(dg, occluder.node());
+    (*nti).write_datagram(manager, dg);
   }
 }
 
@@ -186,19 +185,32 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) {
   int pi = RenderEffect::complete_pointers(p_list, manager);
   AttribNodeRegistry *areg = AttribNodeRegistry::get_global_ptr();
 
-  Occluders::iterator ci;
-  ci = _on_occluders.begin();
-  while (ci != _on_occluders.end()) {
-    PandaNode *node;
-    DCAST_INTO_R(node, p_list[pi++], pi);
+  if (manager->get_file_minor_ver() >= 40) {
+    for (int i = 0; i < _on_occluders.size(); ++i) {
+      pi += _on_occluders[i].complete_pointers(p_list + pi, manager);
 
-    int ni = areg->find_node(node->get_type(), node->get_name());
-    if (ni != -1) {
-      (*ci) = areg->get_node(ni);
-    } else {
-      (*ci) = NodePath(node);
+      int n = areg->find_node(_on_occluders[i]);
+      if (n != -1) {
+        // If it's in the registry, replace it.
+        _on_occluders[i] = areg->get_node(n);
+      }
+    }
+
+  } else {
+    Occluders::iterator ci;
+    ci = _on_occluders.begin();
+    while (ci != _on_occluders.end()) {
+      PandaNode *node;
+      DCAST_INTO_R(node, p_list[pi++], pi);
+
+      int ni = areg->find_node(node->get_type(), node->get_name());
+      if (ni != -1) {
+        (*ci) = areg->get_node(ni);
+      } else {
+        (*ci) = NodePath(node);
+      }
+      ++ci;
     }
-    ++ci;
   }
   _on_occluders.sort();
 
@@ -250,13 +262,16 @@ make_from_bam(const FactoryParams &params) {
 void OccluderEffect::
 fillin(DatagramIterator &scan, BamReader *manager) {
   RenderEffect::fillin(scan, manager);
-    
+
   // Push back an empty NodePath for each Occluder for now, until we
   // get the actual list of pointers later in complete_pointers().
   int num_on_occluders = scan.get_uint16();
-  _on_occluders.reserve(num_on_occluders);
-  for (int i = 0; i < num_on_occluders; i++) {
-    manager->read_pointer(scan);
-    _on_occluders.push_back(NodePath());
+  _on_occluders.resize(num_on_occluders);
+  if (manager->get_file_minor_ver() >= 40) {
+    for (int i = 0; i < num_on_occluders; i++) {
+      _on_occluders[i].fillin(scan, manager);
+    }
+  } else {
+    manager->read_pointers(scan, num_on_occluders);
   }
 }

+ 13 - 11
panda/src/pgraph/paramNodePath.cxx

@@ -48,15 +48,7 @@ register_with_read_factory() {
 void ParamNodePath::
 write_datagram(BamWriter *manager, Datagram &dg) {
   ParamValueBase::write_datagram(manager, dg);
-
-  // We can't store a NodePath, so we store a pointer to the
-  // underlying node, and pray that there is an unambiguous path
-  // from the root to it.
-  if (_node_path.is_empty()) {
-    manager->write_pointer(dg, NULL);
-  } else {
-    manager->write_pointer(dg, _node_path.node());
-  }
+  _node_path.write_datagram(manager, dg);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -69,7 +61,12 @@ write_datagram(BamWriter *manager, Datagram &dg) {
 int ParamNodePath::
 complete_pointers(TypedWritable **p_list, BamReader *manager) {
   int pi = ParamValueBase::complete_pointers(p_list, manager);
-  _node_path = NodePath(DCAST(PandaNode, p_list[pi++]));
+
+  if (manager->get_file_minor_ver() >= 40) {
+    pi += _node_path.complete_pointers(p_list + pi, manager);
+  } else {
+    _node_path = NodePath(DCAST(PandaNode, p_list[pi++]));
+  }
 
   return pi;
 }
@@ -104,5 +101,10 @@ make_from_bam(const FactoryParams &params) {
 void ParamNodePath::
 fillin(DatagramIterator &scan, BamReader *manager) {
   ParamValueBase::fillin(scan, manager);
-  manager->read_pointer(scan);
+
+  if (manager->get_file_minor_ver() >= 40) {
+    _node_path.fillin(scan, manager);
+  } else {
+    manager->read_pointer(scan);
+  }
 }

+ 19 - 3
panda/src/pgraphnodes/directionalLight.I

@@ -43,12 +43,16 @@ CData(const DirectionalLight::CData &copy) :
 //     Function: DirectionalLight::get_specular_color
 //       Access: Public, Final
 //  Description: Returns the color of specular highlights generated by
-//               the light.
+//               the light.  This is usually the same as get_color().
 ////////////////////////////////////////////////////////////////////
 INLINE const LColor &DirectionalLight::
 get_specular_color() const {
-  CDReader cdata(_cycler);
-  return cdata->_specular_color;
+  if (_has_specular_color) {
+    CDReader cdata(_cycler);
+    return cdata->_specular_color;
+  } else {
+    return get_color();
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -60,9 +64,21 @@ get_specular_color() const {
 INLINE void DirectionalLight::
 set_specular_color(const LColor &color) {
   CDWriter cdata(_cycler);
+  _has_specular_color = true;
   cdata->_specular_color = color;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: DirectionalLight::clear_specular_color
+//       Access: Public
+//  Description: Clears a custom specular color setting, meaning that
+//               the specular color will now come from the color.
+////////////////////////////////////////////////////////////////////
+INLINE void DirectionalLight::
+clear_specular_color() {
+  _has_specular_color = false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DirectionalLight::get_point
 //       Access: Public

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