Browse Source

Merge branch 'master' into vulkan

rdb 7 years ago
parent
commit
3cdd77530d
100 changed files with 2077 additions and 468 deletions
  1. 17 1
      direct/src/interval/MetaInterval.py
  2. 1 0
      dtool/src/dtoolutil/pandaSystem.cxx
  3. 7 0
      dtool/src/parser-inc/time.h
  4. 2 1
      dtool/src/parser-inc/unordered_map
  5. 2 1
      dtool/src/parser-inc/unordered_set
  6. 5 0
      makepanda/installer.nsi
  7. 0 1
      makepanda/makepanda.vcproj
  8. 13 9
      panda/src/audiotraits/fmodAudioManager.cxx
  9. 6 11
      panda/src/audiotraits/fmodAudioSound.cxx
  10. 4 3
      panda/src/audiotraits/fmodAudioSound.h
  11. 9 0
      panda/src/bullet/bulletBodyNode.cxx
  12. 16 0
      panda/src/bullet/bulletCapsuleShape.cxx
  13. 4 0
      panda/src/bullet/bulletCapsuleShape.h
  14. 23 0
      panda/src/bullet/bulletPlaneShape.cxx
  15. 3 0
      panda/src/bullet/bulletPlaneShape.h
  16. 9 2
      panda/src/bullet/bulletSoftBodyNode.cxx
  17. 5 4
      panda/src/chan/partBundle.cxx
  18. 134 105
      panda/src/collide/collisionBox.cxx
  19. 7 0
      panda/src/collide/collisionBox.h
  20. 1 1
      panda/src/collide/collisionParabola.cxx
  21. 2 2
      panda/src/collide/collisionPolygon.cxx
  22. 1 1
      panda/src/collide/collisionSegment.cxx
  23. 2 2
      panda/src/collide/collisionSolid.cxx
  24. 144 8
      panda/src/collide/collisionTube.cxx
  25. 8 3
      panda/src/collide/collisionTube.h
  26. 8 0
      panda/src/display/displayRegion.cxx
  27. 42 0
      panda/src/display/graphicsEngine.cxx
  28. 4 1
      panda/src/display/graphicsEngine.h
  29. 0 18
      panda/src/display/test_display.cxx
  30. 1 1
      panda/src/downloader/virtualFileMountHTTP.cxx
  31. 12 5
      panda/src/dxgsg9/dxGeomMunger9.I
  32. 1 1
      panda/src/dxgsg9/wdxGraphicsPipe9.cxx
  33. 162 0
      panda/src/express/pointerTo.I
  34. 34 0
      panda/src/express/pointerTo.h
  35. 48 8
      panda/src/express/pointerToBase.I
  36. 8 0
      panda/src/express/pointerToBase.h
  37. 1 1
      panda/src/express/virtualFileMount.cxx
  38. 2 2
      panda/src/express/weakPointerTo.h
  39. 0 2
      panda/src/express/weakPointerToBase.I
  40. 1 2
      panda/src/express/weakPointerToBase.h
  41. 1 1
      panda/src/ffmpeg/ffmpegVideo.cxx
  42. 2 2
      panda/src/ffmpeg/ffmpegVideoCursor.cxx
  43. 9 1
      panda/src/framework/pandaFramework.cxx
  44. 1 0
      panda/src/framework/pandaFramework.h
  45. 1 1
      panda/src/framework/windowFramework.cxx
  46. 15 8
      panda/src/glstuff/glCgShaderContext_src.cxx
  47. 27 2
      panda/src/glstuff/glGraphicsBuffer_src.cxx
  48. 152 9
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  49. 15 1
      panda/src/glstuff/glGraphicsStateGuardian_src.h
  50. 101 24
      panda/src/glstuff/glShaderContext_src.cxx
  51. 7 0
      panda/src/glstuff/glmisc_src.cxx
  52. 631 31
      panda/src/glstuff/panda_glext.h
  53. 5 0
      panda/src/gobj/geomCacheManager.cxx
  54. 1 1
      panda/src/gobj/geomLines.cxx
  55. 3 3
      panda/src/gobj/geomLinestrips.cxx
  56. 2 2
      panda/src/gobj/geomLinestripsAdjacency.cxx
  57. 2 0
      panda/src/gobj/geomMunger.h
  58. 1 1
      panda/src/gobj/geomPrimitive.cxx
  59. 3 3
      panda/src/gobj/geomTriangles.cxx
  60. 2 2
      panda/src/gobj/geomTrianglesAdjacency.cxx
  61. 2 2
      panda/src/gobj/geomTrifans.cxx
  62. 2 2
      panda/src/gobj/geomTristrips.cxx
  63. 1 1
      panda/src/gobj/internalName_ext.cxx
  64. 1 1
      panda/src/gobj/lens.cxx
  65. 5 0
      panda/src/gobj/perspectiveLens.cxx
  66. 24 8
      panda/src/gobj/shader.cxx
  67. 10 9
      panda/src/gobj/shader.h
  68. 8 4
      panda/src/gobj/shaderBuffer.I
  69. 1 1
      panda/src/gobj/shaderBuffer.cxx
  70. 1 1
      panda/src/gobj/shaderBuffer.h
  71. 18 0
      panda/src/gobj/texture.I
  72. 1 2
      panda/src/gobj/texture.cxx
  73. 1 0
      panda/src/gobj/texture.h
  74. 6 0
      panda/src/gobj/texturePeeker.cxx
  75. 1 1
      panda/src/grutil/cardMaker.cxx
  76. 1 1
      panda/src/grutil/fisheyeMaker.cxx
  77. 1 1
      panda/src/grutil/movieTexture.cxx
  78. 14 3
      panda/src/mathutil/frustum_src.I
  79. 31 0
      panda/src/mathutil/plane_src.I
  80. 3 0
      panda/src/mathutil/plane_src.h
  81. 1 1
      panda/src/pgraph/cacheStats.h
  82. 1 1
      panda/src/pgraph/stateMunger.cxx
  83. 1 1
      panda/src/pgraphnodes/shaderGenerator.cxx
  84. 4 4
      panda/src/pgui/pgFrameStyle.cxx
  85. 13 0
      panda/src/pgui/pgItem.I
  86. 79 54
      panda/src/pgui/pgItem.cxx
  87. 5 3
      panda/src/pgui/pgItem.h
  88. 1 1
      panda/src/speedtree/loaderFileTypeSrt.cxx
  89. 1 1
      panda/src/speedtree/loaderFileTypeStf.cxx
  90. 51 51
      panda/src/text/textAssembler.cxx
  91. 3 3
      panda/src/text/textNode.cxx
  92. 1 1
      panda/src/vision/openCVTexture.cxx
  93. 8 3
      panda/src/wgldisplay/wglGraphicsPipe.cxx
  94. 2 1
      panda/src/wgldisplay/wglGraphicsPipe.h
  95. 6 1
      panda/src/wgldisplay/wglGraphicsStateGuardian.cxx
  96. 5 1
      panda/src/wgldisplay/wglGraphicsWindow.cxx
  97. 4 8
      panda/src/windisplay/winGraphicsWindow.cxx
  98. 22 8
      panda/src/x11display/x11GraphicsWindow.cxx
  99. 4 0
      pandatool/src/maxegg/maxEgg.h
  100. 3 0
      pandatool/src/maxegg/maxEggLoader.cxx

+ 17 - 1
direct/src/interval/MetaInterval.py

@@ -573,7 +573,23 @@ class MetaInterval(CMetaInterval):
             out = ostream
         CMetaInterval.timeline(self, out)
 
-
+    add_sequence = addSequence
+    add_parallel = addParallel
+    add_parallel_end_together = addParallelEndTogether
+    add_track = addTrack
+    add_interval = addInterval
+    set_manager = setManager
+    get_manager = getManager
+    set_t = setT
+    resume_until = resumeUntil
+    clear_to_initial = clearToInitial
+    clear_intervals = clearIntervals
+    set_play_rate = setPlayRate
+    priv_do_event = privDoEvent
+    priv_post_event = privPostEvent
+    set_interval_start_time = setIntervalStartTime
+    get_interval_start_time = getIntervalStartTime
+    get_duration = getDuration
 
 
 class Sequence(MetaInterval):

+ 1 - 0
dtool/src/dtoolutil/pandaSystem.cxx

@@ -435,6 +435,7 @@ write(std::ostream &out) const {
 PandaSystem *PandaSystem::
 get_global_ptr() {
   if (_global_ptr == nullptr) {
+    init_type();
     _global_ptr = new PandaSystem;
   }
 

+ 7 - 0
dtool/src/parser-inc/time.h

@@ -1 +1,8 @@
+#pragma once
+
 #include <stdtypedefs.h>
+
+struct timespec {
+  time_t tv_sec;
+  long tv_nsec;
+};

+ 2 - 1
dtool/src/parser-inc/unordered_map

@@ -24,9 +24,10 @@
 #include <pair>
 #include <initializer_list>
 #include <functional>
+#include <memory>
 
 namespace std {
- 
+
   template <class Key,
     class T,
     class Hash = hash<Key>,

+ 2 - 1
dtool/src/parser-inc/unordered_set

@@ -24,6 +24,7 @@
 #include <pair>
 #include <initializer_list>
 #include <functional>
+#include <memory>
 
 namespace std {
 
@@ -46,7 +47,7 @@ namespace std {
     typedef typename allocator_type::const_reference  const_reference;
     typedef size_t size_type;
     typedef std::ptrdiff_t difference_type;
-   
+
     class iterator;
     class const_iterator;
     class local_iterator;

+ 5 - 0
makepanda/installer.nsi

@@ -1239,8 +1239,13 @@ done:
 
 FunctionEnd
 
+!ifndef LVM_GETITEMCOUNT
 !define LVM_GETITEMCOUNT 0x1004
+!endif
+
+!ifndef LVM_GETITEMTEXT
 !define LVM_GETITEMTEXT 0x102D
+!endif
 
 Function DumpLog
   Exch $5

+ 0 - 1
makepanda/makepanda.vcproj

@@ -1379,7 +1379,6 @@
 				<File RelativePath="..\panda\src\display\windowHandle.h"></File>
 				<File RelativePath="..\panda\src\display\displayRegionCullCallbackData.cxx"></File>
 				<File RelativePath="..\panda\src\display\graphicsOutput.cxx"></File>
-				<File RelativePath="..\panda\src\display\test_display.cxx"></File>
 				<File RelativePath="..\panda\src\display\graphicsBuffer.I"></File>
 				<File RelativePath="..\panda\src\display\stencilRenderStates.cxx"></File>
 				<File RelativePath="..\panda\src\display\stereoDisplayRegion.I"></File>

+ 13 - 9
panda/src/audiotraits/fmodAudioManager.cxx

@@ -419,15 +419,19 @@ get_sound(const std::string &file_name, bool positional, int) {
   VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
   vfs->resolve_filename(path, get_model_path());
 
-  // Build a new AudioSound from the audio data.
-  PT(AudioSound) audioSound;
-  PT(FmodAudioSound) fmodAudioSound = new FmodAudioSound(this, path, positional);
-
-  _all_sounds.insert(fmodAudioSound);
-
-  audioSound = fmodAudioSound;
-
-  return audioSound;
+  // Locate the file on disk.
+  path.set_binary();
+  PT(VirtualFile) file = vfs->get_file(path);
+  if (file != nullptr) {
+    // Build a new AudioSound from the audio data.
+    PT(FmodAudioSound) sound = new FmodAudioSound(this, file, positional);
+
+    _all_sounds.insert(sound);
+    return sound;
+  } else {
+    audio_error("createSound(" << path << "): File not found.");
+    return get_null_sound();
+  }
 }
 
 /**

+ 6 - 11
panda/src/audiotraits/fmodAudioSound.cxx

@@ -39,9 +39,10 @@ TypeHandle FmodAudioSound::_type_handle;
  */
 
 FmodAudioSound::
-FmodAudioSound(AudioManager *manager, Filename file_name, bool positional) {
+FmodAudioSound(AudioManager *manager, VirtualFile *file, bool positional) {
   ReMutexHolder holder(FmodAudioManager::_lock);
-  audio_debug("FmodAudioSound::FmodAudioSound() Creating new sound, filename: " << file_name  );
+  audio_debug("FmodAudioSound::FmodAudioSound() Creating new sound, filename: "
+              << file->get_original_filename());
 
   _active = manager->get_active();
   _paused = false;
@@ -77,20 +78,14 @@ FmodAudioSound(AudioManager *manager, Filename file_name, bool positional) {
   _manager = fmanager;
 
   _channel = 0;
-  _file_name = file_name;
+  _file_name = file->get_original_filename();
   _file_name.set_binary();
 
   // Get the Speaker Mode [Important for later on.]
   result = _manager->_system->getSpeakerMode( &_speakermode );
   fmod_audio_errcheck("_system->getSpeakerMode()", result);
 
-  VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
-  PT(VirtualFile) file = vfs->get_file(_file_name);
-  if (file == nullptr) {
-    // File not found.  We will display the appropriate error message below.
-    result = FMOD_ERR_FILE_NOTFOUND;
-
-  } else {
+  {
     bool preload = (fmod_audio_preload_threshold < 0) || (file->get_file_size() < fmod_audio_preload_threshold);
     int flags = FMOD_SOFTWARE;
     flags |= positional ? FMOD_3D : FMOD_2D;
@@ -149,7 +144,7 @@ FmodAudioSound(AudioManager *manager, Filename file_name, bool positional) {
 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
       // Otherwise, if the Panda threading system is compiled in, we can
       // assign callbacks to read the file through the VFS.
-      name_or_data = (const char *)file.p();
+      name_or_data = (const char *)file;
       sound_info.length = (unsigned int)info.get_size();
       sound_info.useropen = open_callback;
       sound_info.userclose = close_callback;

+ 4 - 3
panda/src/audiotraits/fmodAudioSound.h

@@ -70,10 +70,11 @@
 #include <fmod.hpp>
 #include <fmod_errors.h>
 
-class EXPCL_FMOD_AUDIO FmodAudioSound : public AudioSound {
- public:
+class VirtualFile;
 
-  FmodAudioSound(AudioManager *manager, Filename fn, bool positional );
+class EXPCL_FMOD_AUDIO FmodAudioSound : public AudioSound {
+public:
+  FmodAudioSound(AudioManager *manager, VirtualFile *file, bool positional);
   ~FmodAudioSound();
 
   // For best compatibility, set the loop_count, start_time, volume, and

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

@@ -20,6 +20,7 @@
 #include "collisionPlane.h"
 #include "collisionSphere.h"
 #include "collisionPolygon.h"
+#include "collisionTube.h"
 
 TypeHandle BulletBodyNode::_type_handle;
 
@@ -804,6 +805,14 @@ add_shapes_from_collision_solids(CollisionNode *cnode) {
       do_add_shape(BulletBoxShape::make_from_solid(box), ts);
     }
 
+    // CollisionTube
+    else if (CollisionTube::get_class_type() == type) {
+      CPT(CollisionTube) tube = DCAST(CollisionTube, solid);
+      CPT(TransformState) ts = TransformState::make_pos((tube->get_point_b() + tube->get_point_a()) / 2.0);
+
+      do_add_shape(BulletCapsuleShape::make_from_solid(tube), ts);
+    }
+
     // CollisionPlane
     else if (CollisionPlane::get_class_type() == type) {
       CPT(CollisionPlane) plane = DCAST(CollisionPlane, solid);

+ 16 - 0
panda/src/bullet/bulletCapsuleShape.cxx

@@ -82,6 +82,22 @@ ptr() const {
   return _shape;
 }
 
+
+/**
+ * Constructs a new BulletCapsuleShape using the information from a
+ * CollisionTube from the builtin collision system.
+ */
+BulletCapsuleShape *BulletCapsuleShape::
+make_from_solid(const CollisionTube *solid) {
+  
+  PN_stdfloat radius = solid->get_radius();
+  // CollisionTube height includes the hemispheres, Bullet only wants the cylinder height.
+  PN_stdfloat height = (solid->get_point_b() - solid->get_point_a()).length() - (radius * 2);
+
+  // CollisionTubes are always Z-Up.
+  return new BulletCapsuleShape(radius, height, Z_up);
+}
+
 /**
  * Tells the BamReader how to create objects of type BulletShape.
  */

+ 4 - 0
panda/src/bullet/bulletCapsuleShape.h

@@ -20,6 +20,8 @@
 #include "bullet_utils.h"
 #include "bulletShape.h"
 
+#include "collisionTube.h"
+
 /**
  *
  */
@@ -33,6 +35,8 @@ PUBLISHED:
   BulletCapsuleShape(const BulletCapsuleShape &copy);
   INLINE ~BulletCapsuleShape();
 
+  static BulletCapsuleShape *make_from_solid(const CollisionTube *solid);
+
   INLINE PN_stdfloat get_radius() const;
   INLINE PN_stdfloat get_half_height() const;
 

+ 23 - 0
panda/src/bullet/bulletPlaneShape.cxx

@@ -15,6 +15,18 @@
 
 TypeHandle BulletPlaneShape::_type_handle;
 
+/**
+ * Creates a plane shape from a plane definition.
+ */
+BulletPlaneShape::
+BulletPlaneShape(LPlane plane) {
+
+  btVector3 btNormal = LVecBase3_to_btVector3(plane.get_normal());
+
+  _shape = new btStaticPlaneShape(btNormal, plane.get_w());
+  _shape->setUserPointer(this);
+}
+
 /**
  *
  */
@@ -50,6 +62,17 @@ ptr() const {
   return _shape;
 }
 
+/**
+ *
+ */
+LPlane BulletPlaneShape::
+get_plane() const {
+  LightMutexHolder holder(BulletWorld::get_global_lock());
+
+  btVector3 normal = _shape->getPlaneNormal();
+  return LPlane(normal[0], normal[1], normal[2], (PN_stdfloat)_shape->getPlaneConstant());
+}
+
 /**
  *
  */

+ 3 - 0
panda/src/bullet/bulletPlaneShape.h

@@ -32,15 +32,18 @@ private:
   INLINE BulletPlaneShape() : _shape(nullptr) {};
 
 PUBLISHED:
+  explicit BulletPlaneShape(LPlane plane);
   explicit BulletPlaneShape(const LVector3 &normal, PN_stdfloat constant);
   BulletPlaneShape(const BulletPlaneShape &copy);
   INLINE ~BulletPlaneShape();
 
+  LPlane get_plane() const;
   LVector3 get_plane_normal() const;
   PN_stdfloat get_plane_constant() const;
 
   static BulletPlaneShape *make_from_solid(const CollisionPlane *solid);
 
+  MAKE_PROPERTY(plane, get_plane);
   MAKE_PROPERTY(plane_normal, get_plane_normal);
   MAKE_PROPERTY(plane_constant, get_plane_constant);
 

+ 9 - 2
panda/src/bullet/bulletSoftBodyNode.cxx

@@ -276,8 +276,15 @@ do_sync_b2p() {
 
   // Update the synchronized transform with the current approximate center of
   // the soft body
-  LVecBase3 pos = this->do_get_aabb().get_approx_center();
-  CPT(TransformState) ts = TransformState::make_pos(pos);
+  btVector3 pMin, pMax;
+  _soft->getAabb(pMin, pMax);
+  LPoint3 pos = (btVector3_to_LPoint3(pMin) + btVector3_to_LPoint3(pMax)) * 0.5;
+  CPT(TransformState) ts;
+  if (!pos.is_nan()) {
+    ts = TransformState::make_pos(pos);
+  } else {
+    ts = TransformState::make_identity();
+  }
 
   NodePath np = NodePath::any_path((PandaNode *)this);
   LVecBase3 scale = np.get_net_transform()->get_scale();

+ 5 - 4
panda/src/chan/partBundle.cxx

@@ -154,10 +154,11 @@ apply_transform(const TransformState *transform) {
 
   AppliedTransforms::iterator ati = _applied_transforms.find(transform);
   if (ati != _applied_transforms.end()) {
-    if ((*ati).first.is_valid_pointer() &&
-        (*ati).second.is_valid_pointer()) {
-      // Here's our cached result.
-      return (*ati).second.lock();
+    if ((*ati).first.is_valid_pointer()) {
+      if (auto new_bundle = (*ati).second.lock()) {
+        // Here's our cached result.
+        return new_bundle;
+      }
     }
   }
 

+ 134 - 105
panda/src/collide/collisionBox.cxx

@@ -398,6 +398,49 @@ test_intersection_from_sphere(const CollisionEntry &entry) const {
   return new_entry;
 }
 
+/**
+ *
+ */
+PT(CollisionEntry) CollisionBox::
+test_intersection_from_line(const CollisionEntry &entry) const {
+  const CollisionLine *line;
+  DCAST_INTO_R(line, entry.get_from(), nullptr);
+
+  const LMatrix4 &wrt_mat = entry.get_wrt_mat();
+
+  LPoint3 from_origin = line->get_origin() * wrt_mat;
+  LVector3 from_direction = line->get_direction() * wrt_mat;
+
+  double t1, t2;
+  if (!intersects_line(t1, t2, from_origin, from_direction)) {
+    // No intersection.
+    return nullptr;
+  }
+
+  if (collide_cat.is_debug()) {
+    collide_cat.debug()
+      << "intersection detected from " << entry.get_from_node_path()
+      << " into " << entry.get_into_node_path() << "\n";
+  }
+  PT(CollisionEntry) new_entry = new CollisionEntry(entry);
+
+  LPoint3 point = from_origin + t1 * from_direction;
+  new_entry->set_surface_point(point);
+
+  if (has_effective_normal() && line->get_respect_effective_normal()) {
+    new_entry->set_surface_normal(get_effective_normal());
+  } else {
+    LVector3 normal(
+      IS_NEARLY_EQUAL(point[0], _max[0]) - IS_NEARLY_EQUAL(point[0], _min[0]),
+      IS_NEARLY_EQUAL(point[1], _max[1]) - IS_NEARLY_EQUAL(point[1], _min[1]),
+      IS_NEARLY_EQUAL(point[2], _max[2]) - IS_NEARLY_EQUAL(point[2], _min[2])
+    );
+    normal.normalize();
+    new_entry->set_surface_normal(normal);
+  }
+
+  return new_entry;
+}
 
 /**
  * Double dispatch point for ray as a FROM object
@@ -411,51 +454,9 @@ test_intersection_from_ray(const CollisionEntry &entry) const {
   LPoint3 from_origin = ray->get_origin() * wrt_mat;
   LVector3 from_direction = ray->get_direction() * wrt_mat;
 
-  int i, j;
-  PN_stdfloat t;
-  PN_stdfloat near_t = 0.0;
-  bool intersect;
-  LPlane plane;
-  LPlane near_plane;
-
-  // Returns the details about the first plane of the box that the ray
-  // intersects.
-  for (i = 0, intersect = false, t = 0, j = 0; i < 6 && j < 2; i++) {
-    plane = get_plane(i);
-
-    if (!plane.intersects_line(t, from_origin, from_direction)) {
-      // No intersection.  The ray is parallel to the plane.
-      continue;
-    }
-
-    if (t < 0.0f) {
-      // The intersection point is before the start of the ray, and so the ray
-      // is entirely in front of the plane.
-      continue;
-    }
-    LPoint3 plane_point = from_origin + t * from_direction;
-    LPoint2 p = to_2d(plane_point, i);
-
-    if (!point_is_inside(p, _points[i])){
-      continue;
-    }
-    intersect = true;
-    if (j) {
-      if(t < near_t) {
-        near_plane = plane;
-        near_t = t;
-      }
-    }
-    else {
-      near_plane = plane;
-      near_t = t;
-    }
-    ++j;
-  }
-
-
-  if(!intersect) {
-    // No intersection with ANY of the box's planes has been detected
+  double t1, t2;
+  if (!intersects_line(t1, t2, from_origin, from_direction) || (t1 < 0.0 && t2 < 0.0)) {
+    // No intersection.
     return nullptr;
   }
 
@@ -464,22 +465,32 @@ test_intersection_from_ray(const CollisionEntry &entry) const {
       << "intersection detected from " << entry.get_from_node_path()
       << " into " << entry.get_into_node_path() << "\n";
   }
-
   PT(CollisionEntry) new_entry = new CollisionEntry(entry);
 
-  LPoint3 into_intersection_point = from_origin + near_t * from_direction;
+  if (t1 < 0.0) {
+    // The origin is inside the box, so we take the exit as our surface point.
+    new_entry->set_interior_point(from_origin);
+    t1 = t2;
+  }
 
-  LVector3 normal =
-    (has_effective_normal() && ray->get_respect_effective_normal())
-    ? get_effective_normal() : near_plane.get_normal();
+  LPoint3 point = from_origin + t1 * from_direction;
+  new_entry->set_surface_point(point);
 
-  new_entry->set_surface_normal(normal);
-  new_entry->set_surface_point(into_intersection_point);
+  if (has_effective_normal() && ray->get_respect_effective_normal()) {
+    new_entry->set_surface_normal(get_effective_normal());
+  } else {
+    LVector3 normal(
+      IS_NEARLY_EQUAL(point[0], _max[0]) - IS_NEARLY_EQUAL(point[0], _min[0]),
+      IS_NEARLY_EQUAL(point[1], _max[1]) - IS_NEARLY_EQUAL(point[1], _min[1]),
+      IS_NEARLY_EQUAL(point[2], _max[2]) - IS_NEARLY_EQUAL(point[2], _min[2])
+    );
+    normal.normalize();
+    new_entry->set_surface_normal(normal);
+  }
 
   return new_entry;
 }
 
-
 /**
  * Double dispatch point for segment as a FROM object
  */
@@ -493,51 +504,10 @@ test_intersection_from_segment(const CollisionEntry &entry) const {
   LPoint3 from_extent = seg->get_point_b() * wrt_mat;
   LVector3 from_direction = from_extent - from_origin;
 
-  int i, j;
-  PN_stdfloat t;
-  PN_stdfloat near_t = 0.0;
-  bool intersect;
-  LPlane plane;
-  LPlane near_plane;
-
-  // Returns the details about the first plane of the box that the segment
-  // intersects.
-  for(i = 0, intersect = false, t = 0, j = 0; i < 6 && j < 2; i++) {
-    plane = get_plane(i);
-
-    if (!plane.intersects_line(t, from_origin, from_direction)) {
-      // No intersection.  The segment is parallel to the plane.
-      continue;
-    }
-
-    if (t < 0.0f || t > 1.0f) {
-      // The intersection point is before the start of the segment, or after
-      // the end of the segment, so the segment is either entirely in front of
-      // or behind the plane.
-      continue;
-    }
-    LPoint3 plane_point = from_origin + t * from_direction;
-    LPoint2 p = to_2d(plane_point, i);
-
-    if (!point_is_inside(p, _points[i])){
-      continue;
-    }
-    intersect = true;
-    if(j) {
-      if(t < near_t) {
-        near_plane = plane;
-        near_t = t;
-      }
-    }
-    else {
-      near_plane = plane;
-      near_t = t;
-    }
-    ++j;
-  }
-
-  if(!intersect) {
-    // No intersection with ANY of the box's planes has been detected
+  double t1, t2;
+  if (!intersects_line(t1, t2, from_origin, from_direction) ||
+      (t1 < 0.0 && t2 < 0.0) || (t1 > 1.0 && t2 > 1.0)) {
+    // No intersection.
     return nullptr;
   }
 
@@ -546,17 +516,31 @@ test_intersection_from_segment(const CollisionEntry &entry) const {
       << "intersection detected from " << entry.get_from_node_path()
       << " into " << entry.get_into_node_path() << "\n";
   }
-
   PT(CollisionEntry) new_entry = new CollisionEntry(entry);
 
-  LPoint3 into_intersection_point = from_origin + near_t * from_direction;
+  // In case the segment is entirely inside the cube, we consider the point
+  // closest to the surface as our entry point.
+  if (t1 < (1.0 - t2)) {
+    std::swap(t1, t2);
+  }
+
+  // Our interior point is the closest point to t2 that is inside the segment.
+  new_entry->set_interior_point(from_origin + std::min(std::max(t2, 0.0), 1.0) * from_direction);
 
-  LVector3 normal =
-    (has_effective_normal() && seg->get_respect_effective_normal())
-    ? get_effective_normal() : near_plane.get_normal();
+  LPoint3 point = from_origin + t1 * from_direction;
+  new_entry->set_surface_point(point);
 
-  new_entry->set_surface_normal(normal);
-  new_entry->set_surface_point(into_intersection_point);
+  if (has_effective_normal() && seg->get_respect_effective_normal()) {
+    new_entry->set_surface_normal(get_effective_normal());
+  } else {
+    LVector3 normal(
+      IS_NEARLY_EQUAL(point[0], _max[0]) - IS_NEARLY_EQUAL(point[0], _min[0]),
+      IS_NEARLY_EQUAL(point[1], _max[1]) - IS_NEARLY_EQUAL(point[1], _min[1]),
+      IS_NEARLY_EQUAL(point[2], _max[2]) - IS_NEARLY_EQUAL(point[2], _min[2])
+    );
+    normal.normalize();
+    new_entry->set_surface_normal(normal);
+  }
 
   return new_entry;
 }
@@ -823,6 +807,51 @@ fill_viz_geom() {
   _bounds_viz_geom->add_geom(geom, get_solid_bounds_viz_state());
 }
 
+/**
+ * Determine the point(s) of intersection of a parametric line with the box.
+ * The line is infinite in both directions, and passes through "from" and
+ * from+delta.  If the line does not intersect the box, the function returns
+ * false, and t1 and t2 are undefined.  If it does intersect the box, it
+ * returns true, and t1 and t2 are set to the points along the equation
+ * from+t*delta that correspond to the two points of intersection.
+ */
+bool CollisionBox::
+intersects_line(double &t1, double &t2,
+                const LPoint3 &from, const LVector3 &delta,
+                PN_stdfloat inflate_size) const {
+
+  LPoint3 bmin = _min - LVector3(inflate_size);
+  LPoint3 bmax = _max + LVector3(inflate_size);
+
+  double tmin = -DBL_MAX;
+  double tmax = DBL_MAX;
+
+  for (int i = 0; i < 3; ++i) {
+    PN_stdfloat d = delta[i];
+    if (!IS_NEARLY_ZERO(d)) {
+      double tmin2 = (bmin[i] - from[i]) / d;
+      double tmax2 = (bmax[i] - from[i]) / d;
+      if (tmin2 > tmax2) {
+        std::swap(tmin2, tmax2);
+      }
+      tmin = std::max(tmin, tmin2);
+      tmax = std::min(tmax, tmax2);
+
+      if (tmin > tmax) {
+        return false;
+      }
+
+    } else if (from[i] < bmin[i] || from[i] > bmax[i]) {
+      // The line is entirely parallel in this dimension.
+      return false;
+    }
+  }
+
+  t1 = tmin;
+  t2 = tmax;
+  return true;
+}
+
 /**
  * Clips the polygon by all of the clip planes named in the clip plane
  * attribute and fills new_points up with the resulting points.

+ 7 - 0
panda/src/collide/collisionBox.h

@@ -75,6 +75,8 @@ protected:
   virtual PT(BoundingVolume) compute_internal_bounds() const;
   virtual PT(CollisionEntry)
     test_intersection_from_sphere(const CollisionEntry &entry) const;
+  virtual PT(CollisionEntry)
+    test_intersection_from_line(const CollisionEntry &entry) const;
   virtual PT(CollisionEntry)
     test_intersection_from_ray(const CollisionEntry &entry) const;
   virtual PT(CollisionEntry)
@@ -84,6 +86,11 @@ protected:
 
   virtual void fill_viz_geom();
 
+protected:
+  bool intersects_line(double &t1, double &t2,
+                       const LPoint3 &from, const LVector3 &delta,
+                       PN_stdfloat inflate_size=0) const;
+
 private:
   LPoint3 _center;
   LPoint3 _min;

+ 1 - 1
panda/src/collide/collisionParabola.cxx

@@ -157,7 +157,7 @@ compute_internal_bounds() const {
                            LPoint3(0.01, 0, max_z), LPoint3(-0.01, 0, max_z));
   // And convert that back into real space.
   volume->xform(from_parabola);
-  return volume.p();
+  return volume;
 }
 
 /**

+ 2 - 2
panda/src/collide/collisionPolygon.cxx

@@ -271,9 +271,9 @@ get_viz(const CullTraverser *trav, const CullTraverserData &data,
   draw_polygon(viz_geom_node, bounds_viz_geom_node, new_points);
 
   if (bounds_only) {
-    return bounds_viz_geom_node.p();
+    return bounds_viz_geom_node;
   } else {
-    return viz_geom_node.p();
+    return viz_geom_node;
   }
 }
 

+ 1 - 1
panda/src/collide/collisionSegment.cxx

@@ -131,7 +131,7 @@ compute_internal_bounds() const {
                            LPoint3(0.01, -0.01, 0.01), LPoint3(-0.01, -0.01, 0.01));
 
   volume->xform(from_segment);
-  return volume.p();
+  return volume;
 }
 
 /**

+ 2 - 2
panda/src/collide/collisionSolid.cxx

@@ -146,9 +146,9 @@ get_viz(const CullTraverser *, const CullTraverserData &, bool bounds_only) cons
   }
 
   if (bounds_only) {
-    return _bounds_viz_geom.p();
+    return _bounds_viz_geom;
   } else {
-    return _viz_geom.p();
+    return _viz_geom;
   }
 }
 

+ 144 - 8
panda/src/collide/collisionTube.cxx

@@ -391,6 +391,70 @@ test_intersection_from_segment(const CollisionEntry &entry) const {
   return new_entry;
 }
 
+/**
+ *
+ */
+PT(CollisionEntry) CollisionTube::
+test_intersection_from_tube(const CollisionEntry &entry) const {
+  const CollisionTube *tube;
+  DCAST_INTO_R(tube, entry.get_from(), nullptr);
+
+  LPoint3 into_a = _a;
+  LVector3 into_direction = _b - into_a;
+
+  const LMatrix4 &wrt_mat = entry.get_wrt_mat();
+
+  LPoint3 from_a = tube->get_point_a() * wrt_mat;
+  LPoint3 from_b = tube->get_point_b() * wrt_mat;
+  LVector3 from_direction = from_b - from_a;
+
+  LVector3 from_radius_v =
+    LVector3(tube->get_radius(), 0.0f, 0.0f) * wrt_mat;
+  PN_stdfloat from_radius = length(from_radius_v);
+
+  // Determine the points on each segment with the smallest distance between.
+  double into_t, from_t;
+  calc_closest_segment_points(into_t, from_t,
+                              into_a, into_direction,
+                              from_a, from_direction);
+  LPoint3 into_closest = into_a + into_direction * into_t;
+  LPoint3 from_closest = from_a + from_direction * from_t;
+
+  // If the distance is greater than the sum of tube radii, the test fails.
+  LVector3 closest_vec = from_closest - into_closest;
+  PN_stdfloat distance = closest_vec.length();
+  if (distance > _radius + from_radius) {
+    return nullptr;
+  }
+
+  if (collide_cat.is_debug()) {
+    collide_cat.debug()
+      << "intersection detected from " << entry.get_from_node_path()
+      << " into " << entry.get_into_node_path() << "\n";
+  }
+  PT(CollisionEntry) new_entry = new CollisionEntry(entry);
+
+  if (distance != 0) {
+    // This is the most common case, where the line segments don't touch
+    // exactly.  We point the normal along the vector of the closest distance.
+    LVector3 surface_normal = closest_vec * (1.0 / distance);
+
+    new_entry->set_surface_point(into_closest + surface_normal * _radius);
+    new_entry->set_interior_point(from_closest - surface_normal * from_radius);
+
+    if (has_effective_normal() && tube->get_respect_effective_normal()) {
+      new_entry->set_surface_normal(get_effective_normal());
+    } else if (distance != 0) {
+      new_entry->set_surface_normal(surface_normal);
+    }
+  } else {
+    // The rare case of the line segments touching exactly.
+    set_intersection_point(new_entry, into_closest, 0);
+  }
+
+  return new_entry;
+}
+
 /**
  *
  */
@@ -578,6 +642,80 @@ calc_sphere2_vertex(int ri, int si, int num_rings, int num_slices,
   return LVertex(x, y, z);
 }
 
+/**
+ * Given line segments s1 and s2 defined by two points each, computes the
+ * point on each segment with the closest distance between them.
+ */
+void CollisionTube::
+calc_closest_segment_points(double &t1, double &t2,
+                            const LPoint3 &from1, const LVector3 &delta1,
+                            const LPoint3 &from2, const LVector3 &delta2) {
+  // Copyright 2001 softSurfer, 2012 Dan Sunday
+  // This code may be freely used, distributed and modified for any purpose
+  // providing that this copyright notice is included with it.
+  // SoftSurfer makes no warranty for this code, and cannot be held
+  // liable for any real or imagined damage resulting from its use.
+  // Users of this code must verify correctness for their application.
+  LVector3 w = from1 - from2;
+  PN_stdfloat a = delta1.dot(delta1); // always >= 0
+  PN_stdfloat b = delta1.dot(delta2);
+  PN_stdfloat c = delta2.dot(delta2); // always >= 0
+  PN_stdfloat d = delta1.dot(w);
+  PN_stdfloat e = delta2.dot(w);
+  PN_stdfloat D = a * c - b * b; // always >= 0
+  PN_stdfloat sN, sD = D;
+  PN_stdfloat tN, tD = D;
+
+  // compute the line parameters of the two closest points
+  if (IS_NEARLY_ZERO(D)) { // the lines are almost parallel
+    sN = 0.0; // force using point P0 on segment S1
+    sD = 1.0; // to prevent possible division by 0.0 later
+    tN = e;
+    tD = c;
+  } else {
+    // get the closest points on the infinite lines
+    sN = (b*e - c*d);
+    tN = (a*e - b*d);
+    if (sN < 0.0) { // sc < 0 => the s=0 edge is visible
+      sN = 0.0;
+      tN = e;
+      tD = c;
+    } else if (sN > sD) { // sc > 1  => the s=1 edge is visible
+      sN = sD;
+      tN = e + b;
+      tD = c;
+    }
+  }
+
+  if (tN < 0.0) { // tc < 0 => the t=0 edge is visible
+    tN = 0.0;
+    // recompute sc for this edge
+    if (-d < 0.0) {
+      sN = 0.0;
+    } else if (-d > a) {
+      sN = sD;
+    } else {
+      sN = -d;
+      sD = a;
+    }
+  } else if (tN > tD) { // tc > 1  => the t=1 edge is visible
+    tN = tD;
+    // recompute sc for this edge
+    if ((-d + b) < 0.0) {
+      sN = 0;
+    } else if ((-d + b) > a) {
+      sN = sD;
+    } else {
+      sN = (-d +  b);
+      sD = a;
+    }
+  }
+
+  // finally do the division to get sc and tc
+  t1 = (IS_NEARLY_ZERO(sN) ? 0.0 : sN / sD);
+  t2 = (IS_NEARLY_ZERO(tN) ? 0.0 : tN / tD);
+}
+
 /**
  * Determine the point(s) of intersection of a parametric line with the tube.
  * The line is infinite in both directions, and passes through "from" and
@@ -692,7 +830,7 @@ intersects_line(double &t1, double &t2,
     // The starting point is off the bottom of the tube.  Test the line
     // against the first endcap.
     double t1a, t2a;
-    if (!sphere_intersects_line(t1a, t2a, 0.0f, from, delta, inflate_radius)) {
+    if (!sphere_intersects_line(t1a, t2a, 0.0f, from, delta, radius)) {
       // If there's no intersection with the endcap, there can't be an
       // intersection with the cylinder.
       return false;
@@ -703,7 +841,7 @@ intersects_line(double &t1, double &t2,
     // The starting point is off the top of the tube.  Test the line against
     // the second endcap.
     double t1b, t2b;
-    if (!sphere_intersects_line(t1b, t2b, _length, from, delta, inflate_radius)) {
+    if (!sphere_intersects_line(t1b, t2b, _length, from, delta, radius)) {
       // If there's no intersection with the endcap, there can't be an
       // intersection with the cylinder.
       return false;
@@ -715,7 +853,7 @@ intersects_line(double &t1, double &t2,
     // The ending point is off the bottom of the tube.  Test the line against
     // the first endcap.
     double t1a, t2a;
-    if (!sphere_intersects_line(t1a, t2a, 0.0f, from, delta, inflate_radius)) {
+    if (!sphere_intersects_line(t1a, t2a, 0.0f, from, delta, radius)) {
       // If there's no intersection with the endcap, there can't be an
       // intersection with the cylinder.
       return false;
@@ -726,7 +864,7 @@ intersects_line(double &t1, double &t2,
     // The ending point is off the top of the tube.  Test the line against the
     // second endcap.
     double t1b, t2b;
-    if (!sphere_intersects_line(t1b, t2b, _length, from, delta, inflate_radius)) {
+    if (!sphere_intersects_line(t1b, t2b, _length, from, delta, radius)) {
       // If there's no intersection with the endcap, there can't be an
       // intersection with the cylinder.
       return false;
@@ -740,16 +878,14 @@ intersects_line(double &t1, double &t2,
 /**
  * After confirming that the line intersects an infinite cylinder, test
  * whether it intersects one or the other endcaps.  The y parameter specifies
- * the center of the sphere (and hence the particular endcap.
+ * the center of the sphere (and hence the particular endcap).
  */
 bool CollisionTube::
 sphere_intersects_line(double &t1, double &t2, PN_stdfloat center_y,
                        const LPoint3 &from, const LVector3 &delta,
-                       PN_stdfloat inflate_radius) const {
+                       PN_stdfloat radius) {
   // See CollisionSphere::intersects_line() for a derivation of the formula
   // here.
-  PN_stdfloat radius = _radius + inflate_radius;
-
   double A = dot(delta, delta);
 
   nassertr(A != 0.0, false);

+ 8 - 3
panda/src/collide/collisionTube.h

@@ -82,6 +82,8 @@ protected:
   virtual PT(CollisionEntry)
   test_intersection_from_segment(const CollisionEntry &entry) const;
   virtual PT(CollisionEntry)
+  test_intersection_from_tube(const CollisionEntry &entry) const;
+  virtual PT(CollisionEntry)
   test_intersection_from_parabola(const CollisionEntry &entry) const;
 
   virtual void fill_viz_geom();
@@ -93,12 +95,15 @@ private:
   LVertex calc_sphere2_vertex(int ri, int si, int num_rings, int num_slices,
                               PN_stdfloat length);
 
+  static void calc_closest_segment_points(double &t1, double &t2,
+                                          const LPoint3 &from1, const LVector3 &delta1,
+                                          const LPoint3 &from2, const LVector3 &delta2);
   bool intersects_line(double &t1, double &t2,
                        const LPoint3 &from, const LVector3 &delta,
                        PN_stdfloat inflate_radius) const;
-  bool sphere_intersects_line(double &t1, double &t2, PN_stdfloat center_y,
-                              const LPoint3 &from, const LVector3 &delta,
-                              PN_stdfloat inflate_radius) const;
+  static bool sphere_intersects_line(double &t1, double &t2, PN_stdfloat center_y,
+                                     const LPoint3 &from, const LVector3 &delta,
+                                     PN_stdfloat radius);
   bool intersects_parabola(double &t, const LParabola &parabola,
                            double t1, double t2,
                            const LPoint3 &p1, const LPoint3 &p2) const;

+ 8 - 0
panda/src/display/displayRegion.cxx

@@ -483,6 +483,14 @@ get_screenshot() {
   GraphicsStateGuardian *gsg = window->get_gsg();
   nassertr(gsg != nullptr, nullptr);
 
+  // Are we on the draw thread?
+  if (gsg->get_threading_model().get_draw_stage() != current_thread->get_pipeline_stage()) {
+    // Ask the engine to do on the draw thread.
+    GraphicsEngine *engine = window->get_engine();
+    return engine->do_get_screenshot(this, gsg);
+  }
+
+  // We are on the draw thread.
   if (!window->begin_frame(GraphicsOutput::FM_refresh, current_thread)) {
     return nullptr;
   }

+ 42 - 0
panda/src/display/graphicsEngine.cxx

@@ -1249,6 +1249,43 @@ texture_uploaded(Texture *tex) {
 // Usually only called by DisplayRegion::do_cull.
 }
 
+/**
+ * Called by DisplayRegion::do_get_screenshot
+ */
+PT(Texture) GraphicsEngine::
+do_get_screenshot(DisplayRegion *region, GraphicsStateGuardian *gsg) {
+  // A multi-threaded environment.  We have to wait until the draw thread
+  // has finished its current task.
+
+  ReMutexHolder holder(_lock);
+
+  const std::string &draw_name = gsg->get_threading_model().get_draw_name();
+  WindowRenderer *wr = get_window_renderer(draw_name, 0);
+  RenderThread *thread = (RenderThread *)wr;
+  MutexHolder cv_holder(thread->_cv_mutex);
+
+  while (thread->_thread_state != TS_wait) {
+    thread->_cv_done.wait();
+  }
+
+  // Now that the draw thread is idle, signal it to do the extraction task.
+  thread->_region = region;
+  thread->_thread_state = TS_do_screenshot;
+  thread->_cv_start.notify();
+  thread->_cv_mutex.release();
+  thread->_cv_mutex.acquire();
+
+  //XXX is this necessary, or is acquiring the mutex enough?
+  while (thread->_thread_state != TS_wait) {
+    thread->_cv_done.wait();
+  }
+
+  PT(Texture) tex = std::move(thread->_texture);
+  thread->_region = nullptr;
+  thread->_texture = nullptr;
+  return tex;
+}
+
 /**
  * Fires off a cull traversal using the indicated camera.
  */
@@ -2633,6 +2670,11 @@ thread_main() {
       _result = _gsg->extract_texture_data(_texture);
       break;
 
+    case TS_do_screenshot:
+      nassertd(_region != nullptr) break;
+      _texture = _region->get_screenshot();
+      break;
+
     case TS_terminate:
       do_pending(_engine, current_thread);
       do_close(_engine, current_thread);

+ 4 - 1
panda/src/display/graphicsEngine.h

@@ -125,11 +125,13 @@ public:
     TS_do_windows,
     TS_do_compute,
     TS_do_extract,
+    TS_do_screenshot,
     TS_terminate,
     TS_done
   };
 
   void texture_uploaded(Texture *tex);
+  PT(Texture) do_get_screenshot(DisplayRegion *region, GraphicsStateGuardian *gsg);
 
 public:
   static void do_cull(CullHandler *cull_handler, SceneSetup *scene_setup,
@@ -304,8 +306,9 @@ private:
 
     // These are stored for extract_texture_data and dispatch_compute.
     GraphicsStateGuardian *_gsg;
-    Texture *_texture;
+    PT(Texture) _texture;
     const RenderState *_state;
+    DisplayRegion *_region;
     LVecBase3i _work_groups;
     bool _result;
   };

+ 0 - 18
panda/src/display/test_display.cxx

@@ -1,18 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file test_display.cxx
- * @author shochet
- * @date 2000-02-02
- */
-
-#include "graphicsWindow.h"
-
-int main() {
-  return 0;
-}

+ 1 - 1
panda/src/downloader/virtualFileMountHTTP.cxx

@@ -168,7 +168,7 @@ make_virtual_file(const Filename &local_filename,
     new VirtualFileHTTP(this, local_filename, implicit_pz_file, open_flags);
   vfile->set_original_filename(original_filename);
 
-  return vfile.p();
+  return vfile;
 }
 
 /**

+ 12 - 5
panda/src/dxgsg9/dxGeomMunger9.I

@@ -17,14 +17,21 @@
 INLINE DXGeomMunger9::
 DXGeomMunger9(GraphicsStateGuardian *gsg, const RenderState *state) :
   StandardMunger(gsg, state, 1, NT_packed_dabc, C_color),
-  _texture(DCAST(TextureAttrib, state->get_attrib(TextureAttrib::get_class_slot()))),
-  _tex_gen(DCAST(TexGenAttrib, state->get_attrib(TexGenAttrib::get_class_slot())))
+  _texture(nullptr),
+  _tex_gen(nullptr)
 {
+  const TextureAttrib *texture = nullptr;
+  const TexGenAttrib *tex_gen = nullptr;
+  state->get_attrib(texture);
+  state->get_attrib(tex_gen);
+  _texture = texture;
+  _tex_gen = tex_gen;
+
   _filtered_texture = nullptr;
   _reffed_filtered_texture = false;
-  if (_texture != nullptr) {
-    _filtered_texture = _texture->filter_to_max(gsg->get_max_texture_stages());
-    if (_filtered_texture != _texture) {
+  if (texture != nullptr) {
+    _filtered_texture = texture->filter_to_max(gsg->get_max_texture_stages());
+    if (_filtered_texture != texture) {
       _filtered_texture->ref();
       _reffed_filtered_texture = true;
     }

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

@@ -846,7 +846,7 @@ make_device(void *scrn) {
   _device = device;
   wdxdisplay9_cat.info() << "walla: device" << device << "\n";
 
-  return device.p();
+  return device;
 }
 
 pmap<D3DFORMAT_FLAG, D3DFORMAT> g_D3DFORMATmap;

+ 162 - 0
panda/src/express/pointerTo.I

@@ -39,6 +39,41 @@ PointerTo(PointerTo<T> &&from) noexcept :
 {
 }
 
+#ifndef CPPPARSER
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE PointerTo<T>::
+PointerTo(Y *ptr) noexcept :
+  PointerToBase<T>(ptr)
+{
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE PointerTo<T>::
+PointerTo(const PointerTo<Y> &r) noexcept :
+  PointerToBase<T>(r.p())
+{
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE PointerTo<T>::
+PointerTo(PointerTo<Y> &&r) noexcept :
+  PointerToBase<T>(std::move(r))
+{
+}
+#endif  // !CPPPARSER
+
 /**
  *
  */
@@ -49,6 +84,30 @@ operator = (PointerTo<T> &&from) noexcept {
   return *this;
 }
 
+#ifndef CPPPARSER
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE PointerTo<T> &PointerTo<T>::
+operator = (const PointerTo<Y> &r) noexcept {
+  this->reassign(r.p());
+  return *this;
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE PointerTo<T> &PointerTo<T>::
+operator = (PointerTo<Y> &&r) noexcept {
+  this->reassign(std::move(r));
+  return *this;
+}
+#endif  // !CPPPARSER
+
 /**
  *
  */
@@ -172,6 +231,63 @@ ConstPointerTo(ConstPointerTo<T> &&from) noexcept :
 {
 }
 
+#ifndef CPPPARSER
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE ConstPointerTo<T>::
+ConstPointerTo(const Y *ptr) noexcept :
+  PointerToBase<T>((Y *)ptr)
+{
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE ConstPointerTo<T>::
+ConstPointerTo(const PointerTo<Y> &r) noexcept :
+  PointerToBase<T>(r.p())
+{
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE ConstPointerTo<T>::
+ConstPointerTo(const ConstPointerTo<Y> &r) noexcept :
+  PointerToBase<T>((Y *)r.p())
+{
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE ConstPointerTo<T>::
+ConstPointerTo(PointerTo<Y> &&r) noexcept :
+  PointerToBase<T>(std::move(r))
+{
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE ConstPointerTo<T>::
+ConstPointerTo(ConstPointerTo<Y> &&r) noexcept :
+  PointerToBase<T>(std::move(r))
+{
+}
+#endif  // !CPPPARSER
+
 /**
  *
  */
@@ -192,6 +308,52 @@ operator = (ConstPointerTo<T> &&from) noexcept {
   return *this;
 }
 
+#ifndef CPPPARSER
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE ConstPointerTo<T> &ConstPointerTo<T>::
+operator = (const PointerTo<Y> &r) noexcept {
+  this->reassign(r.p());
+  return *this;
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE ConstPointerTo<T> &ConstPointerTo<T>::
+operator = (const ConstPointerTo<Y> &r) noexcept {
+  this->reassign((Y *)r.p());
+  return *this;
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE ConstPointerTo<T> &ConstPointerTo<T>::
+operator = (PointerTo<Y> &&r) noexcept {
+  this->reassign(std::move(r));
+  return *this;
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE ConstPointerTo<T> &ConstPointerTo<T>::
+operator = (ConstPointerTo<Y> &&r) noexcept {
+  this->reassign(std::move(r));
+  return *this;
+}
+#endif  // !CPPPARSER
+
 /**
  *
  */

+ 34 - 0
panda/src/express/pointerTo.h

@@ -77,8 +77,21 @@ PUBLISHED:
 
 public:
   INLINE PointerTo(PointerTo<T> &&from) noexcept;
+
+  template<class Y>
+  ALWAYS_INLINE explicit PointerTo(Y *ptr) noexcept;
+  template<class Y>
+  ALWAYS_INLINE PointerTo(const PointerTo<Y> &r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE PointerTo(PointerTo<Y> &&r) noexcept;
+
   INLINE PointerTo<T> &operator = (PointerTo<T> &&from) noexcept;
 
+  template<class Y>
+  ALWAYS_INLINE PointerTo<T> &operator = (const PointerTo<Y> &r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE PointerTo<T> &operator = (PointerTo<Y> &&r) noexcept;
+
   constexpr To &operator *() const noexcept;
   constexpr To *operator -> () const noexcept;
   // MSVC.NET 2005 insists that we use T *, and not To *, here.
@@ -141,9 +154,30 @@ PUBLISHED:
 public:
   INLINE ConstPointerTo(PointerTo<T> &&from) noexcept;
   INLINE ConstPointerTo(ConstPointerTo<T> &&from) noexcept;
+
+  template<class Y>
+  ALWAYS_INLINE explicit ConstPointerTo(const Y *ptr) noexcept;
+  template<class Y>
+  ALWAYS_INLINE ConstPointerTo(const PointerTo<Y> &r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE ConstPointerTo(const ConstPointerTo<Y> &r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE ConstPointerTo(PointerTo<Y> &&r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE ConstPointerTo(ConstPointerTo<Y> &&r) noexcept;
+
   INLINE ConstPointerTo<T> &operator = (PointerTo<T> &&from) noexcept;
   INLINE ConstPointerTo<T> &operator = (ConstPointerTo<T> &&from) noexcept;
 
+  template<class Y>
+  ALWAYS_INLINE ConstPointerTo<T> &operator = (const PointerTo<Y> &r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE ConstPointerTo<T> &operator = (const ConstPointerTo<Y> &r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE ConstPointerTo<T> &operator = (PointerTo<Y> &&r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE ConstPointerTo<T> &operator = (ConstPointerTo<Y> &&r) noexcept;
+
   constexpr const To &operator *() const noexcept;
   constexpr const To *operator -> () const noexcept;
   constexpr operator const T *() const noexcept;

+ 48 - 8
panda/src/express/pointerToBase.I

@@ -44,21 +44,36 @@ PointerToBase(const PointerToBase<T> &copy) {
  */
 template<class T>
 INLINE PointerToBase<T>::
-~PointerToBase() {
-  if (_void_ptr != nullptr) {
-    unref_delete((To *)_void_ptr);
-    _void_ptr = nullptr;
-  }
+PointerToBase(PointerToBase<T> &&from) noexcept {
+  _void_ptr = from._void_ptr;
+  from._void_ptr = nullptr;
 }
 
 /**
  *
  */
 template<class T>
+template<class Y>
 INLINE PointerToBase<T>::
-PointerToBase(PointerToBase<T> &&from) noexcept {
-  _void_ptr = from._void_ptr;
-  from._void_ptr = nullptr;
+PointerToBase(PointerToBase<Y> &&r) noexcept {
+  // If this next line gives an error, you are trying to convert a PointerTo
+  // from an incompatible type of another PointerTo.
+  To *ptr = (Y *)r._void_ptr;
+
+  this->_void_ptr = ptr;
+  r._void_ptr = nullptr;
+}
+
+/**
+ *
+ */
+template<class T>
+INLINE PointerToBase<T>::
+~PointerToBase() {
+  if (_void_ptr != nullptr) {
+    unref_delete((To *)_void_ptr);
+    _void_ptr = nullptr;
+  }
 }
 
 /**
@@ -84,6 +99,31 @@ reassign(PointerToBase<T> &&from) noexcept {
   }
 }
 
+/**
+ * Like above, but casts from a compatible pointer type.
+ */
+template<class T>
+template<class Y>
+INLINE void PointerToBase<T>::
+reassign(PointerToBase<Y> &&from) noexcept {
+  // Protect against self-move-assignment.
+  if (from._void_ptr != this->_void_ptr) {
+    To *old_ptr = (To *)this->_void_ptr;
+
+    // If there is a compile error on this line, it means you tried to assign
+    // an incompatible type.
+    To *new_ptr = (Y *)from._void_ptr;
+
+    this->_void_ptr = new_ptr;
+    from._void_ptr = nullptr;
+
+    // Now delete the old pointer.
+    if (old_ptr != nullptr) {
+      unref_delete(old_ptr);
+    }
+  }
+}
+
 /**
  * This is the main work of the PointerTo family.  When the pointer is
  * reassigned, decrement the old reference count and increment the new one.

+ 8 - 0
panda/src/express/pointerToBase.h

@@ -35,17 +35,25 @@ protected:
   INLINE PointerToBase(To *ptr);
   INLINE PointerToBase(const PointerToBase<T> &copy);
   INLINE PointerToBase(PointerToBase<T> &&from) noexcept;
+  template<class Y>
+  INLINE PointerToBase(PointerToBase<Y> &&r) noexcept;
+
   INLINE ~PointerToBase();
 
   INLINE void reassign(To *ptr);
   INLINE void reassign(const PointerToBase<To> &copy);
   INLINE void reassign(PointerToBase<To> &&from) noexcept;
+  template<class Y>
+  INLINE void reassign(PointerToBase<Y> &&from) noexcept;
 
   INLINE void update_type(To *ptr);
 
   // No assignment or retrieval functions are declared in PointerToBase,
   // because we will have to specialize on const vs.  non-const later.
 
+  // This is needed to be able to access the privates of other instantiations.
+  template<typename Y> friend class PointerToBase;
+
 PUBLISHED:
   ALWAYS_INLINE void clear();
 

+ 1 - 1
panda/src/express/virtualFileMount.cxx

@@ -58,7 +58,7 @@ make_virtual_file(const Filename &local_filename,
     make_directory(local);
   }
 
-  return file.p();
+  return file;
 }
 
 /**

+ 2 - 2
panda/src/express/weakPointerTo.h

@@ -38,7 +38,7 @@ public:
   INLINE To &operator *() const;
   INLINE To *operator -> () const;
   // MSVC.NET 2005 insists that we use T *, and not To *, here.
-  INLINE operator T *() const;
+  INLINE explicit operator T *() const;
 
 PUBLISHED:
   INLINE PointerTo<T> lock() const;
@@ -75,7 +75,7 @@ PUBLISHED:
 public:
   INLINE const To &operator *() const;
   INLINE const To *operator -> () const;
-  INLINE operator const T *() const;
+  INLINE explicit operator const T *() const;
 
 PUBLISHED:
   INLINE ConstPointerTo<T> lock() const;

+ 0 - 2
panda/src/express/weakPointerToBase.I

@@ -202,7 +202,6 @@ update_type(To *ptr) {
 }
 
 #ifndef CPPPARSER
-#ifndef WIN32_VC
 /**
  *
  */
@@ -426,7 +425,6 @@ INLINE bool WeakPointerToBase<T>::
 operator >= (const PointerToBase<To> &other) const {
   return (To *)_void_ptr >= (To *)((WeakPointerToBase<To> *)&other)->_void_ptr;
 }
-#endif  // WIN32_VC
 
 /**
  *

+ 1 - 2
panda/src/express/weakPointerToBase.h

@@ -48,7 +48,6 @@ public:
   // These comparison functions are common to all things PointerTo, so they're
   // defined up here.
 #ifndef CPPPARSER
-#ifndef WIN32_VC
   INLINE bool operator == (const To *other) const;
   INLINE bool operator != (const To *other) const;
   INLINE bool operator > (const To *other) const;
@@ -77,7 +76,7 @@ public:
   INLINE bool operator > (const PointerToBase<To> &other) const;
   INLINE bool operator <= (const PointerToBase<To> &other) const;
   INLINE bool operator >= (const PointerToBase<To> &other) const;
-#endif  // WIN32_VC
+
   INLINE bool operator < (const To *other) const;
   INLINE bool operator < (std::nullptr_t) const;
   INLINE bool operator < (const WeakPointerToBase<To> &other) const;

+ 1 - 1
panda/src/ffmpeg/ffmpegVideo.cxx

@@ -60,7 +60,7 @@ open() {
     ffmpeg_cat.error() << "Could not open " << _filename << "\n";
     return nullptr;
   } else {
-    return result.p();
+    return result;
   }
 }
 

+ 2 - 2
panda/src/ffmpeg/ffmpegVideoCursor.cxx

@@ -446,7 +446,7 @@ fetch_buffer() {
         << " at frame " << _current_frame << ", returning NULL\n";
     }
   }
-  return frame.p();
+  return frame;
 }
 
 /**
@@ -455,7 +455,7 @@ fetch_buffer() {
 PT(MovieVideoCursor::Buffer) FfmpegVideoCursor::
 make_new_buffer() {
   PT(FfmpegBuffer) frame = new FfmpegBuffer(size_x() * size_y() * get_num_components(), _video_timebase);
-  return frame.p();
+  return frame;
 }
 
 /**

+ 9 - 1
panda/src/framework/pandaFramework.cxx

@@ -82,7 +82,7 @@ PandaFramework::
  * control parameters.
  */
 void PandaFramework::
-open_framework(int &argc, char **&argv) {
+open_framework() {
   if (_is_open) {
     return;
   }
@@ -162,6 +162,14 @@ open_framework(int &argc, char **&argv) {
   _event_handler.add_hook("window-event", event_window_event, this);
 }
 
+/**
+ * @deprecated See the version of open_framework() without arguments.
+ */
+void PandaFramework::
+open_framework(int &argc, char **&argv) {
+  open_framework();
+}
+
 /**
  * Should be called at the end of an application to close Panda.  This is
  * optional, as the destructor will do the same thing.

+ 1 - 0
panda/src/framework/pandaFramework.h

@@ -40,6 +40,7 @@ public:
   PandaFramework();
   virtual ~PandaFramework();
 
+  void open_framework();
   void open_framework(int &argc, char **&argv);
   void close_framework();
 

+ 1 - 1
panda/src/framework/windowFramework.cxx

@@ -1334,7 +1334,7 @@ load_image_as_model(const Filename &filename) {
 
   card_node->add_geom(geom);
 
-  return card_node.p();
+  return card_node;
 }
 
 /**

+ 15 - 8
panda/src/glstuff/glCgShaderContext_src.cxx

@@ -648,6 +648,7 @@ issue_parameters(int altered) {
         continue;
 
       case Shader::SPT_int:
+      case Shader::SPT_uint:
         switch (spec._info._class) {
         case Shader::SAC_scalar:
           cgSetParameter1iv(p, (int*)ptr_data->_ptr);
@@ -884,17 +885,21 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
 
           _glgsg->enable_vertex_attrib_array(p);
 
-          if (bind._integer) {
-            _glgsg->_glVertexAttribIPointer(p, num_values, type,
-                                            stride, client_pointer);
-          } else if (numeric_type == GeomEnums::NT_packed_dabc) {
+          if (numeric_type == GeomEnums::NT_packed_dabc) {
             // GL_BGRA is a special accepted value available since OpenGL 3.2.
             // It requires us to pass GL_TRUE for normalized.
             _glgsg->_glVertexAttribPointer(p, GL_BGRA, GL_UNSIGNED_BYTE,
                                            GL_TRUE, stride, client_pointer);
-          } else {
+          } else if (bind._numeric_type == Shader::SPT_float ||
+                     numeric_type == GeomEnums::NT_float32) {
             _glgsg->_glVertexAttribPointer(p, num_values, type,
                                            normalized, stride, client_pointer);
+          } else if (bind._numeric_type == Shader::SPT_double) {
+            _glgsg->_glVertexAttribLPointer(p, num_values, type,
+                                            stride, client_pointer);
+          } else {
+            _glgsg->_glVertexAttribIPointer(p, num_values, type,
+                                            stride, client_pointer);
           }
 
           if (divisor > 0) {
@@ -951,10 +956,12 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
           // So, we work around this by just binding something silly to 0.
           // This breaks flat colors, but it's better than invisible objects?
           _glgsg->enable_vertex_attrib_array(0);
-          if (bind._integer) {
-            _glgsg->_glVertexAttribIPointer(0, 4, GL_INT, 0, 0);
-          } else {
+          if (bind._numeric_type == Shader::SPT_float) {
             _glgsg->_glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
+          } else if (bind._numeric_type == Shader::SPT_double) {
+            _glgsg->_glVertexAttribLPointer(0, 4, GL_DOUBLE, 0, 0);
+          } else {
+            _glgsg->_glVertexAttribIPointer(0, 4, GL_INT, 0, 0);
           }
 
         } else if (p >= 0) {

+ 27 - 2
panda/src/glstuff/glGraphicsBuffer_src.cxx

@@ -864,14 +864,22 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
       case RTP_depth_stencil:
         if (_fb_properties.get_depth_bits() > 24 ||
             _fb_properties.get_float_depth()) {
-          gl_format = GL_DEPTH32F_STENCIL8;
+          if (!glgsg->_use_remapped_depth_range) {
+            gl_format = GL_DEPTH32F_STENCIL8;
+          } else {
+            gl_format = GL_DEPTH32F_STENCIL8_NV;
+          }
         } else {
           gl_format = GL_DEPTH24_STENCIL8;
         }
         break;
       case RTP_depth:
         if (_fb_properties.get_float_depth()) {
-          gl_format = GL_DEPTH_COMPONENT32F;
+          if (!glgsg->_use_remapped_depth_range) {
+            gl_format = GL_DEPTH_COMPONENT32F;
+          } else {
+            gl_format = GL_DEPTH_COMPONENT32F_NV;
+          }
         } else if (_fb_properties.get_depth_bits() > 24) {
           gl_format = GL_DEPTH_COMPONENT32;
         } else if (_fb_properties.get_depth_bits() > 16) {
@@ -981,6 +989,23 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
       GLint depth_size = 0;
       glgsg->_glRenderbufferStorage(GL_RENDERBUFFER_EXT, gl_format, _rb_size_x, _rb_size_y);
       glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &depth_size);
+
+#ifndef OPENGLES
+      // Are we getting only 24 bits of depth when we requested 32?  It may be
+      // because GL_DEPTH_COMPONENT32 is not a required format, while 32F is.
+      if (gl_format == GL_DEPTH_COMPONENT32 && depth_size < 32) {
+        if (!glgsg->_use_remapped_depth_range) {
+          gl_format = GL_DEPTH_COMPONENT32F;
+        } else {
+          gl_format = GL_DEPTH_COMPONENT32F_NV;
+        }
+        glgsg->_glRenderbufferStorage(GL_RENDERBUFFER_EXT, gl_format, _rb_size_x, _rb_size_y);
+        glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &depth_size);
+
+        _fb_properties.set_float_depth(true);
+      }
+#endif
+
       _fb_properties.set_depth_bits(depth_size);
       _rb_data_size_bytes += _rb_size_x * _rb_size_y * (depth_size / 8);
 

+ 152 - 9
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -92,10 +92,6 @@ PStatCollector CLP(GraphicsStateGuardian)::_texture_update_pcollector("Draw:Upda
 PStatCollector CLP(GraphicsStateGuardian)::_fbo_bind_pcollector("Draw:Bind FBO");
 PStatCollector CLP(GraphicsStateGuardian)::_check_error_pcollector("Draw:Check errors");
 
-#ifndef OPENGLES_1
-PT(Shader) CLP(GraphicsStateGuardian)::_default_shader = nullptr;
-#endif
-
 // The following noop functions are assigned to the corresponding glext
 // function pointers in the class, in case the functions are not defined by
 // the GL, just so it will always be safe to call the extension functions.
@@ -188,6 +184,48 @@ static const string default_vshader =
   "  color = p3d_Color * p3d_ColorScale;\n"
   "}\n";
 
+#ifndef OPENGLES
+// This version of the shader is used if vertices-float64 is enabled.
+static const string default_vshader_fp64 =
+#ifdef __APPLE__
+  "#version 150\n"
+#else
+  "#version 130\n"
+#endif
+  "#extension GL_ARB_vertex_attrib_64bit : require\n"
+  "#extension GL_ARB_gpu_shader_fp64 : require\n"
+  "in dvec3 p3d_Vertex;\n"
+  "in vec4 p3d_Color;\n"
+  "in dvec2 p3d_MultiTexCoord0;\n"
+  "out vec2 texcoord;\n"
+  "out vec4 color;\n"
+  "uniform mat4 p3d_ModelViewMatrix;\n"
+  "uniform mat4 p3d_ProjectionMatrix;\n"
+  "uniform vec4 p3d_ColorScale;\n"
+  "void main(void) {\n" // Apply proj & modelview in two steps, more precise
+  "  gl_Position = vec4(dmat4(p3d_ProjectionMatrix) * (dmat4(p3d_ModelViewMatrix) * dvec4(p3d_Vertex, 1)));\n"
+  "  texcoord = vec2(p3d_MultiTexCoord0);\n"
+  "  color = p3d_Color * p3d_ColorScale;\n"
+  "}\n";
+
+// Same as above, but for OpenGL 4.1.
+static const string default_vshader_fp64_gl41 =
+  "#version 410\n"
+  "in dvec3 p3d_Vertex;\n"
+  "in vec4 p3d_Color;\n"
+  "in dvec2 p3d_MultiTexCoord0;\n"
+  "out vec2 texcoord;\n"
+  "out vec4 color;\n"
+  "uniform mat4 p3d_ModelViewMatrix;\n"
+  "uniform mat4 p3d_ProjectionMatrix;\n"
+  "uniform vec4 p3d_ColorScale;\n"
+  "void main(void) {\n" // Apply proj & modelview in two steps, more precise
+  "  gl_Position = vec4(dmat4(p3d_ProjectionMatrix) * (dmat4(p3d_ModelViewMatrix) * dvec4(p3d_Vertex, 1)));\n"
+  "  texcoord = vec2(p3d_MultiTexCoord0);\n"
+  "  color = p3d_Color * p3d_ColorScale;\n"
+  "}\n";
+#endif
+
 static const string default_fshader =
 #ifndef OPENGLES
 #ifdef __APPLE__  // Apple's GL 3.2 contexts require at least GLSL 1.50.
@@ -613,6 +651,8 @@ reset() {
         get_extension_func("glDebugMessageControlARB");
       _supports_debug = true;
 #endif
+    } else {
+      _supports_debug = false;
     }
 
     if (_supports_debug) {
@@ -1697,6 +1737,14 @@ reset() {
        get_extension_func("glUniform3iv");
     _glUniform4iv = (PFNGLUNIFORM4IVPROC)
        get_extension_func("glUniform4iv");
+    _glUniform1uiv = (PFNGLUNIFORM1UIVPROC)
+       get_extension_func("glUniform1uiv");
+    _glUniform2uiv = (PFNGLUNIFORM2UIVPROC)
+       get_extension_func("glUniform2uiv");
+    _glUniform3uiv = (PFNGLUNIFORM3UIVPROC)
+       get_extension_func("glUniform3uiv");
+    _glUniform4uiv = (PFNGLUNIFORM4UIVPROC)
+       get_extension_func("glUniform4uiv");
     _glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)
        get_extension_func("glUniformMatrix3fv");
     _glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)
@@ -1775,6 +1823,10 @@ reset() {
   _glUniform2fv = glUniform2fv;
   _glUniform3fv = glUniform3fv;
   _glUniform4fv = glUniform4fv;
+  _glUniform1iv = glUniform1iv;
+  _glUniform2iv = glUniform2iv;
+  _glUniform3iv = glUniform3iv;
+  _glUniform4iv = glUniform4iv;
   _glUniformMatrix3fv = glUniformMatrix3fv;
   _glUniformMatrix4fv = glUniformMatrix4fv;
   _glValidateProgram = glValidateProgram;
@@ -1825,7 +1877,17 @@ reset() {
   // shader just outputs a red color, indicating that something went wrong.
 #ifndef OPENGLES_1
   if (_default_shader == nullptr && !has_fixed_function_pipeline()) {
-    _default_shader = Shader::make(Shader::SL_GLSL, default_vshader, default_fshader);
+#ifndef OPENGLES
+    bool use_float64 = vertices_float64;
+    if (use_float64 && is_at_least_gl_version(4, 1)) {
+      _default_shader = Shader::make(Shader::SL_GLSL, default_vshader_fp64_gl41, default_fshader);
+    } else if (use_float64 && has_extension("GL_ARB_vertex_attrib_64bit")) {
+      _default_shader = Shader::make(Shader::SL_GLSL, default_vshader_fp64, default_fshader);
+    } else
+#endif
+    {
+      _default_shader = Shader::make(Shader::SL_GLSL, default_vshader, default_fshader);
+    }
   }
 #endif
 
@@ -2995,6 +3057,50 @@ reset() {
   }
 #endif
 
+  // Set depth range from zero to one if requested.
+#ifndef OPENGLES
+  _use_depth_zero_to_one = false;
+  _use_remapped_depth_range = false;
+
+  if (gl_depth_zero_to_one) {
+    if (is_at_least_gl_version(4, 5) || has_extension("GL_ARB_clip_control")) {
+      PFNGLCLIPCONTROLPROC pglClipControl =
+        (PFNGLCLIPCONTROLPROC)get_extension_func("glClipControl");
+
+      if (pglClipControl != nullptr) {
+        pglClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
+        _use_depth_zero_to_one = true;
+
+        if (GLCAT.is_debug()) {
+          GLCAT.debug()
+            << "Set zero-to-one depth using glClipControl\n";
+        }
+      }
+    }/* else if (has_extension("GL_NV_depth_buffer_float")) {
+      // Alternatively, all GeForce 8+ and even some AMD drivers support this
+      // extension, which (unlike the core glDepthRange, which clamps its
+      // input parameters) can compensate for the built-in depth remapping.
+      _glDepthRangedNV = (PFNGLDEPTHRANGEDNVPROC)get_extension_func("glDepthRangedNV");
+
+      if (_glDepthRangedNV != nullptr) {
+        _glDepthRangedNV(-1.0, 1.0);
+        _use_depth_zero_to_one = true;
+        _use_remapped_depth_range = true;
+
+        if (GLCAT.is_debug()) {
+          GLCAT.debug()
+            << "Set zero-to-one depth using glDepthRangedNV\n";
+        }
+      }
+    }*/
+
+    if (!_use_depth_zero_to_one) {
+      GLCAT.warning()
+        << "Zero-to-one depth was requested, but driver does not support it.\n";
+    }
+  }
+#endif
+
   // Set up all the enableddisabled flags to GL's known initial values:
   // everything off.
   _multisample_mode = 0;
@@ -3644,6 +3750,19 @@ calc_projection_mat(const Lens *lens) {
                           lens->get_coordinate_system()) *
     lens->get_projection_mat(_current_stereo_channel);
 
+#ifndef OPENGLES
+  if (_use_depth_zero_to_one) {
+    // If we requested that the OpenGL NDC Z goes from zero to one like in
+    // Direct3D, we need to scale the projection matrix, which assumes -1..1.
+    static const LMatrix4 rescale_mat
+      (1, 0, 0, 0,
+       0, 1, 0, 0,
+       0, 0, 0.5, 0,
+       0, 0, 0.5, 1);
+    result *= rescale_mat;
+  }
+#endif
+
   if (_scene_setup->get_inverted()) {
     // If the scene is supposed to be inverted, then invert the projection
     // matrix.
@@ -6330,10 +6449,11 @@ prepare_shader_buffer(ShaderBuffer *data) {
 
     if (_use_object_labels) {
       string name = data->get_name();
-      _glObjectLabel(GL_SHADER_STORAGE_BUFFER, gbc->_index, name.size(), name.data());
+      _glObjectLabel(GL_BUFFER, gbc->_index, name.size(), name.data());
     }
 
-    uint64_t num_bytes = data->get_data_size_bytes();
+    // Some drivers require the buffer to be padded to 16 byte boundary.
+    uint64_t num_bytes = (data->get_data_size_bytes() + 15u) & ~15u;
     if (_supports_buffer_storage) {
       _glBufferStorage(GL_SHADER_STORAGE_BUFFER, num_bytes, data->get_initial_data(), 0);
     } else {
@@ -7450,7 +7570,13 @@ do_issue_depth_offset() {
   glDepthRangef((GLclampf)min_value, (GLclampf)max_value);
 #else
   // Mainline OpenGL uses a double-precision call.
-  glDepthRange((GLclampd)min_value, (GLclampd)max_value);
+  if (!_use_remapped_depth_range) {
+    glDepthRange((GLclampd)min_value, (GLclampd)max_value);
+  } else {
+    // If we have a remapped depth range, we should adjust the values to range
+    // from -1 to 1.  We need to use an NV extension to pass unclamped values.
+    _glDepthRangedNV(min_value * 2.0 - 1.0, max_value * 2.0 - 1.0);
+  }
 #endif  // OPENGLES
 
   report_my_gl_errors();
@@ -12778,7 +12904,9 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
 
       int width = tex->get_expected_mipmap_x_size(n);
       int height = tex->get_expected_mipmap_y_size(n);
+#ifndef OPENGLES_1
       int depth = tex->get_expected_mipmap_z_size(n);
+#endif
 
 #ifdef DO_PSTATS
       _data_transferred_pcollector.add_level(view_size);
@@ -12958,7 +13086,9 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
 
       int width = tex->get_expected_mipmap_x_size(n);
       int height = tex->get_expected_mipmap_y_size(n);
+#ifndef OPENGLES_1
       int depth = tex->get_expected_mipmap_z_size(n);
+#endif
 
 #ifdef DO_PSTATS
       _data_transferred_pcollector.add_level(view_size);
@@ -13309,6 +13439,12 @@ do_extract_texture_data(CLP(TextureContext) *gtc) {
       << "glBindTexture(0x" << hex << target << dec << ", " << gtc->_index << "): " << *tex << "\n";
   }
 
+#ifndef OPENGLES
+  if (target == GL_TEXTURE_BUFFER) {
+    _glBindBuffer(GL_TEXTURE_BUFFER, gtc->_buffer);
+  }
+#endif
+
   GLint wrap_u, wrap_v, wrap_w;
   GLint minfilter, magfilter;
 
@@ -13367,7 +13503,14 @@ do_extract_texture_data(CLP(TextureContext) *gtc) {
 
   GLint internal_format = GL_RGBA;
 #ifndef OPENGLES
-  glGetTexLevelParameteriv(page_target, 0, GL_TEXTURE_INTERNAL_FORMAT, &internal_format);
+  if (target != GL_TEXTURE_BUFFER) {
+    glGetTexLevelParameteriv(page_target, 0, GL_TEXTURE_INTERNAL_FORMAT, &internal_format);
+  } else {
+    // Some drivers give the wrong result for the above call.  No problem; we
+    // already know the internal format of a buffer texture since glTexBuffer
+    // required passing the exact sized format.
+    internal_format = gtc->_internal_format;
+  }
 #endif  // OPENGLES
 
   // Make sure we were able to query those parameters properly.

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

@@ -175,6 +175,10 @@ typedef void (APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, con
 typedef void (APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value);
 typedef void (APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value);
 typedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint *value);
 typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
 typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
 typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program);
@@ -670,7 +674,7 @@ protected:
   PT(Shader) _texture_binding_shader;
   ShaderContext *_texture_binding_shader_context;
 
-  static PT(Shader) _default_shader;
+  PT(Shader) _default_shader;
 
 #ifndef OPENGLES
   bool _shader_point_size;
@@ -743,6 +747,12 @@ protected:
 #endif
 
 public:
+#ifndef OPENGLES
+  bool _use_depth_zero_to_one;
+  bool _use_remapped_depth_range;
+  PFNGLDEPTHRANGEDNVPROC _glDepthRangedNV;
+#endif
+
   bool _supports_point_parameters;
   PFNGLPOINTPARAMETERFVPROC _glPointParameterfv;
   bool _supports_point_sprite;
@@ -978,6 +988,10 @@ public:
   PFNGLUNIFORM2IVPROC _glUniform2iv;
   PFNGLUNIFORM3IVPROC _glUniform3iv;
   PFNGLUNIFORM4IVPROC _glUniform4iv;
+  PFNGLUNIFORM1UIVPROC _glUniform1uiv;
+  PFNGLUNIFORM2UIVPROC _glUniform2uiv;
+  PFNGLUNIFORM3UIVPROC _glUniform3uiv;
+  PFNGLUNIFORM4UIVPROC _glUniform4uiv;
   PFNGLUNIFORMMATRIX3FVPROC _glUniformMatrix3fv;
   PFNGLUNIFORMMATRIX4FVPROC _glUniformMatrix4fv;
   PFNGLVALIDATEPROGRAMPROC _glValidateProgram;

+ 101 - 24
panda/src/glstuff/glShaderContext_src.cxx

@@ -426,18 +426,34 @@ reflect_attribute(int i, char *name_buffer, GLsizei name_buflen) {
   bind._elements = 1;
 
   // Check if this is an integer input- if so, we have to bind it differently.
-  bind._integer = (param_type == GL_BOOL ||
-                   param_type == GL_BOOL_VEC2 ||
-                   param_type == GL_BOOL_VEC3 ||
-                   param_type == GL_BOOL_VEC4 ||
-                   param_type == GL_INT ||
-                   param_type == GL_INT_VEC2 ||
-                   param_type == GL_INT_VEC3 ||
-                   param_type == GL_INT_VEC4 ||
-                   param_type == GL_UNSIGNED_INT_VEC2 ||
-                   param_type == GL_UNSIGNED_INT_VEC3 ||
-                   param_type == GL_UNSIGNED_INT_VEC4 ||
-                   param_type == GL_UNSIGNED_INT);
+  switch (param_type) {
+  case GL_INT:
+  case GL_INT_VEC2:
+  case GL_INT_VEC3:
+  case GL_INT_VEC4:
+    bind._numeric_type = Shader::SPT_int;
+    break;
+  case GL_BOOL:
+  case GL_BOOL_VEC2:
+  case GL_BOOL_VEC3:
+  case GL_BOOL_VEC4:
+  case GL_UNSIGNED_INT:
+  case GL_UNSIGNED_INT_VEC2:
+  case GL_UNSIGNED_INT_VEC3:
+  case GL_UNSIGNED_INT_VEC4:
+    bind._numeric_type = Shader::SPT_uint;
+    break;
+#ifndef OPENGLES
+  case GL_DOUBLE:
+  case GL_DOUBLE_VEC2:
+  case GL_DOUBLE_VEC3:
+  case GL_DOUBLE_VEC4:
+    bind._numeric_type = Shader::SPT_double;
+    break;
+#endif
+  default:
+    bind._numeric_type = Shader::SPT_float;
+  }
 
   // Check if it has a p3d_ prefix - if so, assign special meaning.
   if (strncmp(name_buffer, "p3d_", 4) == 0) {
@@ -1501,21 +1517,29 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       case GL_INT:
       case GL_INT_VEC2:
       case GL_INT_VEC3:
-      case GL_INT_VEC4: {
+      case GL_INT_VEC4:
+      case GL_UNSIGNED_INT:
+      case GL_UNSIGNED_INT_VEC2:
+      case GL_UNSIGNED_INT_VEC3:
+      case GL_UNSIGNED_INT_VEC4: {
         Shader::ShaderPtrSpec bind;
         bind._id = arg_id;
         switch (param_type) {
           case GL_BOOL:
           case GL_INT:
+          case GL_UNSIGNED_INT:
           case GL_FLOAT:      bind._dim[1] = 1; break;
           case GL_BOOL_VEC2:
           case GL_INT_VEC2:
+          case GL_UNSIGNED_INT_VEC2:
           case GL_FLOAT_VEC2: bind._dim[1] = 2; break;
           case GL_BOOL_VEC3:
           case GL_INT_VEC3:
+          case GL_UNSIGNED_INT_VEC3:
           case GL_FLOAT_VEC3: bind._dim[1] = 3; break;
           case GL_BOOL_VEC4:
           case GL_INT_VEC4:
+          case GL_UNSIGNED_INT_VEC4:
           case GL_FLOAT_VEC4: bind._dim[1] = 4; break;
           case GL_FLOAT_MAT3: bind._dim[1] = 9; break;
           case GL_FLOAT_MAT4: bind._dim[1] = 16; break;
@@ -1525,6 +1549,12 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         case GL_BOOL_VEC2:
         case GL_BOOL_VEC3:
         case GL_BOOL_VEC4:
+        case GL_UNSIGNED_INT:
+        case GL_UNSIGNED_INT_VEC2:
+        case GL_UNSIGNED_INT_VEC3:
+        case GL_UNSIGNED_INT_VEC4:
+          bind._type = Shader::SPT_uint;
+          break;
         case GL_INT:
         case GL_INT_VEC2:
         case GL_INT_VEC3:
@@ -1604,6 +1634,10 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
     case GL_INT_VEC2:
     case GL_INT_VEC3:
     case GL_INT_VEC4:
+    case GL_UNSIGNED_INT:
+    case GL_UNSIGNED_INT_VEC2:
+    case GL_UNSIGNED_INT_VEC3:
+    case GL_UNSIGNED_INT_VEC4:
     case GL_FLOAT:
     case GL_FLOAT_VEC2:
     case GL_FLOAT_VEC3:
@@ -1633,6 +1667,12 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       case GL_BOOL_VEC2:
       case GL_BOOL_VEC3:
       case GL_BOOL_VEC4:
+      case GL_UNSIGNED_INT:
+      case GL_UNSIGNED_INT_VEC2:
+      case GL_UNSIGNED_INT_VEC3:
+      case GL_UNSIGNED_INT_VEC4:
+        bind._type = Shader::SPT_uint;
+        break;
       case GL_INT:
       case GL_INT_VEC2:
       case GL_INT_VEC3:
@@ -2003,6 +2043,8 @@ issue_parameters(int altered) {
         return;
       }
 
+      nassertd(spec._dim[1] > 0) continue;
+
       GLint p = spec._id._seqno;
       int array_size = min(spec._dim[0], (int)ptr_data->_size / spec._dim[1]);
       switch (spec._type) {
@@ -2019,6 +2061,14 @@ issue_parameters(int altered) {
             }
             break;
 
+          case Shader::SPT_uint:
+            // Convert unsigned int data to float data.
+            data = (float*) alloca(sizeof(float) * array_size * spec._dim[1]);
+            for (int i = 0; i < (array_size * spec._dim[1]); ++i) {
+              data[i] = (float)(((unsigned int*)ptr_data->_ptr)[i]);
+            }
+            break;
+
           case Shader::SPT_double:
             // Downgrade double data to float data.
             data = (float*) alloca(sizeof(float) * array_size * spec._dim[1]);
@@ -2048,7 +2098,8 @@ issue_parameters(int altered) {
         break;
 
       case Shader::SPT_int:
-        if (ptr_data->_type != Shader::SPT_int) {
+        if (ptr_data->_type != Shader::SPT_int &&
+            ptr_data->_type != Shader::SPT_uint) {
           GLCAT.error()
             << "Cannot pass floating-point data to integer shader input '" << spec._id._name << "'\n";
 
@@ -2068,6 +2119,28 @@ issue_parameters(int altered) {
         }
         break;
 
+      case Shader::SPT_uint:
+        if (ptr_data->_type != Shader::SPT_uint &&
+            ptr_data->_type != Shader::SPT_int) {
+          GLCAT.error()
+            << "Cannot pass floating-point data to integer shader input '" << spec._id._name << "'\n";
+
+          // Deactivate it to make sure the user doesn't get flooded with this
+          // error.
+          spec._dep[0] = 0;
+          spec._dep[1] = 0;
+
+        } else {
+          switch (spec._dim[1]) {
+          case 1: _glgsg->_glUniform1uiv(p, array_size, (GLuint *)ptr_data->_ptr); continue;
+          case 2: _glgsg->_glUniform2uiv(p, array_size, (GLuint *)ptr_data->_ptr); continue;
+          case 3: _glgsg->_glUniform3uiv(p, array_size, (GLuint *)ptr_data->_ptr); continue;
+          case 4: _glgsg->_glUniform4uiv(p, array_size, (GLuint *)ptr_data->_ptr); continue;
+          }
+          nassertd(false) continue;
+        }
+        break;
+
       case Shader::SPT_double:
         GLCAT.error() << "Passing double-precision shader inputs to GLSL shaders is not currently supported\n";
 
@@ -2207,7 +2280,7 @@ disable_shader_vertex_arrays() {
     return;
   }
 
-  for (int i=0; i<(int)_shader->_var_spec.size(); i++) {
+  for (size_t i = 0; i < _shader->_var_spec.size(); ++i) {
     const Shader::ShaderVarSpec &bind = _shader->_var_spec[i];
     GLint p = bind._id._seqno;
 
@@ -2332,21 +2405,25 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
         }
         client_pointer += start;
 
+        GLenum type = _glgsg->get_numeric_type(numeric_type);
         for (int i = 0; i < num_elements; ++i) {
           _glgsg->enable_vertex_attrib_array(p);
 
-          if (bind._integer) {
-            _glgsg->_glVertexAttribIPointer(p, num_values, _glgsg->get_numeric_type(numeric_type),
-                                            stride, client_pointer);
-          } else if (numeric_type == GeomEnums::NT_packed_dabc) {
+          if (numeric_type == GeomEnums::NT_packed_dabc) {
             // GL_BGRA is a special accepted value available since OpenGL 3.2.
             // It requires us to pass GL_TRUE for normalized.
             _glgsg->_glVertexAttribPointer(p, GL_BGRA, GL_UNSIGNED_BYTE,
                                            GL_TRUE, stride, client_pointer);
-          } else {
-            _glgsg->_glVertexAttribPointer(p, num_values,
-                                           _glgsg->get_numeric_type(numeric_type),
+          } else if (bind._numeric_type == Shader::SPT_float ||
+                     numeric_type == GeomEnums::NT_float32) {
+            _glgsg->_glVertexAttribPointer(p, num_values, type,
                                            normalized, stride, client_pointer);
+          } else if (bind._numeric_type == Shader::SPT_double) {
+            _glgsg->_glVertexAttribLPointer(p, num_values, type,
+                                            stride, client_pointer);
+          } else {
+            _glgsg->_glVertexAttribIPointer(p, num_values, type,
+                                            stride, client_pointer);
           }
 
           if (divisor > 0) {
@@ -2612,8 +2689,8 @@ update_shader_texture_bindings(ShaderContext *prev) {
   }
 
   size_t num_textures = _shader->_tex_spec.size();
-  GLuint *textures;
-  GLuint *samplers;
+  GLuint *textures = nullptr;
+  GLuint *samplers = nullptr;
 #ifdef OPENGLES
   static const bool multi_bind = false;
 #else

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

@@ -313,6 +313,13 @@ ConfigVariableEnum<CoordinateSystem> gl_coordinate_system
             "creating a shader-only application, it may be easier and "
             "more efficient to set this to default."));
 
+ConfigVariableBool gl_depth_zero_to_one
+  ("gl-depth-zero-to-one", false,
+   PRC_DESC("Normally, OpenGL uses an NDC coordinate space wherein the Z "
+            "ranges from -1 to 1.  This setting can be used to instead use a "
+            "range from 0 to 1, matching other graphics APIs.  This setting "
+            "requires OpenGL 4.5, or NVIDIA GeForce 8+ hardware."));
+
 extern ConfigVariableBool gl_parallel_arrays;
 
 void CLP(init_classes)() {

File diff suppressed because it is too large
+ 631 - 31
panda/src/glstuff/panda_glext.h


+ 5 - 0
panda/src/gobj/geomCacheManager.cxx

@@ -13,7 +13,9 @@
 
 #include "geomCacheManager.h"
 #include "geomCacheEntry.h"
+#include "geomMunger.h"
 #include "lightMutexHolder.h"
+#include "lightReMutexHolder.h"
 #include "clockObject.h"
 
 GeomCacheManager *GeomCacheManager::_global_ptr = nullptr;
@@ -53,6 +55,9 @@ GeomCacheManager::
  */
 void GeomCacheManager::
 flush() {
+  // Prevent deadlock
+  LightReMutexHolder registry_holder(GeomMunger::get_registry()->_registry_lock);
+
   LightMutexHolder holder(_lock);
   evict_old_entries(0, false);
 }

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

@@ -128,7 +128,7 @@ make_adjacency() const {
   }
 
   adj->set_vertices(std::move(new_vertices));
-  return adj.p();
+  return adj;
 }
 
 /**

+ 3 - 3
panda/src/gobj/geomLinestrips.cxx

@@ -164,7 +164,7 @@ make_adjacency() const {
   }
   nassertr(vi == num_vertices, nullptr);
 
-  return adj.p();
+  return adj;
 }
 
 /**
@@ -220,7 +220,7 @@ decompose_impl() const {
     // Skip unused vertices between tristrips.
     vi += num_unused;
     int end = ends[li];
-    nassertr(vi + 1 <= end, lines.p());
+    nassertr(vi + 1 <= end, lines);
     int v0 = get_vertex(vi);
     ++vi;
     while (vi < end) {
@@ -235,7 +235,7 @@ decompose_impl() const {
   }
   nassertr(vi == get_num_vertices(), nullptr);
 
-  return lines.p();
+  return lines;
 }
 
 /**

+ 2 - 2
panda/src/gobj/geomLinestripsAdjacency.cxx

@@ -142,7 +142,7 @@ decompose_impl() const {
     // Skip unused vertices between tristrips.
     vi += num_unused;
     int end = ends[li];
-    nassertr(vi + 3 <= end, lines.p());
+    nassertr(vi + 3 <= end, lines);
     int v0 = from.get_vertex(vi++);
     int v1 = from.get_vertex(vi++);
     int v2 = from.get_vertex(vi++);
@@ -160,7 +160,7 @@ decompose_impl() const {
   }
   nassertr(vi == num_vertices, nullptr);
 
-  return lines.p();
+  return lines;
 }
 
 /**

+ 2 - 0
panda/src/gobj/geomMunger.h

@@ -149,6 +149,8 @@ private:
 
   static PStatCollector _munge_pcollector;
 
+  friend class GeomCacheManager;
+
 public:
   static TypeHandle get_class_type() {
     return _type_handle;

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

@@ -55,7 +55,7 @@ GeomPrimitive() {
  */
 PT(CopyOnWriteObject) GeomPrimitive::
 make_cow_copy() {
-  return make_copy().p();
+  return make_copy();
 }
 
 /**

+ 3 - 3
panda/src/gobj/geomTriangles.cxx

@@ -138,7 +138,7 @@ make_adjacency() const {
   }
 
   adj->set_vertices(std::move(new_vertices));
-  return adj.p();
+  return adj;
 }
 
 /**
@@ -199,7 +199,7 @@ doubleside_impl() const {
     reversed = (GeomTriangles *)DCAST(GeomTriangles, reversed->rotate());
   }
 
-  return reversed.p();
+  return reversed;
 }
 
 /**
@@ -232,7 +232,7 @@ reverse_impl() const {
     break;
   }
 
-  return reversed.p();
+  return reversed;
 }
 
 /**

+ 2 - 2
panda/src/gobj/geomTrianglesAdjacency.cxx

@@ -133,7 +133,7 @@ doubleside_impl() const {
     reversed = (GeomTrianglesAdjacency *)DCAST(GeomTrianglesAdjacency, reversed->rotate());
   }
 
-  return reversed.p();
+  return reversed;
 }
 
 /**
@@ -166,7 +166,7 @@ reverse_impl() const {
     break;
   }
 
-  return reversed.p();
+  return reversed;
 }
 
 /**

+ 2 - 2
panda/src/gobj/geomTrifans.cxx

@@ -110,7 +110,7 @@ decompose_impl() const {
   int li = 0;
   while (li < (int)ends.size()) {
     int end = ends[li];
-    nassertr(vi + 2 <= end, triangles.p());
+    nassertr(vi + 2 <= end, triangles);
     int v0 = get_vertex(vi);
     ++vi;
     int v1 = get_vertex(vi);
@@ -129,7 +129,7 @@ decompose_impl() const {
 
   nassertr(vi == num_vertices, nullptr);
 
-  return triangles.p();
+  return triangles;
 }
 
 /**

+ 2 - 2
panda/src/gobj/geomTristrips.cxx

@@ -219,7 +219,7 @@ make_adjacency() const {
   }
   nassertr(vi == num_vertices, nullptr);
 
-  return adj.p();
+  return adj;
 }
 
 /**
@@ -358,7 +358,7 @@ decompose_impl() const {
     nassertr(vi == num_vertices, nullptr);
   }
 
-  return triangles.p();
+  return triangles;
 }
 
 /**

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

@@ -76,7 +76,7 @@ make(PyStringObject *str) {
     iname->ref();
 
     InternalName::_py_intern_table.insert(std::make_pair((PyObject *)str, iname.p()));
-    return iname.p();
+    return iname;
   }
 
 }

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

@@ -630,7 +630,7 @@ make_geometry() {
   PT(Geom) geom = new Geom(cdata->_geom_data);
   geom->add_primitive(line);
 
-  return geom.p();
+  return geom;
 }
 
 /**

+ 5 - 0
panda/src/gobj/perspectiveLens.cxx

@@ -71,9 +71,14 @@ do_compute_projection_mat(Lens::CData *lens_cdata) {
   PN_stdfloat fNear = do_get_near(lens_cdata);
   PN_stdfloat a, b;
 
+  // Take the limits if either near or far is infinite.
   if (cinf(fFar)) {
     a = 1;
     b = -2 * fNear;
+  } else if (cinf(fNear)) {
+    // This is valid if the near/far planes are inverted.
+    a = -1;
+    b = 2 * fFar;
   } else {
     PN_stdfloat far_minus_near = fFar-fNear;
     a = (fFar + fNear);

+ 24 - 8
panda/src/gobj/shader.cxx

@@ -622,12 +622,29 @@ cg_recurse_parameters(CGparameter parameter, const ShaderType &type,
             p._type       = arg_type;
             p._direction  = arg_dir;
             p._varying    = (vbl == CG_VARYING);
-            p._integer    = (base_type == CG_UINT || base_type == CG_INT ||
-                             base_type == CG_ULONG || base_type == CG_LONG ||
-                             base_type == CG_USHORT || base_type == CG_SHORT ||
-                             base_type == CG_UCHAR || base_type == CG_CHAR);
             p._cat        = shader_cat.get_safe_ptr();
 
+            //NB. Cg does have a CG_DOUBLE type, but at least for the ARB
+            // profiles and GLSL profiles it just maps to float.
+            switch (base_type) {
+            case CG_UINT:
+            case CG_ULONG:
+            case CG_USHORT:
+            case CG_UCHAR:
+            case CG_BOOL:
+              p._numeric_type = SPT_uint;
+              break;
+            case CG_INT:
+            case CG_LONG:
+            case CG_SHORT:
+            case CG_CHAR:
+              p._numeric_type = SPT_int;
+              break;
+            default:
+              p._numeric_type = SPT_float;
+              break;
+            }
+
             success &= compile_parameter(p, arg_dim);
             break;
           }
@@ -684,7 +701,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
     ShaderVarSpec bind;
     bind._id = p._id;
     bind._append_uv = -1;
-    bind._integer = p._integer;
+    bind._numeric_type = p._numeric_type;
 
     if (pieces.size() == 2) {
       if (pieces[1] == "position") {
@@ -3073,7 +3090,7 @@ spirv_analyze_shader(const string &data) {
           spec._name = InternalName::make(var._name);
           spec._append_uv = false;
           spec._elements = 1;
-          spec._integer = false;
+          spec._numeric_type = SPT_float;
           _var_spec.push_back(spec);
         }
         break;
@@ -3658,8 +3675,7 @@ parse_eof() {
  */
 PT(AsyncFuture) Shader::
 prepare(PreparedGraphicsObjects *prepared_objects) {
-  PT(PreparedGraphicsObjects::EnqueuedObject) obj = prepared_objects->enqueue_shader_future(this);
-  return obj.p();
+  return prepared_objects->enqueue_shader_future(this);
 }
 
 /**

+ 10 - 9
panda/src/gobj/shader.h

@@ -333,6 +333,14 @@ public:
     int        _seqno;
   };
 
+  enum ShaderPtrType {
+    SPT_float,
+    SPT_double,
+    SPT_int,
+    SPT_uint,
+    SPT_unknown
+  };
+
   struct ShaderArgInfo {
     ShaderArgId       _id;
     ShaderArgClass    _class;
@@ -340,17 +348,10 @@ public:
     ShaderArgType     _type;
     ShaderArgDir      _direction;
     bool              _varying;
-    bool              _integer;
+    ShaderPtrType     _numeric_type;
     NotifyCategory   *_cat;
   };
 
-  enum ShaderPtrType {
-    SPT_float,
-    SPT_double,
-    SPT_int,
-    SPT_unknown
-  };
-
   // Container structure for data of parameters ShaderPtrSpec.
   struct ShaderPtrData {
   private:
@@ -426,7 +427,7 @@ public:
     PT(InternalName)  _name;
     int               _append_uv;
     int               _elements;
-    bool              _integer;
+    ShaderPtrType     _numeric_type;
   };
 
   struct ShaderPtrSpec {

+ 8 - 4
panda/src/gobj/shaderBuffer.I

@@ -19,8 +19,7 @@ INLINE ShaderBuffer::
 ShaderBuffer(const std::string &name, uint64_t size, UsageHint usage_hint) :
   Namable(name),
   _data_size_bytes(size),
-  _usage_hint(usage_hint),
-  _contexts(nullptr) {
+  _usage_hint(usage_hint) {
 }
 
 /**
@@ -32,8 +31,13 @@ ShaderBuffer(const std::string &name, vector_uchar initial_data, UsageHint usage
   Namable(name),
   _data_size_bytes(initial_data.size()),
   _usage_hint(usage_hint),
-  _initial_data(initial_data),
-  _contexts(nullptr) {
+  _initial_data(std::move(initial_data)) {
+
+  // Make sure it is padded to 16 bytes.  Some drivers like that.
+  if ((_initial_data.size() & 15u) != 0) {
+    _initial_data.resize((_initial_data.size() + 15u) & ~15u, 0);
+    _data_size_bytes = _initial_data.size();
+  }
 }
 
 /**

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

@@ -193,7 +193,7 @@ fillin(DatagramIterator &scan, BamReader *manager) {
 
   if (scan.get_bool() && _data_size_bytes > 0) {
     nassertv_always(_data_size_bytes <= scan.get_remaining_size());
-    _initial_data.resize(_data_size_bytes);
+    _initial_data.resize((_data_size_bytes + 15u) & ~15u);
     scan.extract_bytes(&_initial_data[0], _data_size_bytes);
   } else {
     _initial_data.clear();

+ 1 - 1
panda/src/gobj/shaderBuffer.h

@@ -63,7 +63,7 @@ private:
   vector_uchar _initial_data;
 
   typedef pmap<PreparedGraphicsObjects *, BufferContext *> Contexts;
-  Contexts *_contexts;
+  Contexts *_contexts = nullptr;
 
 public:
   static void register_with_read_factory();

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

@@ -2342,6 +2342,24 @@ get_unsigned_int(const unsigned char *&p) {
   return (double)v.ui / 4294967295.0;
 }
 
+/**
+ * This is used by store() to retrieve the next consecutive component value
+ * from the indicated element of the array, which is taken to be an array of
+ * unsigned ints with the value packed in the 24 least significant bits.
+ */
+INLINE double Texture::
+get_unsigned_int_24(const unsigned char *&p) {
+  union {
+    uint32_t ui;
+    uint8_t uc[4];
+  } v;
+  v.uc[0] = (*p++);
+  v.uc[1] = (*p++);
+  v.uc[2] = (*p++);
+  v.uc[3] = (*p++);
+  return (double)(v.ui & 0xffffff) / (double)0xffffff;
+}
+
 /**
  * This is used by store() to retrieve the next consecutive component value
  * from the indicated element of the array, which is taken to be an array of

+ 1 - 2
panda/src/gobj/texture.cxx

@@ -1427,8 +1427,7 @@ peek() {
  */
 PT(AsyncFuture) Texture::
 prepare(PreparedGraphicsObjects *prepared_objects) {
-  PT(PreparedGraphicsObjects::EnqueuedObject) obj = prepared_objects->enqueue_texture_future(this);
-  return obj.p();
+  return prepared_objects->enqueue_texture_future(this);
 }
 
 /**

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

@@ -858,6 +858,7 @@ private:
   INLINE static double get_unsigned_byte(const unsigned char *&p);
   INLINE static double get_unsigned_short(const unsigned char *&p);
   INLINE static double get_unsigned_int(const unsigned char *&p);
+  INLINE static double get_unsigned_int_24(const unsigned char *&p);
   INLINE static double get_float(const unsigned char *&p);
   INLINE static double get_half_float(const unsigned char *&p);
 

+ 6 - 0
panda/src/gobj/texturePeeker.cxx

@@ -94,6 +94,10 @@ TexturePeeker(Texture *tex, Texture::CData *cdata) {
     _get_component = Texture::get_half_float;
     break;
 
+  case Texture::T_unsigned_int_24_8:
+    _get_component = Texture::get_unsigned_int_24;
+    break;
+
   default:
     // Not supported.
     _image.clear();
@@ -108,6 +112,8 @@ TexturePeeker(Texture *tex, Texture::CData *cdata) {
   case Texture::F_depth_component32:
   case Texture::F_red:
   case Texture::F_r16:
+  case Texture::F_r32:
+  case Texture::F_r32i:
     _get_texel = get_texel_r;
     break;
 

+ 1 - 1
panda/src/grutil/cardMaker.cxx

@@ -133,7 +133,7 @@ generate() {
 
   gnode->add_geom(geom, state);
 
-  return gnode.p();
+  return gnode;
 }
 
 /**

+ 1 - 1
panda/src/grutil/fisheyeMaker.cxx

@@ -322,7 +322,7 @@ generate() {
     }
   }
 
-  return geom_node.p();
+  return geom_node;
 }
 
 /**

+ 1 - 1
panda/src/grutil/movieTexture.cxx

@@ -409,7 +409,7 @@ make_copy_impl() const {
   CDWriter cdata_copy(copy->_cycler, true);
   copy->do_assign(cdata_copy, cdata_copy_tex, this, cdata, cdata_tex);
 
-  return copy.p();
+  return copy;
 }
 
 /**

+ 14 - 3
panda/src/mathutil/frustum_src.I

@@ -140,7 +140,6 @@ get_perspective_projection_mat(CoordinateSystem cs) const {
     cs = get_default_coordinate_system();
   }
 
-  FLOATTYPE recip_far_minus_near = 1.0f/(_ffar - _fnear);
   FLOATTYPE recip_r_minus_l = 1.0f/(_r - _l);
   FLOATTYPE recip_t_minus_b = 1.0f/(_t - _b);
   FLOATTYPE two_fnear = 2.0f*_fnear;
@@ -149,8 +148,20 @@ get_perspective_projection_mat(CoordinateSystem cs) const {
   FLOATTYPE a = two_fnear * recip_r_minus_l;
   FLOATTYPE e = two_fnear * recip_t_minus_b;
   FLOATTYPE b = (_t + _b) * recip_t_minus_b;
-  FLOATTYPE c = (_ffar + _fnear) * recip_far_minus_near;
-  FLOATTYPE f = -_ffar * two_fnear * recip_far_minus_near;
+  FLOATTYPE c, f;
+
+  // Take the limits if either near or far is infinite.
+  if (cinf(_ffar)) {
+    c = 1;
+    f = -2 * _fnear;
+  } else if (cinf(_fnear)) {
+    c = -1;
+    f = 2 * _ffar;
+  } else {
+    FLOATTYPE recip_far_minus_near = 1.0f / (_ffar - _fnear);
+    c = (_ffar + _fnear) * recip_far_minus_near;
+    f = -_ffar * two_fnear * recip_far_minus_near;
+  }
 
 /*
   FLOATTYPE a = (2.0f * _fnear) / (_r - _l);

+ 31 - 0
panda/src/mathutil/plane_src.I

@@ -137,6 +137,37 @@ dist_to_plane(const FLOATNAME(LPoint3) &point) const {
   return (_v(0) * point[0] + _v(1) * point[1] + _v(2) * point[2] + _v(3));
 }
 
+/**
+ * Normalizes the plane in place.  Returns true if the plane was normalized,
+ * false if the plane had a zero-length normal vector.
+ */
+INLINE_MATHUTIL bool FLOATNAME(LPlane)::
+normalize() {
+  FLOATTYPE l2 = get_normal().length_squared();
+  if (l2 == (FLOATTYPE)0.0f) {
+    return false;
+
+  } else if (!IS_THRESHOLD_EQUAL(l2, 1.0f, NEARLY_ZERO(FLOATTYPE) * NEARLY_ZERO(FLOATTYPE))) {
+    (*this) /= csqrt(l2);
+  }
+
+  return true;
+}
+
+/**
+ * Normalizes the plane and returns the normalized plane as a copy.  If the
+ * plane's normal was a zero-length vector, the same plane is returned.
+ */
+INLINE_MATHUTIL FLOATNAME(LPlane) FLOATNAME(LPlane)::
+normalized() const {
+  FLOATTYPE l2 = get_normal().length_squared();
+  if (l2 != (FLOATTYPE)0.0f) {
+    return (*this) / csqrt(l2);
+  } else {
+    return (*this);
+  }
+}
+
 /**
  * Returns the point within the plane nearest to the indicated point in space.
  */

+ 3 - 0
panda/src/mathutil/plane_src.h

@@ -39,6 +39,9 @@ PUBLISHED:
   FLOATNAME(LPoint3) get_point() const;
 
   INLINE_MATHUTIL FLOATTYPE dist_to_plane(const FLOATNAME(LPoint3) &point) const;
+
+  INLINE_MATHUTIL bool normalize();
+  INLINE_MATHUTIL FLOATNAME(LPlane) normalized() const;
   INLINE_MATHUTIL FLOATNAME(LPoint3) project(const FLOATNAME(LPoint3) &point) const;
   INLINE_MATHUTIL void flip();
 

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

@@ -24,7 +24,7 @@
  */
 class EXPCL_PANDA_PGRAPH CacheStats {
 public:
-  constexpr CacheStats() = default;
+  CacheStats() = default;
   void init();
   void reset(double now);
   void write(std::ostream &out, const char *name) const;

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

@@ -40,7 +40,7 @@ munge_state(const RenderState *state) {
   }
 
   CPT(RenderState) result = munge_state_impl(state);
-  munged_states.store(id, result.p());
+  munged_states.store(id, result);
 
   return result;
 }

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

@@ -77,7 +77,7 @@ ShaderGenerator(const GraphicsStateGuardianBase *gsg) {
 #ifdef _WIN32
   _use_generic_attr = !gsg->get_supports_hlsl();
 #else
-  _use_generic_attr = false;
+  _use_generic_attr = true;
 #endif
 
   // Do we want to use the ARB_shadow extension?  This also allows us to use

+ 4 - 4
panda/src/pgui/pgFrameStyle.cxx

@@ -257,7 +257,7 @@ generate_flat_geom(const LVecBase4 &frame) {
   geom->add_primitive(strip);
   gnode->add_geom(geom, state);
 
-  return gnode.p();
+  return gnode;
 }
 
 /**
@@ -431,7 +431,7 @@ generate_bevel_geom(const LVecBase4 &frame, bool in) {
   }
   gnode->add_geom(geom, state);
 
-  return gnode.p();
+  return gnode;
 }
 
 /**
@@ -663,7 +663,7 @@ generate_groove_geom(const LVecBase4 &frame, bool in) {
   }
   gnode->add_geom(geom, state);
 
-  return gnode.p();
+  return gnode;
 }
 
 /**
@@ -803,5 +803,5 @@ generate_texture_border_geom(const LVecBase4 &frame) {
   geom->add_primitive(strip);
   gnode->add_geom(geom, state);
 
-  return gnode.p();
+  return gnode;
 }

+ 13 - 0
panda/src/pgui/pgItem.I

@@ -202,6 +202,19 @@ get_suppress_flags() const {
   return _region->get_suppress_flags();
 }
 
+/**
+ * Returns the Node that is the root of the subgraph that will be drawn when
+ * the PGItem is in the indicated state.  The first time this is called for a
+ * particular state index, it may create the Node.
+ */
+INLINE NodePath &PGItem::
+get_state_def(int state) {
+  nassertr(state >= 0 && state < 1000, get_state_def(0));  // Sanity check.
+
+  LightReMutexHolder holder(_lock);
+  return do_get_state_def(state);
+}
+
 /**
  * Returns the unique ID assigned to this PGItem.  This will be assigned to
  * the region created with the MouseWatcher, and will thus be used to generate

+ 79 - 54
panda/src/pgui/pgItem.cxx

@@ -35,8 +35,6 @@
 #include "audioSound.h"
 #endif
 
-using std::max;
-using std::min;
 using std::string;
 
 TypeHandle PGItem::_type_handle;
@@ -59,16 +57,15 @@ is_right(const LVector2 &v1, const LVector2 &v2) {
 PGItem::
 PGItem(const string &name) :
   PandaNode(name),
-  _lock(name)
+  _lock(name),
+  _notify(nullptr),
+  _has_frame(false),
+  _frame(0, 0, 0, 0),
+  _region(new PGMouseWatcherRegion(this)),
+  _state(0),
+  _flags(0)
 {
   set_cull_callback();
-
-  _notify = nullptr;
-  _has_frame = false;
-  _frame.set(0, 0, 0, 0);
-  _region = new PGMouseWatcherRegion(this);
-  _state = 0;
-  _flags = 0;
 }
 
 /**
@@ -96,17 +93,16 @@ PGItem::
 PGItem::
 PGItem(const PGItem &copy) :
   PandaNode(copy),
+  _notify(nullptr),
   _has_frame(copy._has_frame),
   _frame(copy._frame),
   _state(copy._state),
-  _flags(copy._flags)
+  _flags(copy._flags),
+  _region(new PGMouseWatcherRegion(this))
 #ifdef HAVE_AUDIO
   , _sounds(copy._sounds)
 #endif
 {
-  _notify = nullptr;
-  _region = new PGMouseWatcherRegion(this);
-
   // We give our region the same name as the region for the PGItem we're
   // copying--so that this PGItem will generate the same event names when the
   // user interacts with it.
@@ -190,9 +186,29 @@ draw_mask_changed() {
  */
 bool PGItem::
 cull_callback(CullTraverser *trav, CullTraverserData &data) {
-  LightReMutexHolder holder(_lock);
-  bool this_node_hidden = data.is_this_node_hidden(trav->get_camera_mask());
-  if (!this_node_hidden && has_frame() && get_active()) {
+  // We try not to hold the lock for longer than necessary.
+  PT(PandaNode) state_def_root;
+  bool has_frame;
+  PGMouseWatcherRegion *region;
+  {
+    LightReMutexHolder holder(_lock);
+    has_frame = _has_frame && ((_flags & F_active) != 0);
+    region = _region;
+
+    int state = _state;
+    if (state >= 0 && (size_t)state < _state_defs.size()) {
+      StateDef &state_def = _state_defs[state];
+      if (!state_def._root.is_empty()) {
+        if (state_def._frame_stale) {
+          update_frame(state);
+        }
+
+        state_def_root = state_def._root.node();
+      }
+    }
+  }
+
+  if (has_frame && !data.is_this_node_hidden(trav->get_camera_mask())) {
     // The item has a frame, so we want to generate a region for it and update
     // the MouseWatcher.
 
@@ -202,8 +218,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
       PGCullTraverser *pg_trav;
       DCAST_INTO_R(pg_trav, trav, true);
 
-      CPT(TransformState) net_transform = data.get_net_transform(trav);
-      const LMatrix4 &transform = net_transform->get_mat();
+      const LMatrix4 &transform = data.get_net_transform(trav)->get_mat();
 
       // Consider the cull bin this object is in.  Since the binning affects
       // the render order, we want bins that render later to get higher sort
@@ -240,19 +255,20 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
       // the existing interface which only provides one.
       sort = (bin_sort << 16) | ((sort + 0x8000) & 0xffff);
 
-      if (activate_region(transform, sort,
-                          DCAST(ClipPlaneAttrib, data._state->get_attrib(ClipPlaneAttrib::get_class_slot())),
-                          DCAST(ScissorAttrib, data._state->get_attrib(ScissorAttrib::get_class_slot())))) {
-        pg_trav->_top->add_region(get_region());
+      const ClipPlaneAttrib *clip = nullptr;
+      const ScissorAttrib *scissor = nullptr;
+      data._state->get_attrib(clip);
+      data._state->get_attrib(scissor);
+      if (activate_region(transform, sort, clip, scissor)) {
+        pg_trav->_top->add_region(region);
       }
     }
   }
 
-  if (has_state_def(get_state())) {
+  if (state_def_root != nullptr) {
     // This item has a current state definition that we should use to render
     // the item.
-    NodePath &root = get_state_def(get_state());
-    CullTraverserData next_data(data, root.node());
+    CullTraverserData next_data(data, state_def_root);
     trav->traverse(next_data);
   }
 
@@ -306,7 +322,7 @@ compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
   // get_state_def() on each one, to ensure that the frames are updated
   // correctly before we measure their bounding volumes.
   for (int i = 0; i < (int)_state_defs.size(); i++) {
-    NodePath &root = ((PGItem *)this)->get_state_def(i);
+    NodePath &root = ((PGItem *)this)->do_get_state_def(i);
     if (!root.is_empty()) {
       PandaNode *node = root.node();
       child_volumes.push_back(node->get_bounds(current_thread));
@@ -388,6 +404,9 @@ bool PGItem::
 activate_region(const LMatrix4 &transform, int sort,
                 const ClipPlaneAttrib *cpa,
                 const ScissorAttrib *sa) {
+  using std::min;
+  using std::max;
+
   LightReMutexHolder holder(_lock);
   // Transform all four vertices, and get the new bounding box.  This way the
   // region works (mostly) even if has been rotated.
@@ -935,30 +954,6 @@ clear_state_def(int state) {
   mark_internal_bounds_stale();
 }
 
-/**
- * Returns the Node that is the root of the subgraph that will be drawn when
- * the PGItem is in the indicated state.  The first time this is called for a
- * particular state index, it may create the Node.
- */
-NodePath &PGItem::
-get_state_def(int state) {
-  LightReMutexHolder holder(_lock);
-  nassertr(state >= 0 && state < 1000, get_state_def(0));  // Sanity check.
-  slot_state_def(state);
-
-  if (_state_defs[state]._root.is_empty()) {
-    // Create a new node.
-    _state_defs[state]._root = NodePath("state_" + format_string(state));
-    _state_defs[state]._frame_stale = true;
-  }
-
-  if (_state_defs[state]._frame_stale) {
-    update_frame(state);
-  }
-
-  return _state_defs[state]._root;
-}
-
 /**
  * Parents an instance of the bottom node of the indicated NodePath to the
  * indicated state index.
@@ -973,7 +968,7 @@ instance_to_state_def(int state, const NodePath &path) {
 
   mark_internal_bounds_stale();
 
-  return path.instance_to(get_state_def(state));
+  return path.instance_to(do_get_state_def(state));
 }
 
 /**
@@ -998,7 +993,7 @@ set_frame_style(int state, const PGFrameStyle &style) {
   LightReMutexHolder holder(_lock);
   // Get the state def node, mainly to ensure that this state is slotted and
   // listed as having been defined.
-  NodePath &root = get_state_def(state);
+  NodePath &root = do_get_state_def(state);
   nassertv(!root.is_empty());
 
   _state_defs[state]._frame_style = style;
@@ -1097,6 +1092,9 @@ play_sound(const string &event) {
  */
 void PGItem::
 reduce_region(LVecBase4 &frame, PGItem *obscurer) const {
+  using std::min;
+  using std::max;
+
   if (obscurer != nullptr && !obscurer->is_overall_hidden()) {
     LVecBase4 oframe = get_relative_frame(obscurer);
 
@@ -1124,6 +1122,9 @@ reduce_region(LVecBase4 &frame, PGItem *obscurer) const {
  */
 LVecBase4 PGItem::
 get_relative_frame(PGItem *item) const {
+  using std::min;
+  using std::max;
+
   NodePath this_np = NodePath::any_path((PGItem *)this);
   NodePath item_np = this_np.find_path_to(item);
   if (item_np.is_empty()) {
@@ -1174,6 +1175,30 @@ frame_changed() {
   }
 }
 
+/**
+ * Returns the Node that is the root of the subgraph that will be drawn when
+ * the PGItem is in the indicated state.  The first time this is called for a
+ * particular state index, it may create the Node.
+ *
+ * Assumes the lock is already held.
+ */
+NodePath &PGItem::
+do_get_state_def(int state) {
+  slot_state_def(state);
+
+  if (_state_defs[state]._root.is_empty()) {
+    // Create a new node.
+    _state_defs[state]._root = NodePath("state_" + format_string(state));
+    _state_defs[state]._frame_stale = true;
+  }
+
+  if (_state_defs[state]._frame_stale) {
+    update_frame(state);
+  }
+
+  return _state_defs[state]._root;
+}
+
 /**
  * Ensures there is a slot in the array for the given state definition.
  */
@@ -1200,7 +1225,7 @@ update_frame(int state) {
 
   // Now create new frame geometry.
   if (has_frame()) {
-    NodePath &root = get_state_def(state);
+    NodePath &root = do_get_state_def(state);
     _state_defs[state]._frame =
       _state_defs[state]._frame_style.generate_into(root, _frame);
   }

+ 5 - 3
panda/src/pgui/pgItem.h

@@ -77,11 +77,12 @@ protected:
                                GeomTransformer &transformer,
                                Thread *current_thread);
 
-public:
   virtual void xform(const LMatrix4 &mat);
   bool activate_region(const LMatrix4 &transform, int sort,
                        const ClipPlaneAttrib *cpa,
                        const ScissorAttrib *sa);
+
+public:
   INLINE PGMouseWatcherRegion *get_region() const;
 
   virtual void enter_region(const MouseWatcherParameter &param);
@@ -130,7 +131,7 @@ PUBLISHED:
   int get_num_state_defs() const;
   void clear_state_def(int state);
   bool has_state_def(int state) const;
-  NodePath &get_state_def(int state);
+  INLINE NodePath &get_state_def(int state);
   MAKE_SEQ(get_state_defs, get_num_state_defs, get_state_def);
   NodePath instance_to_state_def(int state, const NodePath &path);
 
@@ -187,6 +188,7 @@ protected:
   virtual void frame_changed();
 
 private:
+  NodePath &do_get_state_def(int state);
   void slot_state_def(int state);
   void update_frame(int state);
   void mark_frames_stale();
@@ -215,7 +217,7 @@ private:
   };
   int _flags;
 
-  PT(PGMouseWatcherRegion) _region;
+  PT(PGMouseWatcherRegion) const _region;
 
   LMatrix4 _frame_inv_xform;
 

+ 1 - 1
panda/src/speedtree/loaderFileTypeSrt.cxx

@@ -68,5 +68,5 @@ load_file(const Filename &path, const LoaderOptions &,
   PT(SpeedTreeNode) st = new SpeedTreeNode(path.get_basename());
   st->add_instance(tree, STTransform());
 
-  return st.p();
+  return st;
 }

+ 1 - 1
panda/src/speedtree/loaderFileTypeStf.cxx

@@ -62,5 +62,5 @@ load_file(const Filename &path, const LoaderOptions &options,
   PT(SpeedTreeNode) st = new SpeedTreeNode(path.get_basename());
   st->add_from_stf(path, options);
 
-  return st.p();
+  return st;
 }

+ 51 - 51
panda/src/text/textAssembler.cxx

@@ -1137,52 +1137,30 @@ generate_quads(GeomNode *geom_node, const QuadMap &quad_map) {
     GeomTextGlyph::Glyphs glyphs;
     glyphs.reserve(quads.size());
 
-    static CPT(GeomVertexFormat) format;
-    if (format.is_null()) {
-      // The optimized code below assumes 32-bit floats, so let's make sure we
-      // got the right format by creating it ourselves.
-      format = GeomVertexFormat::register_format(new GeomVertexArrayFormat(
-        InternalName::get_vertex(), 3, GeomEnums::NT_float32, GeomEnums::C_point,
-        InternalName::get_texcoord(), 2, GeomEnums::NT_float32, GeomEnums::C_texcoord));
-    }
-
+    const GeomVertexFormat *format = GeomVertexFormat::get_v3t2();
     PT(GeomVertexData) vdata = new GeomVertexData("text", format, Geom::UH_static);
 
-    PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_static);
-    if (quads.size() > 10922) {
-      tris->set_index_type(GeomEnums::NT_uint32);
-    } else {
-      tris->set_index_type(GeomEnums::NT_uint16);
-    }
-
-    int i = 0;
+    Thread *current_thread = Thread::get_current_thread();
 
     // This is quite a critical loop and GeomVertexWriter quickly becomes the
     // bottleneck.  So, I've written this out the hard way instead.  Two
-    // versions of the loop: one for 32-bit indices, one for 16-bit.
+    // versions of the loop: one for 32-bit floats, the other for 64-bit.
     {
       PT(GeomVertexArrayDataHandle) vtx_handle = vdata->modify_array_handle(0);
       vtx_handle->unclean_set_num_rows(quads.size() * 4);
 
-      Thread *current_thread = Thread::get_current_thread();
       unsigned char *write_ptr = vtx_handle->get_write_pointer();
-      size_t stride = format->get_array(0)->get_stride() / sizeof(PN_float32);
-
-      PN_float32 *vtx_ptr = (PN_float32 *)
-        (write_ptr + format->get_column(InternalName::get_vertex())->get_start());
-      PN_float32 *tex_ptr = (PN_float32 *)
-        (write_ptr + format->get_column(InternalName::get_texcoord())->get_start());
 
-      if (tris->get_index_type() == GeomEnums::NT_uint32) {
-        // 32-bit index case.
-        PT(GeomVertexArrayDataHandle) idx_handle = tris->modify_vertices_handle(current_thread);
-        idx_handle->unclean_set_num_rows(quads.size() * 6);
-        uint32_t *idx_ptr = (uint32_t *)idx_handle->get_write_pointer();
+      if (format->get_vertex_column()->get_numeric_type() == GeomEnums::NT_float32) {
+        // 32-bit vertex case.
+        size_t stride = format->get_array(0)->get_stride() / sizeof(PN_float32);
 
-        QuadDefs::const_iterator qi;
-        for (qi = quads.begin(); qi != quads.end(); ++qi) {
-          const QuadDef &quad = (*qi);
+        PN_float32 *vtx_ptr = (PN_float32 *)
+          (write_ptr + format->get_column(InternalName::get_vertex())->get_start());
+        PN_float32 *tex_ptr = (PN_float32 *)
+          (write_ptr + format->get_column(InternalName::get_texcoord())->get_start());
 
+        for (const QuadDef &quad : quads) {
           vtx_ptr[0] = quad._dimensions[0] + quad._slanth;
           vtx_ptr[1] = 0;
           vtx_ptr[2] = quad._dimensions[3];
@@ -1219,26 +1197,18 @@ generate_quads(GeomNode *geom_node, const QuadMap &quad_map) {
           tex_ptr[1] = quad._uvs[1];
           tex_ptr += stride;
 
-          *(idx_ptr++) = i + 0;
-          *(idx_ptr++) = i + 1;
-          *(idx_ptr++) = i + 2;
-          *(idx_ptr++) = i + 2;
-          *(idx_ptr++) = i + 1;
-          *(idx_ptr++) = i + 3;
-          i += 4;
-
           glyphs.push_back(move(quad._glyph));
         }
       } else {
-        // 16-bit index case.
-        PT(GeomVertexArrayDataHandle) idx_handle = tris->modify_vertices_handle(current_thread);
-        idx_handle->unclean_set_num_rows(quads.size() * 6);
-        uint16_t *idx_ptr = (uint16_t *)idx_handle->get_write_pointer();
+        // 64-bit vertex case.
+        size_t stride = format->get_array(0)->get_stride() / sizeof(PN_float64);
 
-        QuadDefs::const_iterator qi;
-        for (qi = quads.begin(); qi != quads.end(); ++qi) {
-          const QuadDef &quad = (*qi);
+        PN_float64 *vtx_ptr = (PN_float64 *)
+          (write_ptr + format->get_column(InternalName::get_vertex())->get_start());
+        PN_float64 *tex_ptr = (PN_float64 *)
+          (write_ptr + format->get_column(InternalName::get_texcoord())->get_start());
 
+        for (const QuadDef &quad : quads) {
           vtx_ptr[0] = quad._dimensions[0] + quad._slanth;
           vtx_ptr[1] = 0;
           vtx_ptr[2] = quad._dimensions[3];
@@ -1275,21 +1245,51 @@ generate_quads(GeomNode *geom_node, const QuadMap &quad_map) {
           tex_ptr[1] = quad._uvs[1];
           tex_ptr += stride;
 
+          glyphs.push_back(move(quad._glyph));
+        }
+      }
+    }
+
+    // Now write the indices.  Two cases: 32-bit indices and 16-bit indices.
+    int vtx_count = quads.size() * 4;
+    PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_static);
+    if (vtx_count > 65535) {
+      tris->set_index_type(GeomEnums::NT_uint32);
+    } else {
+      tris->set_index_type(GeomEnums::NT_uint16);
+    }
+    {
+      PT(GeomVertexArrayDataHandle) idx_handle = tris->modify_vertices_handle(current_thread);
+      idx_handle->unclean_set_num_rows(quads.size() * 6);
+      if (tris->get_index_type() == GeomEnums::NT_uint16) {
+        // 16-bit index case.
+        uint16_t *idx_ptr = (uint16_t *)idx_handle->get_write_pointer();
+
+        for (int i = 0; i < vtx_count; i += 4) {
           *(idx_ptr++) = i + 0;
           *(idx_ptr++) = i + 1;
           *(idx_ptr++) = i + 2;
           *(idx_ptr++) = i + 2;
           *(idx_ptr++) = i + 1;
           *(idx_ptr++) = i + 3;
-          i += 4;
+        }
+      } else {
+        // 32-bit index case.
+        uint32_t *idx_ptr = (uint32_t *)idx_handle->get_write_pointer();
 
-          glyphs.push_back(move(quad._glyph));
+        for (int i = 0; i < vtx_count; i += 4) {
+          *(idx_ptr++) = i + 0;
+          *(idx_ptr++) = i + 1;
+          *(idx_ptr++) = i + 2;
+          *(idx_ptr++) = i + 2;
+          *(idx_ptr++) = i + 1;
+          *(idx_ptr++) = i + 3;
         }
       }
     }
 
     // We can compute this value much faster than GeomPrimitive can.
-    tris->set_minmax(0, i - 1, nullptr, nullptr);
+    tris->set_minmax(0, vtx_count - 1, nullptr, nullptr);
 
     PT(GeomTextGlyph) geom = new GeomTextGlyph(vdata);
     geom->_glyphs.swap(glyphs);

+ 3 - 3
panda/src/text/textNode.cxx

@@ -755,7 +755,7 @@ make_frame() {
     frame_node->add_geom(geom2, state);
   }
 
-  return frame_node.p();
+  return frame_node;
 }
 
 /**
@@ -795,7 +795,7 @@ make_card() {
 
   card_node->add_geom(geom);
 
-  return card_node.p();
+  return card_node;
 }
 
 
@@ -896,7 +896,7 @@ make_card_with_border() {
 
   card_node->add_geom(geom);
 
-  return card_node.p();
+  return card_node;
 }
 
 /**

+ 1 - 1
panda/src/vision/openCVTexture.cxx

@@ -98,7 +98,7 @@ make_copy_impl() const {
   Texture::CDWriter cdata_copy_tex(copy->Texture::_cycler, true);
   copy->do_assign(cdata_copy_tex, this, cdata_tex);
 
-  return copy.p();
+  return copy;
 }
 
 /**

+ 8 - 3
panda/src/wgldisplay/wglGraphicsPipe.cxx

@@ -22,6 +22,7 @@ TypeHandle wglGraphicsPipe::_type_handle;
 bool    wglGraphicsPipe::_current_valid;
 HDC     wglGraphicsPipe::_current_hdc;
 HGLRC   wglGraphicsPipe::_current_hglrc;
+Thread *wglGraphicsPipe::_current_thread;
 
 /**
  *
@@ -41,16 +42,19 @@ wglGraphicsPipe::
 /**
  * a thin wrapper around wglMakeCurrent to avoid unnecessary OS-call overhead.
  */
-void wglGraphicsPipe::
+bool wglGraphicsPipe::
 wgl_make_current(HDC hdc, HGLRC hglrc, PStatCollector *collector) {
+  Thread *thread = Thread::get_current_thread();
   if ((_current_valid) &&
       (_current_hdc == hdc) &&
-      (_current_hglrc == hglrc)) {
-    return;
+      (_current_hglrc == hglrc) &&
+      (_current_thread == thread)) {
+    return true;
   }
   _current_valid = true;
   _current_hdc = hdc;
   _current_hglrc = hglrc;
+  _current_thread = thread;
   BOOL res;
   if (collector) {
     PStatTimer timer(*collector);
@@ -58,6 +62,7 @@ wgl_make_current(HDC hdc, HGLRC hglrc, PStatCollector *collector) {
   } else {
     res = wglMakeCurrent(hdc, hglrc);
   }
+  return (res != 0);
 }
 
 /**

+ 2 - 1
panda/src/wgldisplay/wglGraphicsPipe.h

@@ -46,11 +46,12 @@ protected:
 private:
 
   static std::string format_pfd_flags(DWORD pfd_flags);
-  static void wgl_make_current(HDC hdc, HGLRC hglrc, PStatCollector *collector);
+  static bool wgl_make_current(HDC hdc, HGLRC hglrc, PStatCollector *collector);
 
   static bool  _current_valid;
   static HDC   _current_hdc;
   static HGLRC _current_hglrc;
+  static Thread *_current_thread;
 
 public:
   static TypeHandle get_class_type() {

+ 6 - 1
panda/src/wgldisplay/wglGraphicsStateGuardian.cxx

@@ -319,7 +319,12 @@ choose_pixel_format(const FrameBufferProperties &properties,
     return;
   }
 
-  wglGraphicsPipe::wgl_make_current(twindow_dc, twindow_ctx, nullptr);
+  if (!wglGraphicsPipe::wgl_make_current(twindow_dc, twindow_ctx, nullptr)) {
+    wgldisplay_cat.error()
+      << "Failed to make WGL context current.\n";
+    wglDeleteContext(twindow_ctx);
+    return;
+  }
 
   _extensions.clear();
   save_extensions((const char *)GLP(GetString)(GL_EXTENSIONS));

+ 5 - 1
panda/src/wgldisplay/wglGraphicsWindow.cxx

@@ -79,7 +79,11 @@ begin_frame(FrameMode mode, Thread *current_thread) {
   HGLRC context = wglgsg->get_context(_hdc);
   nassertr(context, false);
 
-  wglGraphicsPipe::wgl_make_current(_hdc, context, &_make_current_pcollector);
+  if (!wglGraphicsPipe::wgl_make_current(_hdc, context, &_make_current_pcollector)) {
+    wgldisplay_cat.error()
+      << "Failed to make WGL context current.\n";
+    return false;
+  }
   wglgsg->reset_if_new();
 
   if (mode == FM_render) {

+ 4 - 8
panda/src/windisplay/winGraphicsWindow.cxx

@@ -134,15 +134,11 @@ get_pointer(int device) const {
 
     // We recheck this immediately to get the most up-to-date value.
     POINT cpos;
-    if (device == 0 && GetCursorPos(&cpos) && ScreenToClient(_hWnd, &cpos)) {
+    if (device == 0 && result._in_window && GetCursorPos(&cpos) && ScreenToClient(_hWnd, &cpos)) {
       double time = ClockObject::get_global_clock()->get_real_time();
-      RECT view_rect;
-      if (GetClientRect(_hWnd, &view_rect)) {
-        result._in_window = PtInRect(&view_rect, cpos);
-        result._xpos = cpos.x;
-        result._ypos = cpos.y;
-        ((GraphicsWindowInputDevice &)_input_devices[0]).set_pointer(result._in_window, result._xpos, result._ypos, time);
-      }
+      result._xpos = cpos.x;
+      result._ypos = cpos.y;
+      ((GraphicsWindowInputDevice &)_input_devices[0]).set_pointer(result._in_window, result._xpos, result._ypos, time);
     }
   }
   return result;

+ 22 - 8
panda/src/x11display/x11GraphicsWindow.cxx

@@ -136,10 +136,11 @@ x11GraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
  */
 x11GraphicsWindow::
 ~x11GraphicsWindow() {
-  pmap<Filename, X11_Cursor>::iterator it;
-
-  for (it = _cursor_filenames.begin(); it != _cursor_filenames.end(); it++) {
-    XFreeCursor(_display, it->second);
+  if (!_cursor_filenames.empty()) {
+    LightReMutexHolder holder(x11GraphicsPipe::_x_mutex);
+    for (auto item : _cursor_filenames) {
+      XFreeCursor(_display, item.second);
+    }
   }
 }
 
@@ -157,17 +158,21 @@ get_pointer(int device) const {
 
     result = _input_devices[device].get_pointer();
 
-    // We recheck this immediately to get the most up-to-date value.
-    if (device == 0 && !_dga_mouse_enabled && result._in_window) {
+    // We recheck this immediately to get the most up-to-date value, but we
+    // won't bother waiting for the lock if we can't.
+    if (device == 0 && !_dga_mouse_enabled && result._in_window &&
+        x11GraphicsPipe::_x_mutex.try_lock()) {
       XEvent event;
-      if (XQueryPointer(_display, _xwindow, &event.xbutton.root,
+      if (_xwindow != None &&
+          XQueryPointer(_display, _xwindow, &event.xbutton.root,
           &event.xbutton.window, &event.xbutton.x_root, &event.xbutton.y_root,
           &event.xbutton.x, &event.xbutton.y, &event.xbutton.state)) {
         double time = ClockObject::get_global_clock()->get_real_time();
         result._xpos = event.xbutton.x;
         result._ypos = event.xbutton.y;
-        ((GraphicsWindowInputDevice &)_input_devices[0]).set_pointer(result._in_window, result._xpos, result._ypos, time);
+        ((GraphicsWindowInputDevice &)_input_devices[0]).set_pointer_in_window(result._xpos, result._ypos, time);
       }
+      x11GraphicsPipe::_x_mutex.release();
     }
   }
   return result;
@@ -197,6 +202,7 @@ move_pointer(int device, int x, int y) {
     const MouseData &md = _input_devices[0].get_pointer();
     if (!md.get_in_window() || md.get_x() != x || md.get_y() != y) {
       if (!_dga_mouse_enabled) {
+        LightReMutexHolder holder(x11GraphicsPipe::_x_mutex);
         XWarpPointer(_display, None, _xwindow, 0, 0, 0, 0, x, y);
       }
       _input_devices[0].set_pointer_in_window(x, y);
@@ -532,6 +538,8 @@ set_properties_now(WindowProperties &properties) {
   x11GraphicsPipe *x11_pipe;
   DCAST_INTO_V(x11_pipe, _pipe);
 
+  LightReMutexHolder holder(x11GraphicsPipe::_x_mutex);
+
   // We're either going into or out of fullscreen, or are in fullscreen and
   // are changing the resolution.
   bool is_fullscreen = _properties.has_fullscreen() && _properties.get_fullscreen();
@@ -858,6 +866,7 @@ close_window() {
     _gsg.clear();
   }
 
+  LightReMutexHolder holder(x11GraphicsPipe::_x_mutex);
   if (_ic != (XIC)nullptr) {
     XDestroyIC(_ic);
     _ic = (XIC)nullptr;
@@ -916,6 +925,9 @@ open_window() {
     _properties.set_size(100, 100);
   }
 
+  // Make sure we are not making X11 calls from other threads.
+  LightReMutexHolder holder(x11GraphicsPipe::_x_mutex);
+
   if (_properties.get_fullscreen() && x11_pipe->_have_xrandr) {
     XRRScreenConfiguration* conf = _XRRGetScreenInfo(_display, x11_pipe->get_root());
     if (_orig_size_id == (SizeID) -1) {
@@ -1062,6 +1074,8 @@ open_window() {
  * If already_mapped is true, the window has already been mapped (manifested)
  * on the display.  This means we may need to use a different action in some
  * cases.
+ *
+ * Assumes the X11 lock is held.
  */
 void x11GraphicsWindow::
 set_wm_properties(const WindowProperties &properties, bool already_mapped) {

+ 4 - 0
pandatool/src/maxegg/maxEgg.h

@@ -19,6 +19,10 @@
 #include <fcntl.h>
 #include <crtdbg.h>
 #include "errno.h"
+
+using std::min;
+using std::max;
+
 #include "Max.h"
 #include "eggGroup.h"
 #include "eggTable.h"

+ 3 - 0
pandatool/src/maxegg/maxEggLoader.cxx

@@ -26,6 +26,9 @@
 #include "eggPolysetMaker.h"
 #include "eggBin.h"
 
+using std::min;
+using std::max;
+
 #include <stdio.h>
 #include "Max.h"
 #include "istdplug.h"

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