Browse Source

Merge branch 'master' into cmake

Sam Edwards 10 years ago
parent
commit
8b876843d4
100 changed files with 3421 additions and 2384 deletions
  1. 26 2
      README.md
  2. 6 1
      contrib/src/ai/Sources.pp
  3. 4 5
      direct/src/doc/dcPacker.txt
  4. 24 11
      direct/src/http/favicon.ico
  5. 1 1
      direct/src/p3d/panda3d.pdef
  6. 2 3
      direct/src/p3d/ppackage.py
  7. 8 0
      direct/src/plugin/fileSpec.I
  8. 25 1
      direct/src/plugin/p3dDownload.I
  9. 10 3
      direct/src/plugin/p3dPackage.I
  10. 1 1
      direct/src/plugin_npapi/startup.cxx
  11. 2 2
      direct/src/plugin_standalone/p3dEmbed.h
  12. 2 2
      direct/src/plugin_standalone/panda3d.h
  13. 4 3
      direct/src/plugin_standalone/panda3dBase.h
  14. 2 2
      direct/src/showutil/FreezeTool.py
  15. 111 0
      doc/ReleaseNotes
  16. 1 2
      dtool/Config.Cygwin64.pp
  17. 237 236
      dtool/metalibs/dtoolconfig/pydtool.cxx
  18. 13 5
      dtool/pptempl/PythonPackageInit.pp
  19. 1 1
      dtool/src/cppparser/cppInstance.cxx
  20. 13 0
      dtool/src/cppparser/cppTypedefType.cxx
  21. 1 1
      dtool/src/dtoolbase/addHash.I
  22. 1 1
      dtool/src/dtoolbase/atomicAdjustGccImpl.h
  23. 0 6
      dtool/src/dtoolbase/atomicAdjustI386Impl.cxx
  24. 1 1
      dtool/src/dtoolbase/atomicAdjustI386Impl.h
  25. 1 0
      dtool/src/dtoolbase/dtool_platform.h
  26. 2 2
      dtool/src/dtoolbase/pallocator.T
  27. 435 0
      dtool/src/dtoolbase/pdtoa.c
  28. 24 0
      dtool/src/dtoolbase/pdtoa.h
  29. 13 0
      dtool/src/dtoolbase/plist.h
  30. 2 2
      dtool/src/dtoolbase/pstrtod.cxx
  31. 2 2
      dtool/src/dtoolbase/typeHandle.cxx
  32. 4 4
      dtool/src/dtoolbase/typeHandle.h
  33. 78 0
      dtool/src/dtoolutil/preprocess_argv.cxx
  34. 9 1
      dtool/src/dtoolutil/string_utils.h
  35. 19 12
      dtool/src/dtoolutil/win32ArgParser.cxx
  36. 5 15
      dtool/src/interrogatedb/py_panda.h
  37. 2 4
      dtool/src/prc/configVariableDouble.cxx
  38. 2 4
      dtool/src/prc/configVariableInt.cxx
  39. 2 4
      dtool/src/prc/configVariableInt64.cxx
  40. 3 0
      makepanda/installpanda.py
  41. 140 112
      makepanda/makepanda.py
  42. 87 39
      makepanda/makepandacore.py
  43. 12 8
      panda/metalibs/pandadx9/Sources.pp
  44. 170 21
      panda/src/bullet/bulletBodyNode.cxx
  45. 13 3
      panda/src/bullet/bulletBodyNode.h
  46. 64 1
      panda/src/bullet/bulletBoxShape.cxx
  47. 11 1
      panda/src/bullet/bulletBoxShape.h
  48. 100 4
      panda/src/bullet/bulletConvexHullShape.cxx
  49. 8 2
      panda/src/bullet/bulletConvexHullShape.h
  50. 67 0
      panda/src/bullet/bulletDebugNode.cxx
  51. 8 1
      panda/src/bullet/bulletDebugNode.h
  52. 68 1
      panda/src/bullet/bulletPlaneShape.cxx
  53. 11 1
      panda/src/bullet/bulletPlaneShape.h
  54. 99 0
      panda/src/bullet/bulletRigidBodyNode.cxx
  55. 11 2
      panda/src/bullet/bulletRigidBodyNode.h
  56. 5 3
      panda/src/bullet/bulletShape.h
  57. 61 1
      panda/src/bullet/bulletSphereShape.cxx
  58. 11 1
      panda/src/bullet/bulletSphereShape.h
  59. 122 0
      panda/src/bullet/bulletTriangleMesh.cxx
  60. 12 5
      panda/src/bullet/bulletTriangleMesh.h
  61. 116 1
      panda/src/bullet/bulletTriangleMeshShape.cxx
  62. 16 1
      panda/src/bullet/bulletTriangleMeshShape.h
  63. 10 0
      panda/src/bullet/config_bullet.cxx
  64. 2 2
      panda/src/cocoadisplay/cocoaGraphicsWindow.mm
  65. 0 3
      panda/src/collide/collisionFloorMesh.I
  66. 1 1
      panda/src/display/config_display.cxx
  67. 17 9
      panda/src/display/get_x11.h
  68. 2 0
      panda/src/display/graphicsDevice.I
  69. 48 0
      panda/src/display/graphicsOutput.I
  70. 3 0
      panda/src/display/graphicsOutput.h
  71. 26 0
      panda/src/display/graphicsStateGuardian.I
  72. 2 0
      panda/src/display/graphicsStateGuardian.cxx
  73. 4 0
      panda/src/display/graphicsStateGuardian.h
  74. 4 18
      panda/src/display/graphicsWindow.cxx
  75. 0 1229
      panda/src/display/lru.cxx
  76. 0 269
      panda/src/display/lru.h
  77. 0 1
      panda/src/display/p3display_composite2.cxx
  78. 13 0
      panda/src/display/standardMunger.I
  79. 2 0
      panda/src/display/standardMunger.cxx
  80. 2 0
      panda/src/display/standardMunger.h
  81. 1 0
      panda/src/display/subprocessWindowBuffer.cxx
  82. 23 12
      panda/src/display/windowProperties.I
  83. 4 0
      panda/src/display/windowProperties.cxx
  84. 1 0
      panda/src/display/windowProperties.h
  85. 0 2
      panda/src/distort/oSphereLens.I
  86. 0 2
      panda/src/dxgsg9/dxIndexBufferContext9.I
  87. 11 5
      panda/src/dxgsg9/dxVertexBufferContext9.I
  88. 1 0
      panda/src/egg2pg/eggSaver.I
  89. 2 1
      panda/src/express/config_express.h
  90. 1 1
      panda/src/express/copy_stream.cxx
  91. 7 0
      panda/src/express/windowsRegistry.cxx
  92. 1 0
      panda/src/glesgsg/glesgsg.h
  93. 4 3
      panda/src/glesgsg/panda_esglext.h
  94. 121 13
      panda/src/glstuff/glCgShaderContext_src.I
  95. 6 0
      panda/src/glstuff/glGeomMunger_src.h
  96. 52 28
      panda/src/glstuff/glGraphicsStateGuardian_src.I
  97. 354 121
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  98. 60 12
      panda/src/glstuff/glGraphicsStateGuardian_src.h
  99. 319 102
      panda/src/glstuff/glShaderContext_src.I
  100. 6 2
      panda/src/glstuff/glShaderContext_src.h

+ 26 - 2
README.md

@@ -29,8 +29,10 @@ need Microsoft Visual Studio to build Panda3D, though - the relevant compilers
 are included as part of the Windows 7.1 SDK.
 
 You will also need to have the third-party dependency libraries available for
-the build scripts to use.  These are available from here:
-https://www.panda3d.org/forums/viewtopic.php?f=9&t=16346
+the build scripts to use.  These are available from one of these two URLs,
+depending on whether you are on a 32-bit or 64-bit system:
+https://www.panda3d.org/download/panda3d-1.9.0/panda3d-1.9.0-tools-win32.zip
+https://www.panda3d.org/download/panda3d-1.9.0/panda3d-1.9.0-tools-win64.zip
 
 After acquiring these dependencies, you may simply build Panda3D from the
 command prompt using the following command:
@@ -81,3 +83,25 @@ your system.  Careful: it is not easy to uninstall Panda3D in this way!
 ```bash
 python2.7 makepanda/installpanda.py --prefix=/usr/local
 ```
+
+Mac OS X
+--------
+
+On Mac OS X, all you need to compile Panda3D is a set of precompiled
+thirdparty packages, which can be acquired from here:
+https://www.panda3d.org/download/panda3d-1.9.0/panda3d-1.9.0-tools-mac.tar.gz
+
+After placing the thirdparty directory inside the panda3d source directory,
+you may build Panda3D using a command like the following:
+
+```bash
+python makepanda/makepanda.py --everything --installer
+```
+
+In order to make a universal build, pass the --universal flag.  You may also
+target a specific minimum Mac OS X version using the --osxtarget flag followed
+by the release number, eg. 10.6 or 10.7.
+
+If the build was successful, makepanda will have generated a .dmg file in
+the source directory containing the installer.  Simply open it and run the
+package file in order to install the SDK onto your system.

+ 6 - 1
contrib/src/ai/Sources.pp

@@ -203,6 +203,11 @@ def processType(handle, type):
             if docstring:
                 print >>handle, docstring
             print >>handle, interrogate_type_enum_value_name(type, i_value), "=", interrogate_type_enum_value(type, i_value), ","
+
+    elif interrogate_type_is_typedef(type):
+        wrapped_type = translated_type_name(interrogate_type_wrapped_type(type))
+        print >>handle, "typedef %s %s;" % (wrapped_type, typename)
+        return
     else:
         if interrogate_type_is_struct(type):
             classtype = "struct"
@@ -211,7 +216,7 @@ def processType(handle, type):
         elif interrogate_type_is_union(type):
             classtype = "union"
         else:
-            print "I don't know what type %s is" % typename
+            print "I don't know what type %s is" % interrogate_type_true_name(type)
             return
         
         if len(derivations) > 0:

+ 4 - 5
direct/src/doc/dcPacker.txt

@@ -107,14 +107,13 @@ def Dtool_PreloadDLL(module):
 # Dtool_FindModule to find our panda3d.core module.  However, we
 # should be able to import it.  To differentiate the old-style Panda
 # build (with .dll's) from the new-style Panda build (with .pyd's), we
-# first try to import libpandaexpress directly; if it succeeds we're
-# in an old-style build, and if it fails we must be in a new-style
-# build.
+# first try to import panda3d.core directly; if it succeeds we're in a
+# new-style build, and if it fails we must be in an old-style build.
 try:
+    from panda3d.core import *
+except ImportError:
     Dtool_PreloadDLL("libpandaexpress")
     from libpandaexpress import *
-except ImportError:
-    from panda3d.core import *
 
 def Dtool_ObjectToDict(cls, name, obj):
     cls.DtoolClassDict[name] = obj;

+ 24 - 11
direct/src/http/favicon.ico


+ 1 - 1
direct/src/p3d/panda3d.pdef

@@ -319,7 +319,7 @@ elif deploy_mode == 'installer':
     del i
 
 elif deploy_mode == 'html':
-    w, h = tokens.get("width", 640), tokens.get("height", 480)
+    w, h = tokens.get("width", 800), tokens.get("height", 600)
     if "data" not in tokens:
         tokens["data"] = appFilename.getBasename()
 

+ 2 - 3
direct/src/p3d/ppackage.py

@@ -90,7 +90,7 @@ Options:
      each supported architecture).  On other platforms, this option
      does nothing.  This is therefore safe to apply in all cases, if
      you wish to take advantage of universal binaries.  This is
-     equivalent to "-P osx_ppc -P osx_i386" on Mac platforms.
+     equivalent to "-P osx_i386 -P osx_amd64" on Mac platforms.
 
   -P platform
      Specify the platform to masquerade as.  The default is whatever
@@ -215,8 +215,7 @@ if universalBinaries:
         print '\nYou may not specify both -u and -P.\n'
         sys.exit(1)
     if PandaSystem.getPlatform().startswith('osx_'):
-        # Maybe soon we'll add osx_x86_64 to this default list.
-        platforms = ['osx_i386', 'osx_ppc']
+        platforms = ['osx_i386', 'osx_amd64']
 
 if not platforms:
     platforms = [PandaSystem.getPlatform()]

+ 8 - 0
direct/src/plugin/fileSpec.I

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

+ 25 - 1
direct/src/plugin/p3dDownload.I

@@ -45,6 +45,10 @@
 #include <dirent.h>
 #endif
 
+#ifdef __APPLE__
+#include <sys/sysctl.h>
+#endif
+
 #include <stdio.h>
 
 static ofstream logfile;
@@ -230,9 +234,29 @@ initialize(int api_version, const string &contents_filename,
       _supported_platforms.push_back("win_i386");
       _supported_platforms.push_back("win32");
     }
+#elif defined(__APPLE__)
+    if (_platform == "osx_amd64") {
+      _supported_platforms.push_back("osx_amd64");
+      _supported_platforms.push_back("osx_i386");
+
+    } else if (_platform == "osx_i386") {
+      // This is a 32-bit process, but determine if the underlying OS
+      // supports 64-bit.
+
+      int mib[2] = { CTL_HW, HW_MACHINE };
+      char machine[512];
+      size_t len = 511;
+      if (sysctl(mib, 2, (void *)machine, &len, NULL, 0) == 0) {
+        if (strcmp(machine, "x86_64") == 0) {
+          _supported_platforms.push_back("osx_amd64");
+        }
+      }
+
+      _supported_platforms.push_back("osx_i386");
+    }
 #endif  // _WIN32
 
-    // TODO: OSX, Linux multiplatform support.  Just add the
+    // TODO: Linux multiplatform support.  Just add the
     // appropriate platform strings to _supported_platforms.
   }
 

+ 10 - 3
direct/src/plugin/p3dPackage.I

@@ -461,7 +461,10 @@ def makeInstaller():
 
         infoFilename = None
         descriptionFilename = None
-        packagemaker = "/Developer/usr/bin/packagemaker"
+        packagemaker = "/Applications/Xcode.app/Contents/Applications/PackageMaker.app/Contents/MacOS/PackageMaker"
+        if not os.path.exists(packagemaker):
+            packagemaker = "/Developer/usr/bin/packagemaker"
+
         if os.path.exists(packagemaker):
             # PackageMaker 3.0 or better, e.g. OSX 10.5.
             CMD = packagemaker
@@ -469,7 +472,7 @@ def makeInstaller():
             CMD += ' --version "%s"' % options.version
             CMD += ' --title "%s"' % options.long_name
             CMD += ' --out "%s"' % (pkgname)
-            CMD += ' --target 10.4' # The earliest version of OSX supported by Panda
+            CMD += ' --target 10.5' # The earliest version of OSX supported by Panda
             CMD += ' --domain system'
             CMD += ' --root "%s"' % tmproot
             CMD += ' --resources "%s"' % tmpresdir
@@ -520,7 +523,11 @@ def makeInstaller():
         
         # Pack the .pkg into a .dmg
         if not os.path.exists(tmproot): os.makedirs(tmproot)
-        shutil.copytree(pkgname, os.path.join(tmproot, pkgname))
+        if os.path.isdir(pkgname):
+            shutil.copytree(pkgname, os.path.join(tmproot, pkgname))
+        else:
+            shutil.copyfile(pkgname, os.path.join(tmproot, pkgname))
+
         tmpdmg = tempfile.mktemp('', 'p3d-setup') + ".dmg"
         CMD = 'hdiutil create "%s" -srcfolder "%s"' % (tmpdmg, tmproot)
         print ""

+ 1 - 1
direct/src/plugin_npapi/startup.cxx

@@ -233,7 +233,7 @@ NP_GetEntryPoints(NPPluginFuncs *pluginFuncs) {
   if (pluginFuncs->size == 0) {
     pluginFuncs->size = sizeof(*pluginFuncs);
   }
-  if (pluginFuncs->size < sizeof(*pluginFuncs)) {
+  if (pluginFuncs->size < offsetof(NPPluginFuncs, gotfocus)) {
     nout << "Invalid NPPPluginFuncs size\n";
     return NPERR_INVALID_FUNCTABLE_ERROR;
   }

+ 2 - 2
direct/src/plugin_standalone/p3dEmbed.h

@@ -226,8 +226,8 @@ run_command_line(int argc, char *argv[]) {
       // The user asked for an embedded window.  Create a toplevel
       // window to be its parent, of the requested size.
       if (_win_width == 0 && _win_height == 0) {
-        _win_width = 640;
-        _win_height = 480;
+        _win_width = 800;
+        _win_height = 600;
       }
       
       make_parent_window();

+ 2 - 2
direct/src/plugin_standalone/panda3d.h

@@ -62,8 +62,8 @@ Panda3DBase(bool console_environment) {
 
   _win_x = -1;
   _win_y = -1;
-  _win_width = 640;
-  _win_height = 480;
+  _win_width = 800;
+  _win_height = 600;
   _got_win_size = false;
 
   _exit_with_last_instance = true;

+ 4 - 3
direct/src/plugin_standalone/panda3dBase.h

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

+ 2 - 2
direct/src/showutil/FreezeTool.py

@@ -143,8 +143,8 @@ class CompilationEnvironment:
                 self.arch = '-arch i386'
             elif proc == 'ppc':
                 self.arch = '-arch ppc'
-            elif proc == 'x86_64':
-                self.arch = '-arch x86_x64'
+            elif proc == 'amd64':
+                self.arch = '-arch x86_64'
             self.compileObj = "gcc -fPIC -c %(arch)s -o %(basename)s.o -O2 -I%(pythonIPath)s %(filename)s"
             self.linkExe = "gcc %(arch)s -o %(basename)s %(basename)s.o -framework Python"
             self.linkDll = "gcc %(arch)s -undefined dynamic_lookup -bundle -o %(basename)s.so %(basename)s.o"

+ 111 - 0
doc/ReleaseNotes

@@ -1,3 +1,114 @@
+------------------------  RELEASE 1.9.0  ------------------------
+
+This is a major release with many exciting new features!
+Beware of bugs.
+
+The list below contains a subset of the changes introduced:
+
+* We now offer 64-bit Windows and Mac OS X builds.
+* Switch to MSVC 2010; no more assembly manifests.
+* Cocoa port for better Mac OS X support, esp. newer versions.
+* We now compile the Python modules into panda3d/*.pyd modules;
+  no more imp.load_dynamic hackery needed.
+* Support for GPU profiling in OpenGL, see pstats-gpu-timing
+* sRGB framebuffers, see framebuffer-srgb
+* sRGB texture support, see Texture::F_srgb et al.
+* Integer vector support, including passing to shaders
+* Native .ogg vorbis and .wav loader (does not require ffmpeg)
+* FFmpeg support is a separate plug-in module now, libp3ffmpeg.
+* Sample programs are now part of the source code repository
+* Can be built with Python 3 (highly experimental)
+* Improvements to Windows installer
+* M_filled_wireframe rendering mode
+* Support specifying sampler state separate from textures
+* Support for bindless texture clearing
+* Texture LOD bias and min/max LOD settings
+* Framebuffer properties allows separate red/green/blue bits
+* Explicit float color and float depth specification in fbprops
+* Coverage samples settable via FrameBufferProperties
+* Stereo buffer implementation in OpenGL via FBOs
+* Support enumeration of pixel formats in WebcamVideo
+* Frame rate meter can be configured to show milliseconds
+* Changes to improve font crispness with default settings
+* Fix assertion error when using more than one GraphicsEngine
+* raw-w, raw-a, etc. keyboard events for layout-independent input
+* Allow querying active keyboard layout via win.get_keyboard_map()
+* Distinguish between lmeta and rmeta keys on Mac OS X
+* Floating-point image manipulation API, support float tiffs
+* Various new 16-bit and 32-bit and int texture formats
+* Man pages are now available for the majority of utilities
+
+Pipeline:
+* Fix bugs with <Collide> group transformations in .egg
+* Don't create unnecessary intermediate node when loading .egg
+* bam2egg supports materials, and correctly converts animations
+* dae2egg has some skeletal animation support
+* Support Maya versions up to 2015
+
+OpenGL renderer changes:
+* Error checking is now OFF by default for performance reasons,
+    set gl-check-errors or gl-debug to true to enable.
+* GL 4.2 shader_image_load_store support (incl. multi-bind)
+* Layered render-to-texture (using geometry shaders)
+* Seamless cube maps (on by default), see gl-cube-map-seamless
+* Added gl-debug for improved debug output support
+* Added GL object labels when gl-debug is enabled
+* gl-dump-compiled-shaders can be used to dump program binaries
+* Direct3D-style NT_packed_dabc vertex arrays now directly supported
+* Native rendering of line strips, using primitive restart
+* Immutable texture storage support (disabled by default)
+* Bindless texture support (disabled by default)
+* Specular component is now computed separately in FFP
+
+Shader system:
+* Support for tessellation shaders
+* Support for compute shaders via ComputeNode
+* GLSL preprocessor with "#pragma include" support
+* Much better coverage of shader inputs in GLSL
+* GLSL error messages now show source filename
+* Fixes apiclip_of_x shader inputs
+* Matrices can be passed directly to setShaderInput
+* Support binding images to shaders
+* Viewport array support
+
+Optimizations and performance improvements:
+* Use of C++11 move semantics to reduce refcounting overhead
+* Build with Eigen by default for faster linear math
+* Dramatic overhead reduction of generated bindings
+* Streamline culling process
+* Tighter bounding volume generation
+* Take advantage of CPU features for bit operations
+* Circumvent bounding volume generation when not required
+* Optimizations for interned strings
+* Use of GCC atomics should improve 64-bit Linux performance
+
+API features:
+* Buffer protocol support for textures and arrays
+* Interrogate supports various C++11 features
+* Expose TextGlyph interfaces for making custom text renderers
+* Better handling of default arguments for many functions
+* Cyclic references can sometimes be tracked through tasks
+* ShowBase clean teardown possible
+* API documentation is more accurate
+* Improve interfaces for interop with other applications
+
+Deprecated features:
+* Use of pandac.PandaModules is discouraged; use panda3d.core
+* Deprecate DirectStart and global run() function; use ShowBase
+* Remove old decal system
+* Remove Direct3D 8 renderer
+* Remove M_light_vector tex gen mode and FFP-based bump mapping
+
+Bug fixes:
+* Various point rendering issues are fixed now
+* Fix pview issue with 1-frame and/or multiple animations
+* Fixes for multisampling in FBOs
+* Fix aspect ratio of frame rate meter
+* Support NaN and infinity values in Config.prc variables
+* Fixes for webcams on Linux that do not output Huffman tables
+* Better support for non-basic Cg shaders on non-NVIDIA cards
+* Many others
+
 ------------------------  RELEASE 1.8.1  ------------------------
 
 This is a bugfix release, fixing many issues in 1.8.0.

+ 1 - 2
dtool/Config.Cygwin64.pp

@@ -44,5 +44,4 @@
 // integers, but by convention it will consist of four integers, with
 // the first three matching the plugin version, and the fourth integer
 // being incremented with each new Core API revision.
-#define P3D_COREAPI_VERSION $[P3D_PLUGIN_VERSION] 1
-
+#define P3D_COREAPI_VERSION $[P3D_PLUGIN_VERSION] 2

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


+ 13 - 5
dtool/pptempl/PythonPackageInit.pp

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

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

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

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

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

+ 1 - 1
dtool/src/dtoolbase/addHash.I

@@ -31,7 +31,7 @@ struct AtomicAdjust {
 #include "atomicAdjustDummyImpl.h"
 typedef AtomicAdjustDummyImpl AtomicAdjust;
 
-#elif defined(__i386__) || defined(_M_IX86)
+#elif (defined(__i386__) || defined(_M_IX86)) && !defined(__APPLE__)
 // For an i386 architecture, we'll always use the i386 implementation.
 // It should be safe for any OS, and it might be a bit faster than
 // any OS-provided calls.

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

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

+ 0 - 6
dtool/src/dtoolbase/atomicAdjustI386Impl.cxx

@@ -12,10 +12,4 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-#include "selectThreadImpl.h"
-
-#ifdef __i386__
-
 #include "atomicAdjustI386Impl.h"
-
-#endif  // __i386__

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

@@ -18,7 +18,7 @@
 #include "dtoolbase.h"
 #include "selectThreadImpl.h"
 
-#if defined(__i386__) || defined(_M_IX86)
+#if (defined(__i386__) || defined(_M_IX86)) && !defined(__APPLE__)
 
 #include "numeric_types.h"
 

+ 1 - 0
dtool/src/dtoolbase/dtool_platform.h

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

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

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

+ 435 - 0
dtool/src/dtoolbase/pdtoa.c

@@ -0,0 +1,435 @@
+/*
+See pdtoa.h for explanation.
+
+Copyright (C) 2014 Milo Yip
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "pdtoa.h"
+#include "cmath.h"
+
+#include <assert.h>
+#include <math.h>
+#include <stdint.h>
+
+#if defined(_MSC_VER)
+#include <intrin.h>
+#endif
+
+#define UINT64_C2(h, l) ((static_cast<uint64_t>(h) << 32) | static_cast<uint64_t>(l))
+
+struct DiyFp {
+  DiyFp() {}
+
+  DiyFp(uint64_t f, int e) : f(f), e(e) {}
+
+  DiyFp(double d) {
+    union {
+      double d;
+      uint64_t u64;
+    } u = { d };
+
+    int biased_e = (u.u64 & kDpExponentMask) >> kDpSignificandSize;
+    uint64_t significand = (u.u64 & kDpSignificandMask);
+    if (biased_e != 0) {
+      f = significand + kDpHiddenBit;
+      e = biased_e - kDpExponentBias;
+    }
+    else {
+      f = significand;
+      e = kDpMinExponent + 1;
+    }
+  }
+
+  DiyFp operator-(const DiyFp& rhs) const {
+    assert(e == rhs.e);
+    assert(f >= rhs.f);
+    return DiyFp(f - rhs.f, e);
+  }
+
+  DiyFp operator*(const DiyFp& rhs) const {
+#if defined(_MSC_VER) && defined(_M_AMD64)
+    uint64_t h;
+    uint64_t l = _umul128(f, rhs.f, &h);
+    if (l & (uint64_t(1) << 63)) // rounding
+      h++;
+    return DiyFp(h, e + rhs.e + 64);
+#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
+    unsigned __int128 p = static_cast<unsigned __int128>(f) * static_cast<unsigned __int128>(rhs.f);
+    uint64_t h = p >> 64;
+    uint64_t l = static_cast<uint64_t>(p);
+    if (l & (uint64_t(1) << 63)) // rounding
+      h++;
+    return DiyFp(h, e + rhs.e + 64);
+#else
+    const uint64_t M32 = 0xFFFFFFFF;
+    const uint64_t a = f >> 32;
+    const uint64_t b = f & M32;
+    const uint64_t c = rhs.f >> 32;
+    const uint64_t d = rhs.f & M32;
+    const uint64_t ac = a * c;
+    const uint64_t bc = b * c;
+    const uint64_t ad = a * d;
+    const uint64_t bd = b * d;
+    uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
+    tmp += 1U << 31;  /// mult_round
+    return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);
+#endif
+  }
+
+  DiyFp Normalize() const {
+#if defined(_MSC_VER) && defined(_M_AMD64)
+    unsigned long index;
+    _BitScanReverse64(&index, f);
+    return DiyFp(f << (63 - index), e - (63 - index));
+#elif defined(__GNUC__)
+    int s = __builtin_clzll(f);
+    return DiyFp(f << s, e - s);
+#else
+    DiyFp res = *this;
+    while (!(res.f & kDpHiddenBit)) {
+      res.f <<= 1;
+      res.e--;
+    }
+    res.f <<= (kDiySignificandSize - kDpSignificandSize - 1);
+    res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 1);
+    return res;
+#endif
+  }
+
+  DiyFp NormalizeBoundary() const {
+#if defined(_MSC_VER) && defined(_M_AMD64)
+    unsigned long index;
+    _BitScanReverse64(&index, f);
+    return DiyFp (f << (63 - index), e - (63 - index));
+#else
+    DiyFp res = *this;
+    while (!(res.f & (kDpHiddenBit << 1))) {
+      res.f <<= 1;
+      res.e--;
+    }
+    res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
+    res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
+    return res;
+#endif
+  }
+
+  void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const {
+    DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
+    DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
+    mi.f <<= mi.e - pl.e;
+    mi.e = pl.e;
+    *plus = pl;
+    *minus = mi;
+  }
+
+  static const int kDiySignificandSize = 64;
+  static const int kDpSignificandSize = 52;
+  static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
+  static const int kDpMinExponent = -kDpExponentBias;
+  static const uint64_t kDpExponentMask = UINT64_C2(0x7FF00000, 0x00000000);
+  static const uint64_t kDpSignificandMask = UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
+  static const uint64_t kDpHiddenBit = UINT64_C2(0x00100000, 0x00000000);
+
+  uint64_t f;
+  int e;
+};
+
+inline static DiyFp GetCachedPower(int e, int* K) {
+  // 10^-348, 10^-340, ..., 10^340
+  static const uint64_t kCachedPowers_F[] = {
+    UINT64_C2(0xfa8fd5a0, 0x081c0288), UINT64_C2(0xbaaee17f, 0xa23ebf76),
+    UINT64_C2(0x8b16fb20, 0x3055ac76), UINT64_C2(0xcf42894a, 0x5dce35ea),
+    UINT64_C2(0x9a6bb0aa, 0x55653b2d), UINT64_C2(0xe61acf03, 0x3d1a45df),
+    UINT64_C2(0xab70fe17, 0xc79ac6ca), UINT64_C2(0xff77b1fc, 0xbebcdc4f),
+    UINT64_C2(0xbe5691ef, 0x416bd60c), UINT64_C2(0x8dd01fad, 0x907ffc3c),
+    UINT64_C2(0xd3515c28, 0x31559a83), UINT64_C2(0x9d71ac8f, 0xada6c9b5),
+    UINT64_C2(0xea9c2277, 0x23ee8bcb), UINT64_C2(0xaecc4991, 0x4078536d),
+    UINT64_C2(0x823c1279, 0x5db6ce57), UINT64_C2(0xc2109436, 0x4dfb5637),
+    UINT64_C2(0x9096ea6f, 0x3848984f), UINT64_C2(0xd77485cb, 0x25823ac7),
+    UINT64_C2(0xa086cfcd, 0x97bf97f4), UINT64_C2(0xef340a98, 0x172aace5),
+    UINT64_C2(0xb23867fb, 0x2a35b28e), UINT64_C2(0x84c8d4df, 0xd2c63f3b),
+    UINT64_C2(0xc5dd4427, 0x1ad3cdba), UINT64_C2(0x936b9fce, 0xbb25c996),
+    UINT64_C2(0xdbac6c24, 0x7d62a584), UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
+    UINT64_C2(0xf3e2f893, 0xdec3f126), UINT64_C2(0xb5b5ada8, 0xaaff80b8),
+    UINT64_C2(0x87625f05, 0x6c7c4a8b), UINT64_C2(0xc9bcff60, 0x34c13053),
+    UINT64_C2(0x964e858c, 0x91ba2655), UINT64_C2(0xdff97724, 0x70297ebd),
+    UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), UINT64_C2(0xf8a95fcf, 0x88747d94),
+    UINT64_C2(0xb9447093, 0x8fa89bcf), UINT64_C2(0x8a08f0f8, 0xbf0f156b),
+    UINT64_C2(0xcdb02555, 0x653131b6), UINT64_C2(0x993fe2c6, 0xd07b7fac),
+    UINT64_C2(0xe45c10c4, 0x2a2b3b06), UINT64_C2(0xaa242499, 0x697392d3),
+    UINT64_C2(0xfd87b5f2, 0x8300ca0e), UINT64_C2(0xbce50864, 0x92111aeb),
+    UINT64_C2(0x8cbccc09, 0x6f5088cc), UINT64_C2(0xd1b71758, 0xe219652c),
+    UINT64_C2(0x9c400000, 0x00000000), UINT64_C2(0xe8d4a510, 0x00000000),
+    UINT64_C2(0xad78ebc5, 0xac620000), UINT64_C2(0x813f3978, 0xf8940984),
+    UINT64_C2(0xc097ce7b, 0xc90715b3), UINT64_C2(0x8f7e32ce, 0x7bea5c70),
+    UINT64_C2(0xd5d238a4, 0xabe98068), UINT64_C2(0x9f4f2726, 0x179a2245),
+    UINT64_C2(0xed63a231, 0xd4c4fb27), UINT64_C2(0xb0de6538, 0x8cc8ada8),
+    UINT64_C2(0x83c7088e, 0x1aab65db), UINT64_C2(0xc45d1df9, 0x42711d9a),
+    UINT64_C2(0x924d692c, 0xa61be758), UINT64_C2(0xda01ee64, 0x1a708dea),
+    UINT64_C2(0xa26da399, 0x9aef774a), UINT64_C2(0xf209787b, 0xb47d6b85),
+    UINT64_C2(0xb454e4a1, 0x79dd1877), UINT64_C2(0x865b8692, 0x5b9bc5c2),
+    UINT64_C2(0xc83553c5, 0xc8965d3d), UINT64_C2(0x952ab45c, 0xfa97a0b3),
+    UINT64_C2(0xde469fbd, 0x99a05fe3), UINT64_C2(0xa59bc234, 0xdb398c25),
+    UINT64_C2(0xf6c69a72, 0xa3989f5c), UINT64_C2(0xb7dcbf53, 0x54e9bece),
+    UINT64_C2(0x88fcf317, 0xf22241e2), UINT64_C2(0xcc20ce9b, 0xd35c78a5),
+    UINT64_C2(0x98165af3, 0x7b2153df), UINT64_C2(0xe2a0b5dc, 0x971f303a),
+    UINT64_C2(0xa8d9d153, 0x5ce3b396), UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
+    UINT64_C2(0xbb764c4c, 0xa7a44410), UINT64_C2(0x8bab8eef, 0xb6409c1a),
+    UINT64_C2(0xd01fef10, 0xa657842c), UINT64_C2(0x9b10a4e5, 0xe9913129),
+    UINT64_C2(0xe7109bfb, 0xa19c0c9d), UINT64_C2(0xac2820d9, 0x623bf429),
+    UINT64_C2(0x80444b5e, 0x7aa7cf85), UINT64_C2(0xbf21e440, 0x03acdd2d),
+    UINT64_C2(0x8e679c2f, 0x5e44ff8f), UINT64_C2(0xd433179d, 0x9c8cb841),
+    UINT64_C2(0x9e19db92, 0xb4e31ba9), UINT64_C2(0xeb96bf6e, 0xbadf77d9),
+    UINT64_C2(0xaf87023b, 0x9bf0ee6b)
+  };
+  static const int16_t kCachedPowers_E[] = {
+    -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007,  -980,
+     -954,  -927,  -901,  -874,  -847,  -821,  -794,  -768,  -741,  -715,
+     -688,  -661,  -635,  -608,  -582,  -555,  -529,  -502,  -475,  -449,
+     -422,  -396,  -369,  -343,  -316,  -289,  -263,  -236,  -210,  -183,
+     -157,  -130,  -103,   -77,   -50,   -24,     3,    30,    56,    83,
+      109,   136,   162,   189,   216,   242,   269,   295,   322,   348,
+      375,   402,   428,   455,   481,   508,   534,   561,   588,   614,
+      641,   667,   694,   720,   747,   774,   800,   827,   853,   880,
+      907,   933,   960,   986,  1013,  1039,  1066
+  };
+
+  //int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
+  double dk = (-61 - e) * 0.30102999566398114 + 347;  // dk must be positive, so can do ceiling in positive
+  int k = static_cast<int>(dk);
+  if (k != dk)
+    k++;
+
+  unsigned index = static_cast<unsigned>((k >> 3) + 1);
+  *K = -(-348 + static_cast<int>(index << 3));  // decimal exponent no need lookup table
+
+  assert(index < sizeof(kCachedPowers_F) / sizeof(kCachedPowers_F[0]));
+  return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
+}
+
+inline static void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
+  while (rest < wp_w && delta - rest >= ten_kappa &&
+       (rest + ten_kappa < wp_w ||  /// closer
+      wp_w - rest > rest + ten_kappa - wp_w)) {
+    buffer[len - 1]--;
+    rest += ten_kappa;
+  }
+}
+
+inline static unsigned CountDecimalDigit32(uint32_t n) {
+  // Simple pure C++ implementation was faster than __builtin_clz version in this situation.
+  if (n < 10) return 1;
+  if (n < 100) return 2;
+  if (n < 1000) return 3;
+  if (n < 10000) return 4;
+  if (n < 100000) return 5;
+  if (n < 1000000) return 6;
+  if (n < 10000000) return 7;
+  if (n < 100000000) return 8;
+  if (n < 1000000000) return 9;
+  return 10;
+}
+
+inline static void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
+  static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
+  const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
+  const DiyFp wp_w = Mp - W;
+  uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
+  uint64_t p2 = Mp.f & (one.f - 1);
+  int kappa = static_cast<int>(CountDecimalDigit32(p1));
+  *len = 0;
+
+  while (kappa > 0) {
+    uint32_t d;
+    switch (kappa) {
+      case 10: d = p1 / 1000000000; p1 %= 1000000000; break;
+      case  9: d = p1 /  100000000; p1 %=  100000000; break;
+      case  8: d = p1 /   10000000; p1 %=   10000000; break;
+      case  7: d = p1 /    1000000; p1 %=    1000000; break;
+      case  6: d = p1 /     100000; p1 %=     100000; break;
+      case  5: d = p1 /      10000; p1 %=      10000; break;
+      case  4: d = p1 /       1000; p1 %=       1000; break;
+      case  3: d = p1 /        100; p1 %=        100; break;
+      case  2: d = p1 /         10; p1 %=         10; break;
+      case  1: d = p1;              p1 =           0; break;
+      default:
+#if defined(_MSC_VER)
+        __assume(0);
+#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
+        __builtin_unreachable();
+#else
+        d = 0;
+#endif
+    }
+    if (d || *len)
+      buffer[(*len)++] = '0' + static_cast<char>(d);
+    kappa--;
+    uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
+    if (tmp <= delta) {
+      *K += kappa;
+      GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
+      return;
+    }
+  }
+
+  // kappa = 0
+  for (;;) {
+    p2 *= 10;
+    delta *= 10;
+    char d = static_cast<char>(p2 >> -one.e);
+    if (d || *len)
+      buffer[(*len)++] = '0' + d;
+    p2 &= one.f - 1;
+    kappa--;
+    if (p2 < delta) {
+      *K += kappa;
+      GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-kappa]);
+      return;
+    }
+  }
+}
+
+inline static void Grisu2(double value, char* buffer, int* length, int* K) {
+  const DiyFp v(value);
+  DiyFp w_m, w_p;
+  v.NormalizedBoundaries(&w_m, &w_p);
+
+  const DiyFp c_mk = GetCachedPower(w_p.e, K);
+  const DiyFp W = v.Normalize() * c_mk;
+  DiyFp Wp = w_p * c_mk;
+  DiyFp Wm = w_m * c_mk;
+  Wm.f++;
+  Wp.f--;
+  DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
+}
+
+static const char cDigitsLut[200] = {
+  '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0', '8', '0', '9',
+  '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9',
+  '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
+  '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9',
+  '4', '0', '4', '1', '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9',
+  '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
+  '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
+  '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7', '7', '8', '7', '9',
+  '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
+  '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'
+};
+
+inline void WriteExponent(int K, char* buffer) {
+  if (K < 0) {
+    *buffer++ = '-';
+    K = -K;
+  }
+
+  if (K >= 100) {
+    *buffer++ = '0' + static_cast<char>(K / 100);
+    K %= 100;
+    const char* d = cDigitsLut + K * 2;
+    *buffer++ = d[0];
+    *buffer++ = d[1];
+  }
+  else if (K >= 10) {
+    const char* d = cDigitsLut + K * 2;
+    *buffer++ = d[0];
+    *buffer++ = d[1];
+  }
+  else
+    *buffer++ = '0' + static_cast<char>(K);
+
+  *buffer = '\0';
+}
+
+inline static void Prettify(char* buffer, int length, int k) {
+  const int kk = length + k;  // 10^(kk-1) <= v < 10^kk
+
+  if (length <= kk && kk <= 21) {
+    // 1234e7 -> 12340000000
+    for (int i = length; i < kk; i++)
+      buffer[i] = '0';
+    buffer[kk] = '.';
+    buffer[kk + 1] = '0';
+    buffer[kk + 2] = '\0';
+  }
+  else if (0 < kk && kk <= 21) {
+    // 1234e-2 -> 12.34
+    memmove(&buffer[kk + 1], &buffer[kk], length - kk);
+    buffer[kk] = '.';
+    buffer[length + 1] = '\0';
+  }
+  else if (-6 < kk && kk <= 0) {
+    // 1234e-6 -> 0.001234
+    const int offset = 2 - kk;
+    memmove(&buffer[offset], &buffer[0], length);
+    buffer[0] = '0';
+    buffer[1] = '.';
+    for (int i = 2; i < offset; i++)
+      buffer[i] = '0';
+    buffer[length + offset] = '\0';
+  }
+  else if (length == 1) {
+    // 1e30
+    buffer[1] = 'e';
+    WriteExponent(kk - 1, &buffer[2]);
+  }
+  else {
+    // 1234e30 -> 1.234e33
+    memmove(&buffer[2], &buffer[1], length - 1);
+    buffer[1] = '.';
+    buffer[length + 1] = 'e';
+    WriteExponent(kk - 1, &buffer[0 + length + 2]);
+  }
+}
+
+void pdtoa(double value, char *buffer) {
+#ifdef _MSC_VER
+  if (copysign(1.0, value) < 0) {
+#else
+  if (signbit(value)) {
+#endif
+    *buffer++ = '-';
+    value = -value;
+  }
+  if (cinf(value)) {
+    buffer[0] = 'i';
+    buffer[1] = 'n';
+    buffer[2] = 'f';
+    buffer[3] = '\0';
+  } else if (cnan(value)) {
+    buffer[0] = 'n';
+    buffer[1] = 'a';
+    buffer[2] = 'n';
+    buffer[3] = '\0';
+  } else if (value == 0.0) {
+    buffer[0] = '0';
+    buffer[1] = '.';
+    buffer[2] = '0';
+    buffer[3] = '\0';
+  } else if (value == 1.0) {
+    buffer[0] = '1';
+    buffer[1] = '.';
+    buffer[2] = '0';
+    buffer[3] = '\0';
+  } else {
+    int length, K;
+    Grisu2(value, buffer, &length, &K);
+    Prettify(buffer, length, K);
+  }
+}

+ 24 - 0
dtool/src/dtoolbase/pdtoa.h

@@ -0,0 +1,24 @@
+/*
+  This is a double-to-string conversion implementation by Milo Yip from:
+    https://github.com/miloyip/dtoa-benchmark
+
+  I introduced it because the ostringstream implementation is just too
+  darned slow, especially when compiled to JavaScript.
+*/
+
+#ifndef PDTOA_H
+#define PDTOA_H
+
+#include "dtoolsymbols.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+EXPCL_DTOOL void pdtoa(double value, char *buffer);
+
+#ifdef __cplusplus
+};  /* end of extern "C" */
+#endif
+
+#endif  // PDTOA_H

+ 13 - 0
dtool/src/dtoolbase/plist.h

@@ -49,6 +49,19 @@ public:
   typedef TYPENAME base_class::const_iterator const_iterator;
   typedef TYPENAME base_class::reverse_iterator reverse_iterator;
   typedef TYPENAME base_class::const_reverse_iterator const_reverse_iterator;
+
+  // This exists because libc++'s remove implementation has a bug with
+  // Panda's allocator class.
+  INLINE void remove(const Type &val) {
+    iterator it = this->begin();
+    while (it != this->end()) {
+      if (*it == val) {
+        it = this->erase(it);
+      } else {
+        ++it;
+      }
+    }
+  };
 };
 
 #endif  // USE_STL_ALLOCATOR

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

@@ -132,9 +132,9 @@ pstrtod(const char *nptr, char **endptr) {
       }
 
       if (esign == '-') {
-        value /= pow(evalue, 10.0);
+        value /= pow(10.0, evalue);
       } else {
-        value *= pow(evalue, 10.0);
+        value *= pow(10.0, evalue);
       }
     }
   }

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

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

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

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

+ 78 - 0
dtool/src/dtoolutil/preprocess_argv.cxx

@@ -20,3 +20,81 @@ format_string(const Thing &thing) {
   str << thing;
   return str.str();
 }
+
+INLINE string
+format_string(const string &value) {
+  return value;
+}
+
+INLINE string
+format_string(float value) {
+  char buffer[32];
+  pdtoa(value, buffer);
+  return string(buffer);
+}
+
+INLINE string
+format_string(double value) {
+  char buffer[32];
+  pdtoa(value, buffer);
+  return string(buffer);
+}
+
+INLINE string
+format_string(unsigned int value) {
+  char buffer[11];
+  char *p = buffer + 10;
+  *p = 0;
+  do {
+    *--p = '0' + (value % 10);
+    value /= 10;
+  } while (value > 0);
+
+  return string(p);
+}
+
+INLINE string
+format_string(int value) {
+  char buffer[12];
+  char *p = buffer + 11;
+  *p = 0;
+
+  if (value < 0) {
+    unsigned int posv = (unsigned int)-value;
+    do {
+      *--p = '0' + (posv % 10);
+      posv /= 10;
+    } while (posv > 0);
+    *--p = '-';
+  } else {
+    do {
+      *--p = '0' + (value % 10);
+      value /= 10;
+    } while (value > 0);
+  }
+
+  return string(p);
+}
+
+INLINE string
+format_string(PN_int64 value) {
+  char buffer[21];
+  char *p = buffer + 20;
+  *p = 0;
+
+  if (value < 0) {
+    PN_uint64 posv = (PN_uint64)-value;
+    do {
+      *--p = '0' + (posv % 10);
+      posv /= 10;
+    } while (posv > 0);
+    *--p = '-';
+  } else {
+    do {
+      *--p = '0' + (value % 10);
+      value /= 10;
+    } while (value > 0);
+  }
+
+  return string(p);
+}

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

@@ -19,6 +19,7 @@
 
 #include <string>
 #include "vector_string.h"
+#include "pdtoa.h"
 
 // Case-insensitive string comparison, from Stroustrup's C++ third edition.
 // Works like strcmp().
@@ -66,7 +67,14 @@ EXPCL_DTOOL bool string_to_stdfloat(const string &str, PN_stdfloat &result);
 template<class Thing>
 INLINE string format_string(const Thing &thing);
 
+// Fast specializations for some primitive types.
+INLINE string format_string(const string &value);
+INLINE string format_string(float value);
+INLINE string format_string(double value);
+INLINE string format_string(unsigned int value);
+INLINE string format_string(int value);
+INLINE string format_string(PN_int64 value);
+
 #include "string_utils.I"
 
 #endif
-

+ 19 - 12
dtool/src/dtoolutil/win32ArgParser.cxx

@@ -2636,7 +2636,7 @@ write_module_class(ostream &out, Object *obj) {
     write_function_slot(out, 2, slots, "bf_getsegcount");
     write_function_slot(out, 2, slots, "bf_getcharbuffer");
     out << "#endif\n";
-    out << "#if PY_MAJOR_VERSION >= 0x02060000\n";
+    out << "#if PY_VERSION_HEX >= 0x02060000\n";
     write_function_slot(out, 2, slots, "bf_getbuffer");
     write_function_slot(out, 2, slots, "bf_releasebuffer");
     out << "#endif\n";
@@ -4475,15 +4475,23 @@ write_function_instance(ostream &out, FunctionRemap *remap,
 
   // Now convert (the rest of the) actual arguments, one by one.
   for (; pn < num_params; ++pn) {
-    if (pn > 0) {
-      expected_params += ", ";
+    ParameterRemap *param = remap->_parameters[pn]._remap;
+    CPPType *orig_type = param->get_orig_type();
+    CPPType *type = param->get_new_type();
+    CPPExpression *default_value = param->get_default_value();
+    string param_name = remap->get_parameter_name(pn);
+
+    if (!is_cpp_type_legal(orig_type)) {
+      // We can't wrap this.  We sometimes get here for default arguments.
+      // Just skip this parameter.
+      continue;
     }
 
-    bool is_optional = false;
     // Has this remap been selected to consider optional arguments for
     // this parameter?  We can do that by adding a vertical bar to the
     // PyArg_ParseTuple format string, coupled with some extra logic
     // in the argument handling, below.
+    bool is_optional = false;
     if (remap->_has_this && !is_constructor) {
       if (pn > min_num_args) {
         is_optional = true;
@@ -4500,11 +4508,9 @@ write_function_instance(ostream &out, FunctionRemap *remap,
       }
     }
 
-    ParameterRemap *param = remap->_parameters[pn]._remap;
-    CPPType *orig_type = param->get_orig_type();
-    CPPType *type = param->get_new_type();
-    CPPExpression *default_value = param->get_default_value();
-    string param_name = remap->get_parameter_name(pn);
+    if (pn > 0) {
+      expected_params += ", ";
+    }
 
     // This is the string to convert our local variable to the
     // appropriate C++ type.  Normally this is just a cast.
@@ -6432,10 +6438,11 @@ is_remap_legal(FunctionRemap *remap) {
     return false;
   }
 
-  // all params must be legal
+  // all non-optional params must be legal
   for (int pn = 0; pn < (int)remap->_parameters.size(); pn++) {
-    CPPType *orig_type = remap->_parameters[pn]._remap->get_orig_type();
-    if (!is_cpp_type_legal(orig_type)) {
+    ParameterRemap *param = remap->_parameters[pn]._remap;
+    CPPType *orig_type = param->get_orig_type();
+    if (param->get_default_value() == NULL && !is_cpp_type_legal(orig_type)) {
       return false;
     }
   }

+ 5 - 15
dtool/src/interrogatedb/py_panda.h

@@ -16,7 +16,7 @@
 #include "configVariableCore.h"
 #include "config_prc.h"
 #include "pstrtod.h"
-
+#include "string_utils.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ConfigDeclaration::Constructor
@@ -93,11 +93,7 @@ set_string_word(int n, const string &value) {
 ////////////////////////////////////////////////////////////////////
 void ConfigDeclaration::
 set_bool_word(int n, bool value) {
-  if (value) {
-    set_string_word(n, "1");
-  } else {
-    set_string_word(n, "0");
-  }
+  set_string_word(n, value ? "1" : "0");
 
   _words[n]._flags |= (F_checked_bool | F_valid_bool);
   _words[n]._bool = value;
@@ -112,9 +108,7 @@ set_bool_word(int n, bool value) {
 ////////////////////////////////////////////////////////////////////
 void ConfigDeclaration::
 set_int_word(int n, int value) {
-  ostringstream strm;
-  strm << value;
-  set_string_word(n, strm.str());
+  set_string_word(n, format_string(value));
 
   _words[n]._flags |= (F_checked_int | F_valid_int);
   _words[n]._int = value;
@@ -129,9 +123,7 @@ set_int_word(int n, int value) {
 ////////////////////////////////////////////////////////////////////
 void ConfigDeclaration::
 set_int64_word(int n, PN_int64 value) {
-  ostringstream strm;
-  strm << value;
-  set_string_word(n, strm.str());
+  set_string_word(n, format_string(value));
 
   _words[n]._flags |= (F_checked_int64 | F_valid_int64);
   _words[n]._int_64 = value;
@@ -146,9 +138,7 @@ set_int64_word(int n, PN_int64 value) {
 ////////////////////////////////////////////////////////////////////
 void ConfigDeclaration::
 set_double_word(int n, double value) {
-  ostringstream strm;
-  strm << value;
-  set_string_word(n, strm.str());
+  set_string_word(n, format_string(value));
 
   _words[n]._flags |= (F_checked_double | F_valid_double);
   _words[n]._double = value;

+ 2 - 4
dtool/src/prc/configVariableDouble.cxx

@@ -13,6 +13,7 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "configVariableDouble.h"
+#include "string_utils.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ConfigVariableDouble::set_default_value
@@ -21,8 +22,5 @@
 ////////////////////////////////////////////////////////////////////
 void ConfigVariableDouble::
 set_default_value(double default_value) {
-  ostringstream strm;
-  strm << default_value;
-
-  _core->set_default_value(strm.str());
+  _core->set_default_value(format_string(default_value));
 }

+ 2 - 4
dtool/src/prc/configVariableInt.cxx

@@ -13,6 +13,7 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "configVariableInt.h"
+#include "string_utils.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ConfigVariableInt::set_default_value
@@ -21,8 +22,5 @@
 ////////////////////////////////////////////////////////////////////
 void ConfigVariableInt::
 set_default_value(int default_value) {
-  ostringstream strm;
-  strm << default_value;
-
-  _core->set_default_value(strm.str());
+  _core->set_default_value(format_string(default_value));
 }

+ 2 - 4
dtool/src/prc/configVariableInt64.cxx

@@ -13,6 +13,7 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "configVariableInt64.h"
+#include "string_utils.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ConfigVariableInt64::set_default_value
@@ -21,8 +22,5 @@
 ////////////////////////////////////////////////////////////////////
 void ConfigVariableInt64::
 set_default_value(PN_int64 default_value) {
-  ostringstream strm;
-  strm << default_value;
-
-  _core->set_default_value(strm.str());
+  _core->set_default_value(format_string(default_value));
 }

+ 3 - 0
makepanda/installpanda.py

@@ -127,6 +127,9 @@ def GetLibDir():
     something like "lib" or "lib64" or in some cases, something
     similar to "lib/x86_64-linux-gnu". """
 
+    if sys.platform == "darwin":
+        return "lib"
+
     # This one's a bit tricky.  Some systems require us to install
     # 64-bits libraries into /usr/lib64, some into /usr/lib.
     # Debian forbids installing to lib64 nowadays, and the only distros

+ 140 - 112
makepanda/makepanda.py

@@ -67,7 +67,7 @@ MAJOR_VERSION=None
 COREAPI_VERSION=None
 PLUGIN_VERSION=None
 OSXTARGET=None
-UNIVERSAL=False
+OSX_ARCHS=[]
 HOST_URL=None
 global STRDXSDKVERSION, STRMSPLATFORMVERSION, BOOUSEINTELCOMPILER
 STRDXSDKVERSION = 'default'
@@ -150,6 +150,9 @@ def usage(problem):
     for pkg in PkgListGet():
         p = pkg.lower()
         print("  --use-%-9s   --no-%-9s (enable/disable use of %s)"%(p, p, pkg))
+    if sys.platform != 'win32':
+        print("  --<PKG>-incdir    (custom location for header files of thirdparty package)")
+        print("  --<PKG>-libdir    (custom location for library files of thirdparty package)")
     print("")
     print("  --nothing         (disable every third-party lib)")
     print("  --everything      (enable every third-party lib)")
@@ -165,7 +168,7 @@ def usage(problem):
 
 def parseopts(args):
     global INSTALLER,RTDIST,RUNTIME,GENMAN,DISTRIBUTOR,VERSION
-    global COMPRESSOR,THREADCOUNT,OSXTARGET,UNIVERSAL,HOST_URL
+    global COMPRESSOR,THREADCOUNT,OSXTARGET,OSX_ARCHS,HOST_URL
     global DEBVERSION,RPMRELEASE,GIT_COMMIT,P3DSUFFIX
     global STRDXSDKVERSION, STRMSPLATFORMVERSION, BOOUSEINTELCOMPILER
     longopts = [
@@ -179,11 +182,15 @@ def parseopts(args):
     optimize = ""
     target = None
     target_arch = None
-    for pkg in PkgListGet(): longopts.append("no-"+pkg.lower())
-    for pkg in PkgListGet(): longopts.append("use-"+pkg.lower())
+    universal = False
+    for pkg in PkgListGet():
+        longopts.append("use-" + pkg.lower())
+        longopts.append("no-" + pkg.lower())
+        longopts.append(pkg.lower() + "-incdir=")
+        longopts.append(pkg.lower() + "-libdir=")
     try:
         opts, extras = getopt.getopt(args, "", longopts)
-        for option,value in opts:
+        for option, value in opts:
             if (option=="--help"): raise Exception
             elif (option=="--optimize"): optimize=value
             elif (option=="--installer"): INSTALLER=1
@@ -197,7 +204,7 @@ def parseopts(args):
             elif (option=="--threads"): THREADCOUNT=int(value)
             elif (option=="--outputdir"): SetOutputDir(value.strip())
             elif (option=="--osxtarget"): OSXTARGET=value.strip()
-            elif (option=="--universal"): UNIVERSAL=True
+            elif (option=="--universal"): universal = True
             elif (option=="--target"): target = value.strip()
             elif (option=="--arch"): target_arch = value.strip()
             elif (option=="--nocolor"): DisableColors()
@@ -228,19 +235,25 @@ def parseopts(args):
             elif (option=="--use-icl"): BOOUSEINTELCOMPILER = True
             else:
                 for pkg in PkgListGet():
-                    if (option=="--use-"+pkg.lower()):
+                    if option == "--use-" + pkg.lower():
                         PkgEnable(pkg)
                         break
-                for pkg in PkgListGet():
-                    if (option=="--no-"+pkg.lower()):
+                    elif option == "--no-" + pkg.lower():
                         PkgDisable(pkg)
                         break
-            if  (option=="--everything" or option.startswith("--use-")
-                or option=="--nothing" or option.startswith("--no-")):
+                    elif option == "--" + pkg.lower() + "-incdir":
+                        PkgSetCustomLocation(pkg)
+                        IncDirectory(pkg, value)
+                        break
+                    elif option == "--" + pkg.lower() + "-libdir":
+                        PkgSetCustomLocation(pkg)
+                        LibDirectory(pkg, value)
+                        break
+            if (option == "--everything" or option.startswith("--use-")
+                or option == "--nothing" or option.startswith("--no-")):
                 anything = 1
     except:
-        usage(0)
-        print("Exception while parsing commandline:", sys.exc_info()[0])
+        usage(sys.exc_info()[1])
 
     if not anything:
         if RUNTIME:
@@ -252,23 +265,39 @@ def parseopts(args):
         usage("Options --runtime and --rtdist cannot be specified at the same time!")
     if (optimize=="" and (RTDIST or RUNTIME)): optimize = "4"
     elif (optimize==""): optimize = "3"
-    if (OSXTARGET != None and OSXTARGET.strip() == ""):
-        OSXTARGET = None
-    elif (OSXTARGET != None):
-        OSXTARGET = OSXTARGET.strip()
-        if (len(OSXTARGET) != 4 or not OSXTARGET.startswith("10.")):
-            usage("Invalid setting for OSXTARGET")
+
+    if OSXTARGET:
         try:
-            OSXTARGET = "10.%d" % (int(OSXTARGET[-1]))
+            maj, min = OSXTARGET.strip().split('.')
+            OSXTARGET = int(maj), int(min)
+            assert OSXTARGET[0] == 10
         except:
             usage("Invalid setting for OSXTARGET")
+    else:
+        OSXTARGET = None
 
-    if UNIVERSAL:
-        if not OSXTARGET:
-            exit("--universal requires --osxtarget")
+    if target is not None or target_arch is not None:
+        SetTarget(target, target_arch)
+
+    if universal:
         if target_arch:
             exit("--universal is incompatible with --arch")
 
+        OSX_ARCHS.append("i386")
+        if OSXTARGET:
+            osxver = OSXTARGET
+        else:
+            maj, min = platform.mac_ver()[0].split('.')[:2]
+            osxver = int(maj), int(min)
+
+        if osxver[1] < 6:
+            OSX_ARCHS.append("ppc")
+        else:
+            OSX_ARCHS.append("x86_64")
+
+    elif HasTargetArch():
+        OSX_ARCHS.append(GetTargetArch())
+
     try:
         SetOptimize(int(optimize))
         assert GetOptimize() in [1, 2, 3, 4]
@@ -278,9 +307,6 @@ def parseopts(args):
     if GIT_COMMIT is not None and not re.match("^[a-f0-9]{40}$", GIT_COMMIT):
         usage("Invalid SHA-1 hash given for --git-commit option!")
 
-    if target is not None or target_arch is not None:
-        SetTarget(target, target_arch)
-
     is_win7 = False
     if GetHost() == "windows":
         if (STRMSPLATFORMVERSION not in ['winserver2003r2', 'win60A']):
@@ -316,8 +342,8 @@ if ("LDFLAGS" in os.environ):
     LDFLAGS = os.environ["LDFLAGS"].strip()
 
 os.environ["MAKEPANDA"] = os.path.abspath(sys.argv[0])
-if (GetHost() == "darwin" and OSXTARGET != None):
-    os.environ["MACOSX_DEPLOYMENT_TARGET"] = OSXTARGET
+if GetHost() == "darwin" and OSXTARGET is not None:
+    os.environ["MACOSX_DEPLOYMENT_TARGET"] = "%d.%d" % OSXTARGET
 
 ########################################################################
 ##
@@ -683,7 +709,7 @@ if (COMPILER=="GCC"):
     elif RUNTIME:
         # We don't support Cocoa in the runtime yet.
         PkgDisable("COCOA")
-    if UNIVERSAL or GetTargetArch() == 'x86_64':
+    if 'x86_64' in OSX_ARCHS:
         # 64-bits OS X doesn't have Carbon.
         PkgDisable("CARBON")
 
@@ -710,7 +736,7 @@ if (COMPILER=="GCC"):
     if (not RUNTIME):
         SmartPkgEnable("EIGEN",     "eigen3",    (), ("Eigen/Dense",), target_pkg = 'ALWAYS')
         SmartPkgEnable("ARTOOLKIT", "",          ("AR"), "AR/ar.h")
-        SmartPkgEnable("FCOLLADA",  "",          ChooseLib(fcollada_libs, "FCOLLADA"), ("FCollada", "FCollada.h"))
+        SmartPkgEnable("FCOLLADA",  "",          ChooseLib(fcollada_libs, "FCOLLADA"), ("FCollada", "FCollada/FCollada.h"))
         SmartPkgEnable("FFMPEG",    ffmpeg_libs, ffmpeg_libs, ffmpeg_libs)
         SmartPkgEnable("SWSCALE",   "libswscale", "libswscale", ("libswscale", "libswscale/swscale.h"), target_pkg = "FFMPEG")
         SmartPkgEnable("SWRESAMPLE","libswresample", "libswresample", ("libswresample", "libswresample/swresample.h"), target_pkg = "FFMPEG")
@@ -734,11 +760,12 @@ if (COMPILER=="GCC"):
 
         if GetTarget() == "darwin" and not PkgSkip("FFMPEG"):
             LibName("FFMPEG", "-Wl,-read_only_relocs,suppress")
+            LibName("FFMPEG", "-framework VideoDecodeAcceleration")
 
         cv_lib = ChooseLib(("opencv_core", "cv"), "OPENCV")
         if cv_lib == "opencv_core":
             OPENCV_VER_23 = True
-            SmartPkgEnable("OPENCV", "opencv",   ("opencv_core"), ("opencv2/core/core.hpp"))
+            SmartPkgEnable("OPENCV", "opencv",   ("opencv_core", "opencv_highgui"), ("opencv2/core/core.hpp"))
         else:
             SmartPkgEnable("OPENCV", "opencv",   ("cv", "highgui", "cvaux", "ml", "cxcore"),
                            ("opencv", "opencv/cv.h", "opencv/cxcore.h", "opencv/highgui.h"))
@@ -752,8 +779,7 @@ if (COMPILER=="GCC"):
         SmartPkgEnable("ROCKET",    "",          rocket_libs, "Rocket/Core.h")
 
         if not PkgSkip("PYTHON"):
-            if GetHost() == "darwin" and GetTarget() == "darwin" and not RTDIST:
-                # Use the system Python framework in the standard Mac SDK.
+            if GetTarget() == "darwin" and not RTDIST and not PkgHasCustomLocation("PYTHON"):
                 LibName("PYTHON", "-framework Python")
             else:
                 SmartPkgEnable("PYTHON", "", SDK["PYTHONVERSION"], (SDK["PYTHONVERSION"], SDK["PYTHONVERSION"] + "/Python.h"), tool = SDK["PYTHONVERSION"] + "-config")
@@ -1125,20 +1151,13 @@ def CompileCxx(obj,src,opts):
         # Mac-specific flags.
         if GetTarget() == "darwin":
             cmd += " -Wno-deprecated-declarations"
-            if (OSXTARGET != None):
+            if OSXTARGET is not None:
                 cmd += " -isysroot " + SDK["MACOSX"]
-                cmd += " -mmacosx-version-min=" + OSXTARGET
-
-            if UNIVERSAL:
-                cmd += " -arch i386"
-                if OSXTARGET:
-                    osxver = int(OSXTARGET[-1])
-                    if "NOPPC" not in opts and int(OSXTARGET[-1]) < 6:
-                        cmd += " -arch ppc"
-                    if int(OSXTARGET[-1]) >= 5:
-                        cmd += " -arch x86_64"
-            elif HasTargetArch():
-                cmd += " -arch %s" % (GetTargetArch())
+                cmd += " -mmacosx-version-min=%d.%d" % (OSXTARGET)
+
+            for arch in OSX_ARCHS:
+                if 'NOARCH:' + arch.upper() not in opts:
+                    cmd += " -arch %s" % arch
 
         if "SYSROOT" in SDK:
             cmd += ' --sysroot=%s -no-canonical-prefixes' % (SDK["SYSROOT"])
@@ -1587,20 +1606,13 @@ def CompileLink(dll, obj, opts):
         # Mac OS X specific flags.
         if GetTarget() == 'darwin':
             cmd += " -headerpad_max_install_names"
-            if OSXTARGET != None:
+            if OSXTARGET is not None:
                 cmd += " -isysroot " + SDK["MACOSX"] + " -Wl,-syslibroot," + SDK["MACOSX"]
-                cmd += " -mmacosx-version-min=" + OSXTARGET
-
-            if UNIVERSAL:
-                cmd += " -arch i386"
-                if OSXTARGET:
-                    osxver = int(OSXTARGET[-1])
-                    if "NOPPC" not in opts and int(OSXTARGET[-1]) < 6:
-                        cmd += " -arch ppc"
-                    if int(OSXTARGET[-1]) >= 5:
-                        cmd += " -arch x86_64"
-            elif HasTargetArch():
-                cmd += " -arch %s" % (GetTargetArch())
+                cmd += " -mmacosx-version-min=%d.%d" % (OSXTARGET)
+
+            for arch in OSX_ARCHS:
+                if 'NOARCH:' + arch.upper() not in opts:
+                    cmd += " -arch %s" % arch
 
         if "SYSROOT" in SDK:
             cmd += " --sysroot=%s -no-canonical-prefixes" % (SDK["SYSROOT"])
@@ -1820,10 +1832,13 @@ def Package(target, inputs, opts):
     command += "direct/src/p3d/ppackage.py"
 
     if GetTarget() == "darwin":
-        if SDK.get("MACOSX") is not None:
+        if SDK.get("MACOSX"):
             command += " -R \"%s\"" % SDK["MACOSX"]
-        if UNIVERSAL:
-            command += " -u"
+
+        for arch in OSX_ARCHS:
+            if arch == "x86_64":
+                arch = "amd64"
+            command += " -P osx_%s" % arch
 
     command += " -i \"" + GetOutputDir() + "/stage\""
     if (P3DSUFFIX):
@@ -2608,14 +2623,27 @@ if tp_dir is not None:
                 if (PkgSkip("PYTHON")==0 and os.path.exists(tp_pkg + "/bin/" + SDK["PYTHONVERSION"])):
                     CopyAllFiles(GetOutputDir() + "/bin/", tp_pkg + "/bin/" + SDK["PYTHONVERSION"] + "/")
         else:
-            if os.path.exists(tp_pkg + "/lib"):
-                CopyAllFiles(GetOutputDir() + "/lib/", tp_pkg + "/lib/")
-                if (PkgSkip("PYTHON")==0 and os.path.exists(tp_pkg + "/lib/" + SDK["PYTHONVERSION"])):
-                    CopyAllFiles(GetOutputDir() + "/lib/", tp_pkg + "/lib/" + SDK["PYTHONVERSION"] + "/")
+            for tp_lib in glob.glob(tp_pkg + "/lib/*.so*"):
+                CopyFile(GetOutputDir() + "/lib/" + os.path.basename(tp_lib), tp_lib)
+
+            if not PkgSkip("PYTHON"):
+                for tp_lib in glob.glob(os.path.join(tp_pkg, "lib", SDK["PYTHONVERSION"], "*.so*")):
+                    CopyFile(GetOutputDir() + "/lib/" + os.path.basename(tp_lib), tp_lib)
+
+            if GetTarget() == 'darwin':
+                for tp_lib in glob.glob(tp_pkg + "/lib/*.dylib"):
+                    CopyFile(GetOutputDir() + "/lib/" + os.path.basename(tp_lib), tp_lib)
+
+                if not PkgSkip("PYTHON"):
+                    for tp_lib in glob.glob(os.path.join(tp_pkg, "lib", SDK["PYTHONVERSION"], "*.dylib")):
+                        CopyFile(GetOutputDir() + "/lib/" + os.path.basename(tp_lib), tp_lib)
+
+                for fwx in glob.glob(tp_pkg + "/*.framework"):
+                    CopyTree(GetOutputDir() + "/Frameworks/" + os.path.basename(fwx), fwx)
 
     if GetTarget() == 'windows':
         CopyAllFiles(GetOutputDir() + "/bin/", tp_dir + "extras/bin/")
-        if PkgSkip("PYTHON") == 0:
+        if not PkgSkip("PYTHON"):
             pydll = "/" + SDK["PYTHONVERSION"].replace(".", "")
             if (GetOptimize() <= 2): pydll += "_d.dll"
             else: pydll += ".dll"
@@ -3745,7 +3773,6 @@ if (not RUNTIME):
 
   TargetAdd('core_module.obj', opts=['IMOD:panda3d.core', 'ILIB:core'])
 
-  OPTS=['WINSOCK2']
   TargetAdd('core.pyd', input='libp3downloader_igate.obj')
   TargetAdd('core.pyd', input='p3express_ext_composite.obj')
   TargetAdd('core.pyd', input='libp3express_igate.obj')
@@ -3795,7 +3822,7 @@ if (not RUNTIME):
   TargetAdd('core.pyd', input='core_module.obj')
   TargetAdd('core.pyd', input='libp3tinyxml.ilb')
   TargetAdd('core.pyd', input=COMMON_PANDA_LIBS)
-  TargetAdd('core.pyd', opts=OPTS)
+  TargetAdd('core.pyd', opts=['PYTHON', 'WINSOCK2'])
 
 #
 # DIRECTORY: panda/src/vision/
@@ -4166,7 +4193,7 @@ if (not RUNTIME):
 #
 
 if (not RUNTIME and PkgSkip("GL")==0):
-  OPTS=['DIR:panda/src/glgsg', 'DIR:panda/src/glstuff', 'BUILDING:PANDAGL',  'NVIDIACG']
+  OPTS=['DIR:panda/src/glgsg', 'DIR:panda/src/glstuff', 'BUILDING:PANDAGL', 'GL', 'NVIDIACG']
   TargetAdd('p3glgsg_config_glgsg.obj', opts=OPTS, input='config_glgsg.cxx')
   TargetAdd('p3glgsg_glgsg.obj', opts=OPTS, input='glgsg.cxx')
 
@@ -4175,7 +4202,7 @@ if (not RUNTIME and PkgSkip("GL")==0):
 #
 
 if (not RUNTIME and PkgSkip("GLES")==0):
-  OPTS=['DIR:panda/src/glesgsg', 'DIR:panda/src/glstuff', 'BUILDING:PANDAGLES']
+  OPTS=['DIR:panda/src/glesgsg', 'DIR:panda/src/glstuff', 'BUILDING:PANDAGLES', 'GLES']
   TargetAdd('p3glesgsg_config_glesgsg.obj', opts=OPTS, input='config_glesgsg.cxx')
   TargetAdd('p3glesgsg_glesgsg.obj', opts=OPTS, input='glesgsg.cxx')
 
@@ -4184,7 +4211,7 @@ if (not RUNTIME and PkgSkip("GLES")==0):
 #
 
 if (not RUNTIME and PkgSkip("GLES2")==0):
-  OPTS=['DIR:panda/src/gles2gsg', 'DIR:panda/src/glstuff', 'BUILDING:PANDAGLES2']
+  OPTS=['DIR:panda/src/gles2gsg', 'DIR:panda/src/glstuff', 'BUILDING:PANDAGLES2', 'GLES2']
   TargetAdd('p3gles2gsg_config_gles2gsg.obj', opts=OPTS, input='config_gles2gsg.cxx')
   TargetAdd('p3gles2gsg_gles2gsg.obj', opts=OPTS, input='gles2gsg.cxx')
 
@@ -4429,10 +4456,10 @@ if (PkgSkip("BULLET")==0 and not RUNTIME):
 #
 
 if (PkgSkip("PHYSX")==0):
-  OPTS=['DIR:panda/src/physx', 'BUILDING:PANDAPHYSX', 'PHYSX', 'NOPPC']
+  OPTS=['DIR:panda/src/physx', 'BUILDING:PANDAPHYSX', 'PHYSX', 'NOARCH:PPC']
   TargetAdd('p3physx_composite.obj', opts=OPTS, input='p3physx_composite.cxx')
 
-  OPTS=['DIR:panda/src/physx', 'PHYSX', 'NOPPC']
+  OPTS=['DIR:panda/src/physx', 'PHYSX', 'NOARCH:PPC']
   IGATEFILES=GetDirectoryContents('panda/src/physx', ["*.h", "*_composite*.cxx"])
   TargetAdd('libpandaphysx.in', opts=OPTS, input=IGATEFILES)
   TargetAdd('libpandaphysx.in', opts=['IMOD:panda3d.physx', 'ILIB:libpandaphysx', 'SRCDIR:panda/src/physx'])
@@ -4443,15 +4470,15 @@ if (PkgSkip("PHYSX")==0):
 #
 
 if (PkgSkip("PHYSX")==0):
-  OPTS=['DIR:panda/metalibs/pandaphysx', 'BUILDING:PANDAPHYSX', 'PHYSX', 'NOPPC']
+  OPTS=['DIR:panda/metalibs/pandaphysx', 'BUILDING:PANDAPHYSX', 'PHYSX', 'NOARCH:PPC']
   TargetAdd('pandaphysx_pandaphysx.obj', opts=OPTS, input='pandaphysx.cxx')
 
   TargetAdd('libpandaphysx.dll', input='pandaphysx_pandaphysx.obj')
   TargetAdd('libpandaphysx.dll', input='p3physx_composite.obj')
   TargetAdd('libpandaphysx.dll', input=COMMON_PANDA_LIBS)
-  TargetAdd('libpandaphysx.dll', opts=['WINUSER', 'PHYSX', 'NOPPC'])
+  TargetAdd('libpandaphysx.dll', opts=['WINUSER', 'PHYSX', 'NOARCH:PPC'])
 
-  OPTS=['DIR:panda/metalibs/pandaphysx', 'PHYSX', 'NOPPC']
+  OPTS=['DIR:panda/metalibs/pandaphysx', 'PHYSX', 'NOARCH:PPC']
   TargetAdd('physx_module.obj', input='libpandaphysx.in')
   TargetAdd('physx_module.obj', opts=OPTS)
   TargetAdd('physx_module.obj', opts=['IMOD:panda3d.physx', 'ILIB:physx'])
@@ -4461,7 +4488,7 @@ if (PkgSkip("PHYSX")==0):
   TargetAdd('physx.pyd', input='libpandaphysx.dll')
   TargetAdd('physx.pyd', input='core.pyd')
   TargetAdd('physx.pyd', input=COMMON_PANDA_LIBS)
-  TargetAdd('physx.pyd', opts=['PYTHON', 'WINUSER', 'PHYSX', 'NOPPC'])
+  TargetAdd('physx.pyd', opts=['PYTHON', 'WINUSER', 'PHYSX', 'NOARCH:PPC'])
 
 #
 # DIRECTORY: panda/src/physics/
@@ -4882,7 +4909,7 @@ if (RTDIST or RUNTIME):
       TargetAdd('p3dcert.exe', input='plugin_mkdir_complete.obj')
       TargetAdd('p3dcert.exe', input='plugin_wstring_encode.obj')
       TargetAdd('p3dcert.exe', input='plugin_p3dCert.obj')
-      OPTS=['OPENSSL', 'FLTK', 'WINCOMCTL', 'WINSOCK', 'WINGDI', 'WINUSER', 'ADVAPI', 'WINOLE', 'WINSHELL', 'SUBSYSTEM:WINDOWS']
+      OPTS=['OPENSSL', 'FLTK', 'X11', 'WINCOMCTL', 'WINSOCK', 'WINGDI', 'WINUSER', 'ADVAPI', 'WINOLE', 'WINSHELL', 'SUBSYSTEM:WINDOWS']
       if GetTarget() == 'darwin':
           OPTS += ['OPT:2']
       TargetAdd('p3dcert.exe', opts=OPTS)
@@ -5853,9 +5880,18 @@ if (PkgSkip("PANDATOOL")==0):
 #
 
 for VER in MAYAVERSIONS:
-  VNUM=VER[4:]
-  if (PkgSkip(VER)==0) and (PkgSkip("PANDATOOL")==0):
-    OPTS=['DIR:pandatool/src/mayaprogs', 'DIR:pandatool/src/maya', 'DIR:pandatool/src/mayaegg', 'DIR:pandatool/src/cvscopy', 'BUILDING:MISC', VER]
+  VNUM = VER[4:]
+  if not PkgSkip(VER) and not PkgSkip("PANDATOOL"):
+    if GetTarget() == 'darwin' and int(VNUM) >= 2012:
+      ARCH_OPTS = ['NOARCH:PPC', 'NOARCH:I386']
+      if len(OSX_ARCHS) != 0 and 'x86_64' not in OSX_ARCHS:
+        continue
+    elif GetTarget() == 'darwin' and int(VNUM) >= 2009:
+      ARCH_OPTS = ['NOARCH:PPC']
+    else:
+      ARCH_OPTS = []
+
+    OPTS=['DIR:pandatool/src/mayaprogs', 'DIR:pandatool/src/maya', 'DIR:pandatool/src/mayaegg', 'DIR:pandatool/src/cvscopy', 'BUILDING:MISC', VER] + ARCH_OPTS
     TargetAdd('mayaeggimport'+VNUM+'_mayaeggimport.obj', opts=OPTS, input='mayaEggImport.cxx')
     TargetAdd('mayaeggimport'+VNUM+'.mll', input='mayaegg'+VNUM+'_loader.obj')
     TargetAdd('mayaeggimport'+VNUM+'.mll', input='mayaeggimport'+VNUM+'_mayaeggimport.obj')
@@ -5863,7 +5899,7 @@ for VER in MAYAVERSIONS:
     TargetAdd('mayaeggimport'+VNUM+'.mll', input=COMMON_PANDA_LIBS)
     if GetTarget() == 'windows':
       TargetAdd('mayaeggimport'+VNUM+'.mll', input='libp3pystub.lib')
-    TargetAdd('mayaeggimport'+VNUM+'.mll', opts=['ADVAPI', VER])
+    TargetAdd('mayaeggimport'+VNUM+'.mll', opts=['ADVAPI', VER]+ARCH_OPTS)
 
     TargetAdd('mayaloader'+VNUM+'_config_mayaloader.obj', opts=OPTS, input='config_mayaloader.cxx')
     TargetAdd('libp3mayaloader'+VNUM+'.dll', input='mayaloader'+VNUM+'_config_mayaloader.obj')
@@ -5887,7 +5923,7 @@ for VER in MAYAVERSIONS:
     TargetAdd('libp3mayaloader'+VNUM+'.dll', input='libp3pandatoolbase.lib')
     TargetAdd('libp3mayaloader'+VNUM+'.dll', input='libpandaegg.dll')
     TargetAdd('libp3mayaloader'+VNUM+'.dll', input=COMMON_PANDA_LIBS)
-    TargetAdd('libp3mayaloader'+VNUM+'.dll', opts=['ADVAPI', VER])
+    TargetAdd('libp3mayaloader'+VNUM+'.dll', opts=['ADVAPI', VER]+ARCH_OPTS)
 
     TargetAdd('mayapview'+VNUM+'_mayaPview.obj', opts=OPTS, input='mayaPview.cxx')
     TargetAdd('libmayapview'+VNUM+'.mll', input='mayapview'+VNUM+'_mayaPview.obj')
@@ -5898,7 +5934,7 @@ for VER in MAYAVERSIONS:
       TargetAdd('libmayapview'+VNUM+'.mll', input=COMMON_EGG2X_LIBS_PYSTUB)
     else:
       TargetAdd('libmayapview'+VNUM+'.mll', input=COMMON_EGG2X_LIBS)
-    TargetAdd('libmayapview'+VNUM+'.mll', opts=['ADVAPI', VER])
+    TargetAdd('libmayapview'+VNUM+'.mll', opts=['ADVAPI', VER]+ARCH_OPTS)
 
     TargetAdd('maya2egg'+VNUM+'_mayaToEgg.obj', opts=OPTS, input='mayaToEgg.cxx')
     TargetAdd('maya2egg'+VNUM+'_bin.exe', input='maya2egg'+VNUM+'_mayaToEgg.obj')
@@ -5908,10 +5944,7 @@ for VER in MAYAVERSIONS:
       TargetAdd('maya2egg'+VNUM+'_bin.exe', input=COMMON_EGG2X_LIBS_PYSTUB)
     else:
       TargetAdd('maya2egg'+VNUM+'_bin.exe', input=COMMON_EGG2X_LIBS)
-    if GetTarget() == "darwin" and int(VNUM) >= 2009:
-      TargetAdd('maya2egg'+VNUM+'_bin.exe', opts=['ADVAPI', 'NOPPC', VER])
-    else:
-      TargetAdd('maya2egg'+VNUM+'_bin.exe', opts=['ADVAPI', VER])
+    TargetAdd('maya2egg'+VNUM+'_bin.exe', opts=['ADVAPI', VER]+ARCH_OPTS)
 
     TargetAdd('egg2maya'+VNUM+'_eggToMaya.obj', opts=OPTS, input='eggToMaya.cxx')
     TargetAdd('egg2maya'+VNUM+'_bin.exe', input='egg2maya'+VNUM+'_eggToMaya.obj')
@@ -5921,10 +5954,7 @@ for VER in MAYAVERSIONS:
       TargetAdd('egg2maya'+VNUM+'_bin.exe', input=COMMON_EGG2X_LIBS_PYSTUB)
     else:
       TargetAdd('egg2maya'+VNUM+'_bin.exe', input=COMMON_EGG2X_LIBS)
-    if GetTarget() == 'darwin' and int(VNUM) >= 2009:
-      TargetAdd('egg2maya'+VNUM+'_bin.exe', opts=['ADVAPI', 'NOPPC', VER])
-    else:
-      TargetAdd('egg2maya'+VNUM+'_bin.exe', opts=['ADVAPI', VER])
+    TargetAdd('egg2maya'+VNUM+'_bin.exe', opts=['ADVAPI', VER]+ARCH_OPTS)
 
     TargetAdd('mayacopy'+VNUM+'_mayaCopy.obj', opts=OPTS, input='mayaCopy.cxx')
     TargetAdd('mayacopy'+VNUM+'_bin.exe', input='mayacopy'+VNUM+'_mayaCopy.obj')
@@ -5934,31 +5964,28 @@ for VER in MAYAVERSIONS:
       TargetAdd('mayacopy'+VNUM+'_bin.exe', input=COMMON_EGG2X_LIBS_PYSTUB)
     else:
       TargetAdd('mayacopy'+VNUM+'_bin.exe', input=COMMON_EGG2X_LIBS)
-    if GetTarget() == 'darwin' and int(VNUM) >= 2009:
-      TargetAdd('mayacopy'+VNUM+'_bin.exe', opts=['ADVAPI', 'NOPPC', VER])
-    else:
-      TargetAdd('mayacopy'+VNUM+'_bin.exe', opts=['ADVAPI', VER])
+    TargetAdd('mayacopy'+VNUM+'_bin.exe', opts=['ADVAPI', VER]+ARCH_OPTS)
 
     TargetAdd('mayasavepview'+VNUM+'_mayaSavePview.obj', opts=OPTS, input='mayaSavePview.cxx')
     TargetAdd('libmayasavepview'+VNUM+'.mll', input='mayasavepview'+VNUM+'_mayaSavePview.obj')
-    TargetAdd('libmayasavepview'+VNUM+'.mll', opts=['ADVAPI',  VER])
+    TargetAdd('libmayasavepview'+VNUM+'.mll', opts=['ADVAPI', VER]+ARCH_OPTS)
 
     TargetAdd('mayapath'+VNUM+'.obj', opts=OPTS, input='mayapath.cxx')
 
     TargetAdd('maya2egg'+VNUM+'.exe', input='mayapath'+VNUM+'.obj')
-    TargetAdd('maya2egg'+VNUM+'.exe', opts=['ADVAPI'])
-    TargetAdd('maya2egg'+VNUM+'.exe', input=COMMON_DTOOL_LIBS)
     TargetAdd('maya2egg'+VNUM+'.exe', input='libpandaexpress.dll')
+    TargetAdd('maya2egg'+VNUM+'.exe', input=COMMON_DTOOL_LIBS_PYSTUB)
+    TargetAdd('maya2egg'+VNUM+'.exe', opts=['ADVAPI']+ARCH_OPTS)
 
     TargetAdd('egg2maya'+VNUM+'.exe', input='mayapath'+VNUM+'.obj')
-    TargetAdd('egg2maya'+VNUM+'.exe', opts=['ADVAPI'])
-    TargetAdd('egg2maya'+VNUM+'.exe', input=COMMON_DTOOL_LIBS)
     TargetAdd('egg2maya'+VNUM+'.exe', input='libpandaexpress.dll')
+    TargetAdd('egg2maya'+VNUM+'.exe', input=COMMON_DTOOL_LIBS_PYSTUB)
+    TargetAdd('egg2maya'+VNUM+'.exe', opts=['ADVAPI']+ARCH_OPTS)
 
     TargetAdd('mayacopy'+VNUM+'.exe', input='mayapath'+VNUM+'.obj')
-    TargetAdd('mayacopy'+VNUM+'.exe', opts=['ADVAPI'])
-    TargetAdd('mayacopy'+VNUM+'.exe', input=COMMON_DTOOL_LIBS)
     TargetAdd('mayacopy'+VNUM+'.exe', input='libpandaexpress.dll')
+    TargetAdd('mayacopy'+VNUM+'.exe', input=COMMON_DTOOL_LIBS_PYSTUB)
+    TargetAdd('mayacopy'+VNUM+'.exe', opts=['ADVAPI']+ARCH_OPTS)
 
 #
 # DIRECTORY: contrib/src/ai/
@@ -6597,6 +6624,7 @@ def MakeInstallerOSX():
     oscmd("cp -R %s/models                dstroot/base/Developer/Panda3D/models" % GetOutputDir())
     oscmd("cp -R doc/LICENSE              dstroot/base/Developer/Panda3D/LICENSE")
     oscmd("cp -R doc/ReleaseNotes         dstroot/base/Developer/Panda3D/ReleaseNotes")
+    oscmd("cp -R %s/Frameworks            dstroot/base/Developer/Panda3D/Frameworks" % GetOutputDir())
     if os.path.isdir(GetOutputDir()+"/plugins"):
         oscmd("cp -R %s/plugins           dstroot/base/Developer/Panda3D/plugins" % GetOutputDir())
 
@@ -6650,11 +6678,11 @@ def MakeInstallerOSX():
     if PkgSkip("PYTHON")==0:
         PV = SDK["PYTHONVERSION"].replace("python", "")
         oscmd("mkdir -p dstroot/pythoncode/usr/bin")
-        oscmd("mkdir -p dstroot/pythoncode/Developer/Panda3D/direct")
+        oscmd("mkdir -p dstroot/pythoncode/Developer/Panda3D")
         oscmd("mkdir -p dstroot/pythoncode/Library/Python/%s/site-packages" % PV)
         WriteFile("dstroot/pythoncode/Library/Python/%s/site-packages/Panda3D.pth" % PV, "/Developer/Panda3D")
         oscmd("cp -R %s/pandac                dstroot/pythoncode/Developer/Panda3D/pandac" % GetOutputDir())
-        oscmd("cp -R direct/src/*             dstroot/pythoncode/Developer/Panda3D/direct")
+        oscmd("cp -R %s/direct                dstroot/pythoncode/Developer/Panda3D/direct" % GetOutputDir())
         oscmd("ln -s %s                       dstroot/pythoncode/usr/bin/ppython" % SDK["PYTHONEXEC"])
         if os.path.isdir(GetOutputDir()+"/Pmw"):
             oscmd("cp -R %s/Pmw               dstroot/pythoncode/Developer/Panda3D/Pmw" % GetOutputDir())
@@ -6691,15 +6719,15 @@ def MakeInstallerOSX():
         if not os.path.isdir("dstroot/" + pkg):
             os.makedirs("dstroot/" + pkg)
 
-        if OSXTARGET:
-            target = '--target %s' % (OSXTARGET)
+        if OSXTARGET and OSXTARGET <= (10, 5):
+            target = '--target %d.%d' % (OSXTARGET)
         else:
             target = ''
 
         if os.path.exists("/Developer/usr/bin/packagemaker"):
             cmd = '/Developer/usr/bin/packagemaker --info /tmp/Info_plist --version ' + VERSION + ' --out dstroot/Panda3D/Panda3D.mpkg/Contents/Packages/' + pkg + '.pkg ' + target + ' --domain system --root dstroot/' + pkg + '/ --no-relocate'
         elif os.path.exists("/Applications/Xcode.app/Contents/Applications/PackageMaker.app/Contents/MacOS/PackageMaker"):
-            cmd = '/Applications/Xcode.app/Contents/Applications/PackageMaker.app/Contents/MacOS/PackageMaker --info /tmp/Info_plist --version ' + VERSION + ' --out dstroot/Panda3D/Panda3D.mpkg/Contents/Packages/' + pkg + '.pkg --target ' + target + ' --domain system --root dstroot/' + pkg + '/ --no-relocate'
+            cmd = '/Applications/Xcode.app/Contents/Applications/PackageMaker.app/Contents/MacOS/PackageMaker --info /tmp/Info_plist --version ' + VERSION + ' --out dstroot/Panda3D/Panda3D.mpkg/Contents/Packages/' + pkg + '.pkg ' + target + ' --domain system --root dstroot/' + pkg + '/ --no-relocate'
         elif os.path.exists("/Developer/Tools/packagemaker"):
             cmd = '/Developer/Tools/packagemaker -build -f dstroot/' + pkg + '/ -p dstroot/Panda3D/Panda3D.mpkg/Contents/Packages/' + pkg + '.pkg -i /tmp/Info_plist'
         else:
@@ -6713,7 +6741,7 @@ def MakeInstallerOSX():
     dist = open("dstroot/Panda3D/Panda3D.mpkg/Contents/distribution.dist", "w")
     dist.write('<?xml version="1.0" encoding="utf-8"?>\n')
     dist.write('<installer-script minSpecVersion="1.000000" authoringTool="com.apple.PackageMaker" authoringToolVersion="3.0.3" authoringToolBuild="174">\n')
-    dist.write('    <title>Panda3D</title>\n')
+    dist.write('    <title>Panda3D SDK %s</title>\n' % (VERSION))
     dist.write('    <options customize="always" allow-external-scripts="no" rootVolumeOnly="false"/>\n')
     dist.write('    <license language="en" mime-type="text/plain">%s</license>\n' % ReadFile("doc/LICENSE"))
     dist.write('    <choices-outline>\n')
@@ -6752,8 +6780,8 @@ def MakeInstallerOSX():
     dist.write('</installer-script>\n')
     dist.close()
 
-    oscmd('hdiutil create Panda3D-rw.dmg -srcfolder dstroot/Panda3D')
-    oscmd('hdiutil convert Panda3D-rw.dmg -format UDBZ -o Panda3D-%s.dmg' % VERSION)
+    oscmd('hdiutil create Panda3D-rw.dmg -volname "Panda3D SDK %s" -srcfolder dstroot/Panda3D' % (VERSION))
+    oscmd('hdiutil convert Panda3D-rw.dmg -format UDBZ -o Panda3D-%s.dmg' % (VERSION))
     oscmd('rm -f Panda3D-rw.dmg')
 
 def MakeInstallerFreeBSD():

+ 87 - 39
makepanda/makepandacore.py

@@ -1062,7 +1062,10 @@ def MakeBuildTree():
     MakeDirectory(OUTPUTDIR + "/panda3d")
     CreateFile(OUTPUTDIR + "/panda3d/__init__.py")
 
-    if GetTarget() == 'android':
+    if GetTarget() == 'darwin':
+        MakeDirectory(OUTPUTDIR + "/Frameworks")
+
+    elif GetTarget() == 'android':
         MakeDirectory(OUTPUTDIR + "/libs")
         MakeDirectory(OUTPUTDIR + "/libs/" + ANDROID_ABI)
         MakeDirectory(OUTPUTDIR + "/src")
@@ -1214,8 +1217,9 @@ def UnsetLinkAllStatic():
 ##
 ########################################################################
 
-PKG_LIST_ALL=[]
-PKG_LIST_OMIT={}
+PKG_LIST_ALL = []
+PKG_LIST_OMIT = {}
+PKG_LIST_CUSTOM = set()
 
 def PkgListSet(pkgs):
     global PKG_LIST_ALL
@@ -1241,6 +1245,12 @@ def PkgEnable(pkg):
 def PkgDisable(pkg):
     PKG_LIST_OMIT[pkg] = 1
 
+def PkgSetCustomLocation(pkg):
+    PKG_LIST_CUSTOM.add(pkg)
+
+def PkgHasCustomLocation(pkg):
+    return pkg in PKG_LIST_CUSTOM
+
 def PkgSkip(pkg):
     return PKG_LIST_OMIT[pkg]
 
@@ -1398,22 +1408,22 @@ def PkgConfigEnable(opt, pkgname, tool = "pkg-config"):
     for i, j in PkgConfigGetDefSymbols(pkgname, tool).items():
         DefSymbol(opt, i, j)
 
-def LibraryExists(lib, lpath=[]):
+def LocateLibrary(lib, lpath=[]):
     """ Returns True if this library was found in the given search path, False otherwise. """
     target = GetTarget()
 
     for dir in lpath:
         if target == 'darwin' and os.path.isfile(os.path.join(dir, 'lib%s.dylib' % lib)):
-            return True
+            return os.path.join(dir, 'lib%s.dylib' % lib)
         elif target != 'darwin' and os.path.isfile(os.path.join(dir, 'lib%s.so' % lib)):
-            return True
+            return os.path.join(dir, 'lib%s.so' % lib)
         elif os.path.isfile(os.path.join(dir, 'lib%s.a' % lib)):
-            return True
+            return os.path.join(dir, 'lib%s.a' % lib)
 
-    return False
+    return None
 
 def SystemLibraryExists(lib):
-    return LibraryExists(lib, SYS_LIB_DIRS)
+    return LocateLibrary(lib, SYS_LIB_DIRS) is not None
 
 def ChooseLib(libs, thirdparty=None):
     """ Chooses a library from the parameters, in order of preference. Returns the first if none of them were found. """
@@ -1427,7 +1437,7 @@ def ChooseLib(libs, thirdparty=None):
         libname = l
         if l.startswith("lib"):
             libname = l[3:]
-        if LibraryExists(libname, lpath):
+        if LocateLibrary(libname, lpath):
             return libname
 
     if len(libs) > 0:
@@ -1463,16 +1473,18 @@ def SmartPkgEnable(pkg, pkgconfig = None, libs = None, incs = None, defs = None,
         for d in olddefs:
             defs[d] = ""
 
-    if (pkg.lower() == "swscale" and os.path.isfile(GetThirdpartyDir() + "ffmpeg/include/libswscale/swscale.h")):
+    custom_loc = PkgHasCustomLocation(pkg)
+
+    if pkg.lower() == "swscale" and os.path.isfile(GetThirdpartyDir() + "ffmpeg/include/libswscale/swscale.h"):
         # Let it be handled by the ffmpeg package
         LibName(target_pkg, "-lswscale")
         return
-    if (pkg.lower() == "swresample" and os.path.isfile(GetThirdpartyDir() + "ffmpeg/include/libswresample/swresample.h")):
+    if pkg.lower() == "swresample" and os.path.isfile(GetThirdpartyDir() + "ffmpeg/include/libswresample/swresample.h"):
         LibName(target_pkg, "-lswresample")
         return
 
     pkg_dir = os.path.join(GetThirdpartyDir(), pkg.lower())
-    if (os.path.isdir(pkg_dir)):
+    if not custom_loc and os.path.isdir(pkg_dir):
         if framework and os.path.isdir(os.path.join(pkg_dir, framework + ".framework")):
             FrameworkDirectory(target_pkg, pkg_dir)
             LibName(target_pkg, "-framework " + framework)
@@ -1512,7 +1524,7 @@ def SmartPkgEnable(pkg, pkgconfig = None, libs = None, incs = None, defs = None,
             DefSymbol(target_pkg, d, v)
         return
 
-    elif (GetHost() == "darwin" and framework != None):
+    elif not custom_loc and GetHost() == "darwin" and framework != None:
         prefix = SDK["MACOSX"]
         if (os.path.isdir(prefix + "/Library/Frameworks/%s.framework" % framework) or
             os.path.isdir(prefix + "/System/Library/Frameworks/%s.framework" % framework) or
@@ -1526,7 +1538,7 @@ def SmartPkgEnable(pkg, pkgconfig = None, libs = None, incs = None, defs = None,
         elif VERBOSE:
             print(ColorText("cyan", "Couldn't find the framework %s" % (framework)))
 
-    elif (LocateBinary(tool) != None and (tool != "pkg-config" or pkgconfig != None)):
+    elif not custom_loc and LocateBinary(tool) != None and (tool != "pkg-config" or pkgconfig != None):
         if (isinstance(pkgconfig, str) or tool != "pkg-config"):
             if (PkgConfigHavePkg(pkgconfig, tool)):
                 return PkgConfigEnable(target_pkg, pkgconfig, tool)
@@ -1556,22 +1568,38 @@ def SmartPkgEnable(pkg, pkgconfig = None, libs = None, incs = None, defs = None,
             libname = l
             if l.startswith("lib"):
                 libname = l[3:]
-            if SystemLibraryExists(libname):
+
+            if custom_loc:
+                # Try searching in the package's LibDirectories.
+                lpath = [dir for ppkg, dir in LIBDIRECTORIES if pkg == ppkg]
+                location = LocateLibrary(libname, lpath)
+                if location is not None:
+                    LibName(target_pkg, location)
+                else:
+                    have_pkg = False
+                    print(GetColor("cyan") + "Couldn't find library lib" + libname + GetColor())
+
+            elif SystemLibraryExists(libname):
+                # It exists in a system library directory.
                 LibName(target_pkg, "-l" + libname)
             else:
                 # Try searching in the package's LibDirectories.
                 lpath = [dir for ppkg, dir in LIBDIRECTORIES if pkg == ppkg or ppkg == "ALWAYS"]
-                if LibraryExists(libname, lpath):
+                location = LocateLibrary(libname, lpath)
+                if location is not None:
                     LibName(target_pkg, "-l" + libname)
                 else:
                     have_pkg = False
-                    if VERBOSE:
+                    if VERBOSE or custom_loc:
                         print(GetColor("cyan") + "Couldn't find library lib" + libname + GetColor())
 
         # Determine which include directories to look in.
-        incdirs = list(SYS_INC_DIRS)
+        incdirs = []
+        if not custom_loc:
+            incdirs += list(SYS_INC_DIRS)
+
         for ppkg, pdir in INCDIRECTORIES:
-            if pkg == ppkg or ppkg == "ALWAYS":
+            if pkg == ppkg or (ppkg == "ALWAYS" and not custom_loc):
                 incdirs.append(pdir)
 
         # The incs list contains both subdirectories to explicitly add to
@@ -1585,14 +1613,17 @@ def SmartPkgEnable(pkg, pkgconfig = None, libs = None, incs = None, defs = None,
             # Note: It's possible to specify a file instead of a dir, for the sake of checking if it exists.
             if incdir is None and i.endswith(".h"):
                 have_pkg = False
-                if VERBOSE:
+                if VERBOSE or custom_loc:
                     print(GetColor("cyan") + "Couldn't find header file " + i + GetColor())
 
             if incdir is not None and os.path.isdir(incdir):
                 IncDirectory(target_pkg, incdir)
 
-        if (not have_pkg):
-            if (pkg in PkgListGet()):
+        if not have_pkg:
+            if custom_loc:
+                print("%sERROR:%s Could not locate thirdparty package %s in specified directory, aborting build" % (GetColor("red"), GetColor(), pkg.lower()))
+                exit()
+            elif pkg in PkgListGet():
                 print("%sWARNING:%s Could not locate thirdparty package %s, excluding from build" % (GetColor("red"), GetColor(), pkg.lower()))
                 PkgDisable(pkg)
             else:
@@ -1847,7 +1878,6 @@ def SdkLocatePython(prefer_thirdparty_python=False):
 
     elif CrossCompiling() or (prefer_thirdparty_python and os.path.isdir(os.path.join(GetThirdpartyDir(), "python"))):
         tp_python = os.path.join(GetThirdpartyDir(), "python")
-        SDK["PYTHON"] = tp_python + "/include"
 
         if GetTarget() == 'darwin':
             py_libs = glob.glob(tp_python + "/lib/libpython[0-9].[0-9].dylib")
@@ -1865,6 +1895,24 @@ def SdkLocatePython(prefer_thirdparty_python=False):
         py_lib = os.path.basename(py_libs[0])
         SDK["PYTHONVERSION"] = "python" + py_lib[9] + "." + py_lib[11]
         SDK["PYTHONEXEC"] = tp_python + "/bin/" + SDK["PYTHONVERSION"]
+        SDK["PYTHON"] = tp_python + "/include/" + SDK["PYTHONVERSION"]
+
+    elif GetTarget() == 'darwin':
+         # On Mac OS X, use the system Python framework.
+         py_fwx = SDK.get("MACOSX", "") + "/System/Library/Frameworks/Python.framework/Versions/Current"
+
+         if not os.path.islink(py_fwx):
+             exit("Could not locate Python installation at %s" % (py_fwx))
+
+         ver = os.path.basename(os.readlink(py_fwx))
+         py_fwx = SDK.get("MACOSX", "") + "/System/Library/Frameworks/Python.framework/Versions/%s" % ver
+
+         SDK["PYTHON"] = py_fwx + "/Headers"
+         SDK["PYTHONVERSION"] = "python" + ver
+         SDK["PYTHONEXEC"] = "/System/Library/Frameworks/Python.framework/Versions/" + ver + "/bin/python" + ver
+
+         if sys.version[:3] != ver:
+             print("Warning: building with Python %s instead of %s since you targeted a specific Mac OS X version." % (ver, sys.version[:3]))
 
     #elif GetTarget() == 'windows':
     #    SDK["PYTHON"] = os.path.dirname(sysconfig.get_python_inc())
@@ -1932,22 +1980,23 @@ def SdkLocateMSPlatform(strMode = 'default'):
 def SdkLocateMacOSX(osxtarget = None):
     if (GetHost() != "darwin"): return
     if (osxtarget != None):
-        if (os.path.exists("/Developer/SDKs/MacOSX%su.sdk" % osxtarget)):
-            SDK["MACOSX"] = "/Developer/SDKs/MacOSX%su.sdk" % osxtarget
-        elif (os.path.exists("/Developer/SDKs/MacOSX%s.sdk" % osxtarget)):
-            SDK["MACOSX"] = "/Developer/SDKs/MacOSX%s.sdk" % osxtarget
-        elif (os.path.exists("/Developer/SDKs/MacOSX%s.0.sdk" % osxtarget)):
-            SDK["MACOSX"] = "/Developer/SDKs/MacOSX%s.0.sdk" % osxtarget
-        elif (os.path.exists("/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX%s.sdk" % osxtarget)):
-            SDK["MACOSX"] = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX%s.sdk" % osxtarget
+        sdkname = "MacOSX%d.%d" % osxtarget
+        if (os.path.exists("/Developer/SDKs/%su.sdk" % sdkname)):
+            SDK["MACOSX"] = "/Developer/SDKs/%su.sdk" % sdkname
+        elif (os.path.exists("/Developer/SDKs/%s.sdk" % sdkname)):
+            SDK["MACOSX"] = "/Developer/SDKs/%s.sdk" % sdkname
+        elif (os.path.exists("/Developer/SDKs/%s.0.sdk" % sdkname)):
+            SDK["MACOSX"] = "/Developer/SDKs/%s.0.sdk" % sdkname
+        elif (os.path.exists("/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/%s.sdk" % sdkname)):
+            SDK["MACOSX"] = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/%s.sdk" % sdkname
         else:
             handle = os.popen("xcode-select -print-path")
             result = handle.read().strip().rstrip('/')
             handle.close()
-            if (os.path.exists("%s/Platforms/MacOSX.platform/Developer/SDKs/MacOSX%s.sdk" % (result, osxtarget))):
-                SDK["MACOSX"] = "%s/Platforms/MacOSX.platform/Developer/SDKs/MacOSX%s.sdk" % (result, osxtarget)
+            if (os.path.exists("%s/Platforms/MacOSX.platform/Developer/SDKs/%s.sdk" % (result, sdkname))):
+                SDK["MACOSX"] = "%s/Platforms/MacOSX.platform/Developer/SDKs/%s.sdk" % (result, sdkname)
             else:
-                exit("Couldn't find any MacOSX SDK for OSX version %s!" % osxtarget)
+                exit("Couldn't find any MacOSX SDK for OSX version %s!" % sdkname)
     else:
         SDK["MACOSX"] = ""
 
@@ -2370,11 +2419,10 @@ def SetupBuildEnvironment(compiler):
     AddToPathEnv("PYTHONPATH", builtdir)
     AddToPathEnv("PANDA_PRC_DIR", os.path.join(builtdir, "etc"))
     AddToPathEnv("PATH", os.path.join(builtdir, "bin"))
-    if (GetHost() == 'windows'):
-        AddToPathEnv("PATH", os.path.join(builtdir, "plugins"))
+    if GetHost() == 'windows':
+        # extension_native_helpers.py currently expects to find libpandaexpress on sys.path.
         AddToPathEnv("PYTHONPATH", os.path.join(builtdir, "bin"))
-    else:
-        AddToPathEnv("PYTHONPATH", os.path.join(builtdir, "lib"))
+        AddToPathEnv("PATH", os.path.join(builtdir, "plugins"))
 
     # Now for the special (DY)LD_LIBRARY_PATH on Unix-esque systems.
     if GetHost() != 'windows':

+ 12 - 8
panda/metalibs/pandadx9/Sources.pp

@@ -125,7 +125,7 @@ OpenALAudioManager() {
       alcGetError(_device); // clear errors
       _context = alcCreateContext(_device, NULL);
       alc_audio_errcheck("alcCreateContext(_device, NULL)",_device);
-      if (_context!=NULL) {
+      if (_context != NULL) {
         _openal_active = true;
       }
     }
@@ -142,20 +142,24 @@ OpenALAudioManager() {
   } else {
     alcGetError(_device); // clear errors
     alcMakeContextCurrent(_context);
-    alc_audio_errcheck("alcMakeContextCurrent(_context)",_device);
-
+    alc_audio_errcheck("alcMakeContextCurrent(_context)", _device);
 
     // set 3D sound characteristics as they are given in the configrc
     audio_3d_set_doppler_factor(audio_doppler_factor);
     audio_3d_set_distance_factor(audio_distance_factor);
     audio_3d_set_drop_off_factor(audio_drop_off_factor);
-  }
 
-  audio_cat->debug() << "ALC_DEVICE_SPECIFIER:" << alcGetString(_device, ALC_DEVICE_SPECIFIER) << endl;    
-  audio_cat->debug() << "AL_RENDERER:" << alGetString(AL_RENDERER) << endl;
-  audio_cat->debug() << "AL_VENDOR:" << alGetString(AL_VENDOR) << endl;
-  audio_cat->debug() << "AL_VERSION:" << alGetString(AL_VERSION) << endl;
+    if (audio_cat.is_debug()) {
+      audio_cat->debug()
+        << "ALC_DEVICE_SPECIFIER:" << alcGetString(_device, ALC_DEVICE_SPECIFIER) << endl;
+    }
+  }
 
+  if (audio_cat.is_debug()) {
+    audio_cat->debug() << "AL_RENDERER:" << alGetString(AL_RENDERER) << endl;
+    audio_cat->debug() << "AL_VENDOR:" << alGetString(AL_VENDOR) << endl;
+    audio_cat->debug() << "AL_VERSION:" << alGetString(AL_VERSION) << endl;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

+ 2 - 2
panda/src/cocoadisplay/cocoaGraphicsWindow.mm

@@ -159,7 +159,7 @@ begin_frame(FrameMode mode, Thread *current_thread) {
   // Set the drawable.
   if (_properties.get_fullscreen()) {
     // Fullscreen.
-    [cocoagsg->_context setFullScreen];
+    CGLSetFullScreenOnDisplay((CGLContextObj) [cocoagsg->_context CGLContextObj], CGDisplayIDToOpenGLDisplayMask(_display));
   } else {
     // Although not recommended, it is technically possible to
     // use the same context with multiple different-sized windows.
@@ -182,7 +182,7 @@ begin_frame(FrameMode mode, Thread *current_thread) {
 
   // Lock the view for drawing.
   if (!_properties.get_fullscreen()) {
-    nassertr([_view lockFocusIfCanDraw], false);
+    nassertr_always([_view lockFocusIfCanDraw], false);
   }
 
   // Make the context current.

+ 0 - 3
panda/src/collide/collisionFloorMesh.I

@@ -37,7 +37,6 @@
     graphicsWindowInputDevice.h \
     graphicsWindowProc.h \
     graphicsWindowProcCallbackData.I graphicsWindowProcCallbackData.h \
-    lru.h \
     nativeWindowHandle.I nativeWindowHandle.h \
     parasiteBuffer.I parasiteBuffer.h \
     pStatGPUTimer.I pStatGPUTimer.h \
@@ -74,7 +73,6 @@
     graphicsWindowProc.cxx \
     graphicsWindowProcCallbackData.cxx \
     graphicsDevice.cxx \
-    lru.cxx \
     nativeWindowHandle.cxx \
     parasiteBuffer.cxx \
     windowHandle.cxx \
@@ -109,7 +107,6 @@
     graphicsThreadingModel.I graphicsThreadingModel.h \
     graphicsWindowInputDevice.I graphicsWindowInputDevice.h \
     graphicsDevice.I graphicsDevice.h \
-    lru.h \
     nativeWindowHandle.I nativeWindowHandle.h \
     parasiteBuffer.I parasiteBuffer.h \
     pStatGPUTimer.I pStatGPUTimer.h \

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

@@ -301,7 +301,7 @@ ConfigVariableBool allow_incomplete_render
           "the frame render if necessary."));
 
 ConfigVariableInt win_size
-("win-size", "640 480",
+("win-size", "800 600",
  PRC_DESC("This is the default size at which to open a new window.  This "
           "replaces the deprecated win-width and win-height variables."));
 

+ 17 - 9
panda/src/display/get_x11.h

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

+ 2 - 0
panda/src/display/graphicsDevice.I

@@ -2001,9 +2001,11 @@ setup_scene(GraphicsStateGuardian *gsg, DisplayRegionPipelineReader *dr) {
   // to use.  We have to do this here because the ShaderGenerator
   // needs a host window pointer.  Hopefully we'll be able to
   // eliminate that requirement in the future.
+#ifdef HAVE_CG
   if (gsg->get_shader_generator() == NULL) {
     gsg->set_shader_generator(new ShaderGenerator(gsg, window));
   }
+#endif
 
   return scene_setup;
 }

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

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

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

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

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

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

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

@@ -185,6 +185,7 @@ GraphicsStateGuardian(CoordinateSystem internal_coordinate_system,
   _max_3d_texture_dimension = 0;
   _max_2d_texture_array_layers = 0;
   _max_cube_map_dimension = 0;
+  _max_buffer_texture_size = 0;
 
   // Assume we don't support these fairly advanced texture combiner
   // modes.
@@ -195,6 +196,7 @@ GraphicsStateGuardian(CoordinateSystem internal_coordinate_system,
   _supports_3d_texture = false;
   _supports_2d_texture_array = false;
   _supports_cube_map = false;
+  _supports_buffer_texture = false;
   _supports_tex_non_pow2 = false;
   _supports_texture_srgb = false;
   _supports_compressed_texture = false;

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

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

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

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

+ 0 - 1229
panda/src/display/lru.cxx

@@ -1,1229 +0,0 @@
-// Filename: lru.cxx
-// Created by: aignacio (12Dec05)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) Carnegie Mellon University.  All rights reserved.
-//
-// All use of this software is subject to the terms of the revised BSD
-// license.  You should have received a copy of this license along
-// with this source code in a file named "LICENSE."
-//
-////////////////////////////////////////////////////////////////////
-
-//#include "stdafx.h"
-
-#define LRU_UNIT_TEST 0
-
-#include <stdio.h>
-#include <stdlib.h>
-//#include <windows.h>
-
-#include "lru.h"
-#if ENABLE_MUTEX
-#include "mutexHolder.h"
-#endif
-
-
-static const int HIGH_PRIORITY_SCALE = 4;
-static const int LOW_PRIORITY_RANGE = 25;
-
-////////////////////////////////////////////////////////////////////
-//     Function: Lru::Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-Lru::Lru (int maximum_memory, int maximum_pages, int maximum_page_types)
-{
-  if(this) {
-    int  index;
-
-    memset(&this->_m, 0, sizeof (LruVariables));
-
-    this->_m.maximum_memory = maximum_memory;
-    this->_m.maximum_pages  = maximum_pages;
-    this->_m.maximum_page_types = maximum_page_types;
-    this->_m.available_memory = maximum_memory;
-    this->_m.current_frame_identifier = 1;
-    this->_m.weight = 0.20f;
-
-    this->set_maximum_frame_bandwidth_utilization(2000000.0f);
-
-    for(index = 0; index < MAXIMUM_LRU_PAGE_TYPES; index++) {
-      this->_m.page_in_function_array[index] = default_page_in_function;
-      this->_m.page_out_function_array[index] = default_page_out_function;
-    }
-
-    if(maximum_pages > 0) {
-      this -> _m.lru_page_pool = new LruPage * [maximum_pages];
-      this -> _m.lru_page_free_pool = new LruPage * [maximum_pages];
-      for(index = 0; index < maximum_pages; index++) {
-        LruPage  * lru_page;
-
-        lru_page = new LruPage ( );
-        if(lru_page) {
-          lru_page->_m.v.pre_allocated = true;
-          this->_m.lru_page_pool[index] = lru_page;
-        }
-        else {
-// ERROR
-        }
-      }
-    }
-
-    if(maximum_page_types > 0) {
-      this -> _m.page_type_statistics_array =
-        new PageTypeStatistics [maximum_page_types];
-    }
-
-#if ENABLE_MUTEX
-    this -> _m.mutex = new Mutex ("lru");
-#endif
-
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Lru::Destructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-Lru::~Lru ( )
-{
-  int        index;
-  LruPage  * lru_page;
-
-  // free pre-allocated LruPages
-  if(this->_m.maximum_pages > 0) {
-    if(this->_m.lru_page_free_pool) {
-      for(index = 0; index < this->_m.maximum_pages; index++) {
-        lru_page = this->_m.lru_page_pool[index];
-        if(lru_page->_m.v.in_lru) {
-          this->remove_page(lru_page);
-        }
-
-        delete lru_page;
-      }
-
-      delete this -> _m.lru_page_free_pool;
-    }
-    if(this->_m.lru_page_pool) {
-      delete this -> _m.lru_page_pool;
-    }
-  }
-
-  // free dynamically allocated LruPages
-  for(index = 0; index < LPP_TotalPriorities; index++) {
-    LruPage  * next_lru_page;
-
-    lru_page = this->_m.lru_page_array[index];
-    while(lru_page) {
-      next_lru_page = lru_page->_m.next;
-
-      delete  lru_page;
-
-      lru_page = next_lru_page;
-    }
-  }
-
-  if(this->_m.page_type_statistics_array) {
-    delete this -> _m.page_type_statistics_array;
-  }
-
-#if ENABLE_MUTEX
-  if(this->_m.mutex) {
-    delete this -> _m.mutex;
-  }
-#endif
-
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: LruPage::Constructor
-//       Access: Protected
-//  Description: Internal function only.
-//               Call  Lru::allocate_page instead.
-////////////////////////////////////////////////////////////////////
-LruPage::LruPage ( )
-{
-  if(this) {
-    memset(&this->_m, 0, sizeof (LruPageVariables));
-    _m.name = "";   
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: LruPage::Destructor
-//       Access: Protected
-//  Description: Internal function only.
-//               Call  Lru::free_page instead.
-////////////////////////////////////////////////////////////////////
-LruPage::~LruPage ( )
-{
-
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: LruPage::change_priority
-//       Access: Protected
-//  Description:
-////////////////////////////////////////////////////////////////////
-void LruPage::change_priority (int delta)
-{
-  this->_m.priority_change += delta;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Lru::register_lru_page_type
-//       Access: Public
-//  Description: Registers a specific type of page and its
-//               required page in and out functions.
-////////////////////////////////////////////////////////////////////
-bool Lru::register_lru_page_type (int index,
-  LruPageTypeFunction page_in_function,
-  LruPageTypeFunction page_out_function)
-{
-  bool  state;
-
-  state = false;
-  if(index >= 0 && index < MAXIMUM_LRU_PAGE_TYPES) {
-    this->_m.page_in_function_array[index] = page_in_function;
-    this->_m.page_out_function_array[index] = page_out_function;
-    state = true;
-  }
-
-  return state;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Lru::allocate_page
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-LruPage *Lru::allocate_page (int size)
-{
-  LruPage  * lru_page;
-
-  lru_page = 0;
-  if(size <= this->_m.maximum_memory) {
-    if(this->_m.maximum_pages) {
-      if(this->_m.total_lru_pages_in_free_pool > 0) {
-        lru_page =
-          this->_m.lru_page_free_pool [this->_m.total_lru_pages_in_free_pool - 1];
-        this->_m.total_lru_pages_in_free_pool--;
-
-        memset (&lru_page -> _m, 0, sizeof (LruPage::LruPageVariables));
-        lru_page->_m.v.pre_allocated = true;
-      }
-      else {
-        if(this->_m.total_lru_pages_in_pool < this->_m.maximum_pages) {
-          lru_page = this->_m.lru_page_pool[this->_m.total_lru_pages_in_pool];
-          this->_m.total_lru_pages_in_pool++;
-        }
-        else {
-          // out of pre-allocated LruPages so dynamically allocate a page
-          lru_page = new LruPage ( );
-        }
-      }
-    }
-    else {
-      lru_page = new LruPage;
-    }
-    if(lru_page) {
-      lru_page->_m.lru = this;
-      lru_page->_m.size = size;
-      lru_page->_m.first_frame_identifier = this->_m.current_frame_identifier;
-      lru_page->_m.last_frame_identifier = this->_m.current_frame_identifier;
-
-      lru_page->_m.v.allocated = true;
-      lru_page->_m.identifier = this->_m.identifier;
-
-      lru_page->_m.average_frame_utilization = 1.0f;
-
-      this->_m.total_pages++;
-      this->_m.identifier++;
-    }
-    else {
-
-// ERROR: could not allocate LruPage
-
-    }
-  }
-  else {
-
-// ERROR: requested page size is larger than maximum memory size
-
-  }
-
-  return lru_page;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Lru::update_start_update_lru_page
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-void Lru::update_start_update_lru_page (LruPage *lru_page)
-{
-  if(lru_page) {
-    if(this->_m.start_update_lru_page == lru_page) {
-      if(lru_page->_m.next) {
-        this->_m.start_update_lru_page = lru_page->_m.next;
-      }
-      else {
-        if((this->_m.start_priority_index + 1) >= LPP_TotalPriorities) {
-          this->_m.start_priority_index = 0;
-        }
-        else {
-          this->_m.start_priority_index = this->_m.start_priority_index + 1;
-        }
-
-        this->_m.start_update_lru_page = 0;
-      }
-    }
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Lru::free_page
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-void Lru::free_page (LruPage *lru_page)
-{
-  if(this->_m.total_pages > 0) {
-    if(lru_page) {
-      LruMutexHolder(this->_m.mutex);
-
-      this->update_start_update_lru_page(lru_page);
-
-      if(lru_page->_m.v.in_cache) {
-        this->_m.available_memory += lru_page->_m.size;
-      }
-
-      if(lru_page->_m.v.pre_allocated) {
-        if(this->_m.maximum_pages) {
-          lru_page->_m.v.allocated = false;
-          this->_m.lru_page_free_pool [this->_m.total_lru_pages_in_free_pool] =
-            lru_page;
-          this->_m.total_lru_pages_in_free_pool++;
-        }
-        else {
-// ERROR: this case should not happen
-        }
-      }
-      else {
-        delete lru_page;
-      }
-
-      this->_m.total_pages--;
-    }
-  }
-  else {
-
-// ERROR: tried to free a page when 0 pages allocated
-
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Lru::add_page
-//       Access: Public
-//  Description: Adds a page to the LRU based on the given priority.
-////////////////////////////////////////////////////////////////////
-void Lru::add_page (LruPagePriority priority, LruPage *lru_page)
-{
-  if(lru_page) {
-    LruMutexHolder(this->_m.mutex);
-
-    LruPage * first_lru_page;
-
-    lru_page->_m.priority = priority;
-
-    first_lru_page = this->_m.lru_page_array[lru_page->_m.priority];
-    if(first_lru_page) {
-      first_lru_page->_m.previous = lru_page;
-      lru_page->_m.next = first_lru_page;
-    }
-
-    this->_m.lru_page_array[lru_page->_m.priority] = lru_page;
-
-    lru_page->_m.v.in_lru = true;
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Lru::add_cached_page
-//       Access: Public
-//  Description: Adds a page that is already paged in to the LRU
-//               based on the given priority.
-////////////////////////////////////////////////////////////////////
-void Lru::add_cached_page (LruPagePriority priority, LruPage *lru_page)
-{
-  if(lru_page) {
-    LruMutexHolder(this->_m.mutex);
-
-    lru_page->_m.v.in_cache = true;
-
-    if(lru_page->_m.size > this->_m.available_memory) {
-      int  memory_required;
-
-      memory_required = lru_page->_m.size - this->_m.available_memory;
-
-      // unload page(s)
-      this->page_out_lru(memory_required);
-    }
-
-    this->_m.available_memory -= lru_page->_m.size;
-
-    this->add_page(priority, lru_page);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Lru::remove_page
-//       Access: Public
-//  Description: Removes a page from the LRU.
-////////////////////////////////////////////////////////////////////
-void Lru::remove_page (LruPage *lru_page)
-{
-  if(this) {
-    if(this->_m.total_pages > 0) {
-      if(lru_page) {
-        LruMutexHolder(this->_m.mutex);
-
-        this->update_start_update_lru_page(lru_page);
-
-        if(lru_page->_m.previous) {
-          lru_page->_m.previous->_m.next = lru_page->_m.next;
-          if(lru_page->_m.next) {
-            lru_page->_m.next->_m.previous = lru_page->_m.previous;
-          }
-        }
-        else {
-          this->_m.lru_page_array[lru_page->_m.priority] =
-            lru_page->_m.next;
-          if(lru_page->_m.next) {
-            lru_page->_m.next->_m.previous = 0;
-          }
-        }
-
-        lru_page->_m.next = 0;
-        lru_page->_m.previous = 0;
-
-        lru_page->_m.v.in_lru = false;
-      }
-    }
-    else {
-
-// ERROR: tried to remove a page when 0 pages are allocated
-
-    }
-  }
-  else {
-
-// ERROR: Lru == 0, this should not happen
-
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Lru::lock_page
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-void Lru::lock_page (LruPage *lru_page)
-{
-  lru_page->_m.v.lock = true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Lru::unlock_page
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-void Lru::unlock_page (LruPage *lru_page)
-{
-  lru_page->_m.v.lock = false;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Lru::access_page
-//       Access: Public
-//  Description: This must always be called before accessing or
-//               using a page's memory since it pages in the page
-//               if it is currently paged out.
-////////////////////////////////////////////////////////////////////
-void Lru::access_page (LruPage *lru_page)
-{
-  if(lru_page) {
-    if(lru_page->_m.current_frame_identifier
-       == this->_m.current_frame_identifier) {
-      lru_page->_m.current_frame_usage++;
-      this->_m.total_page_all_access_size += lru_page->_m.size;
-    }
-    else {
-      // first update this frame
-      lru_page->_m.last_frame_identifier = lru_page->_m.current_frame_identifier;
-      lru_page->_m.current_frame_identifier = this->_m.current_frame_identifier;
-      lru_page->_m.last_frame_usage = lru_page->_m.current_frame_usage;
-      lru_page->_m.current_frame_usage = 1;
-      lru_page->_m.total_frame_page_faults = 0;
-
-      this->_m.total_page_access_size += lru_page->_m.size;
-    }
-
-    // check if the page is out
-    if(lru_page->_m.v.in_cache == false) {
-      bool  state;
-
-      state = true;
-
-      LruMutexHolder(this->_m.mutex);
-
-      // check memory usage
-      if(lru_page->_m.size > this->_m.available_memory) {
-        int  memory_required;
-
-        memory_required = lru_page->_m.size - this->_m.available_memory;
-
-        // unload page(s)
-        state = this->page_out_lru(memory_required);
-      }
-
-      // load the page in
-      if(state) {
-        // PAGE IN CALLBACK
-        if(this->_m.page_in_function_array[lru_page->_m.v.type](lru_page)) {
-          this->_m.available_memory -= lru_page->_m.size;
-          lru_page->_m.v.in_cache = true;
-
-          // CHANGE THE PAGE PRIORITY FROM LPP_PageOut TO LPP_New
-          this->remove_page(lru_page);
-          this->add_page(LPP_New, lru_page);
-
-          this->_m.total_lifetime_page_ins++;
-        }
-      }
-
-      lru_page->_m.total_frame_page_faults++;
-      lru_page->_m.total_page_faults++;
-    }
-
-    lru_page->_m.total_usage++;
-    lru_page->_m.update_total_usage++;
-
-    this->_m.total_page_access++;
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Lru::set_maximum_frame_bandwidth_utilization
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-void Lru::set_maximum_frame_bandwidth_utilization
-  (PN_stdfloat maximum_frame_bandwidth_utilization)
-{
-  this->_m.maximum_frame_bandwidth_utilization =
-    maximum_frame_bandwidth_utilization;
-
-  this->_m.frame_bandwidth_factor = (PN_stdfloat) LPP_TotalPriorities
-    / this->_m.maximum_frame_bandwidth_utilization;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Lru::begin_frame
-//       Access: Public
-//  Description: This must be called before each frame.
-////////////////////////////////////////////////////////////////////
-void Lru::begin_frame ( )
-{
-  this->_m.current_frame_identifier++;
-
-  this->_m.total_page_ins_last_frame = this->_m.total_page_ins;
-  this->_m.total_page_outs = this->_m.total_page_outs;
-
-  this->_m.total_page_ins = 0;
-  this->_m.total_page_outs = 0;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Lru::update_page_priorities
-//       Access: Public
-//  Description: This updates the priority of a page that has a
-//               change in priority.
-////////////////////////////////////////////////////////////////////
-void Lru::update_page_priorities (void)
-{
-  int index;
-  LruPage *lru_page;
-
-  for(index = 0; index < this->_m.total_lru_page_priority_changes; index++) {
-    int priority;
-
-    lru_page = this->_m.lru_page_priority_change_array[index];
-
-    this->remove_page(lru_page);
-
-    priority = (( int ) lru_page->_m.priority + lru_page->_m.priority_change);
-    if(priority < 0) {
-      priority = 0;
-    }
-    if(priority >= LPP_TotalPriorities) {
-      priority = LPP_TotalPriorities - 1;
-    }
-
-    this->add_page((LruPagePriority) priority, lru_page);
-    lru_page->_m.priority_change = 0;
-  }
-  this->_m.total_lru_page_priority_changes = 0;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Lru::update_lru_page
-//       Access: Public
-//  Description: This updates the page's average utilization.
-//               Priority LPP_New is considered to be average usage
-//               of 1.0 (which means the page is used once per frame
-//               on average).  Priorities < LPP_New are for pages
-//               used more than once per frame and Priorities >
-//               LPP_New are for pages used less than once per frame.
-//               If there was a change in priority, then adds it to
-//               the array of lru pages with changed priorities
-//               which will be updated later.
-////////////////////////////////////////////////////////////////////
-void Lru::update_lru_page (LruPage *lru_page)
-{
-
-#if LRU_UNIT_TEST
-  if(false) {
-    char  string[256];
-
-    sprintf(string, "  UPDATE %d\n", lru_page->_m.identifier);
-    OutputDebugString(string);
-  }
-#endif
-
-  if(lru_page->_m.v.lock == false && lru_page->_m.v.in_cache) {
-    int delta_priority;
-    int lifetime_frames;
-
-    delta_priority = 0;
-
-    lifetime_frames = this->_m.current_frame_identifier -
-      lru_page->_m.first_frame_identifier;
-    if(lifetime_frames >= 1) {
-      if(lru_page->_m.update_frame_identifier) {
-        int target_priority;
-        int integer_update_frames;
-        PN_stdfloat update_frames;
-        PN_stdfloat one_over_update_frames;
-        PN_stdfloat update_average_frame_utilization;
-
-        integer_update_frames = (this->_m.current_frame_identifier -
-          lru_page->_m.update_frame_identifier);
-        if(integer_update_frames > 0) {
-          update_frames = ( PN_stdfloat ) integer_update_frames;
-          one_over_update_frames = 1.0f / update_frames;
-
-          update_average_frame_utilization =
-            (PN_stdfloat) (lru_page->_m.update_total_usage)* one_over_update_frames;
-
-          lru_page->_m.average_frame_utilization =
-            calculate_exponential_moving_average(
-               update_average_frame_utilization, this->_m.weight,
-               lru_page->_m.average_frame_utilization);
-
-          target_priority = lru_page->_m.priority;
-          if(lru_page->_m.average_frame_utilization >= 1.0f) {
-            int integer_average_frame_utilization;
-
-            integer_average_frame_utilization =
-              (int) ((lru_page->_m.average_frame_utilization - 1.0f) *
-              (PN_stdfloat) HIGH_PRIORITY_SCALE);
-            if(integer_average_frame_utilization >= LPP_New) {
-              integer_average_frame_utilization = LPP_New;
-            }
-            integer_average_frame_utilization = LPP_New -
-              integer_average_frame_utilization;
-            target_priority = integer_average_frame_utilization;
-          }
-          else {
-            int integer_average_frame_utilization;
-
-            integer_average_frame_utilization = (int)
-               (lru_page->_m.average_frame_utilization *
-               (PN_stdfloat) LOW_PRIORITY_RANGE);
-            integer_average_frame_utilization = LOW_PRIORITY_RANGE -
-              integer_average_frame_utilization;
-            target_priority = LPP_New + integer_average_frame_utilization;
-          }
-
-          delta_priority = target_priority - lru_page->_m.priority;
-          lru_page->change_priority(delta_priority);
-        }
-      }
-
-      lru_page->_m.update_frame_identifier = this->_m.current_frame_identifier;
-      lru_page->_m.update_total_usage = 0;
-    }
-
-    if(lru_page->_m.priority_change) {
-      if(this->_m.total_lru_page_priority_changes
-         < FRAME_MAXIMUM_PRIORITY_CHANGES)
-      {
-        this->_m.lru_page_priority_change_array
-          [this->_m.total_lru_page_priority_changes] = lru_page;
-        this->_m.total_lru_page_priority_changes++;
-      }
-    }
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Lru::update_lru_page_old
-//       Access: Public
-//  Description: This updates the page's average utilization and
-//               adds it to the array of pages with changed
-//               priorities if there was a change in priority.
-//               Old method.
-////////////////////////////////////////////////////////////////////
-void Lru::update_lru_page_old (LruPage *lru_page)
-{
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Lru::update_entire_lru
-//       Access: Public
-//  Description: This updates all the pages in the Lru.
-//               Lru::partial_lru_update should be called instead
-//               due to performance reasons.
-////////////////////////////////////////////////////////////////////
-void Lru::update_entire_lru ( )
-{
-  if(this->_m.total_pages > 0) {
-    int index;
-    LruPage *lru_page;
-
-    LruMutexHolder(this->_m.mutex);
-
-    for(index = 0; index < LPP_TotalPriorities; index++) {
-
-      LruPage  * next_lru_page;
-
-      lru_page = this->_m.lru_page_array[index];
-      while(lru_page) {
-        next_lru_page = lru_page->_m.next;
-
-        this->update_lru_page(lru_page);
-
-        lru_page = next_lru_page;
-      }
-    }
-
-    this->update_page_priorities( );
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Lru::partial_lru_update
-//       Access: Public
-//  Description: This only updates a number of pages up to the
-//               specified maximum_updates.
-////////////////////////////////////////////////////////////////////
-void Lru::partial_lru_update (int maximum_updates)
-{
-  int total_page_updates;
-
-  if (maximum_updates <= 0) {
-    // enforce a minimum number of updates
-    maximum_updates = 1;
-  }
-
-  total_page_updates = 0;
-  if(this->_m.total_pages > 0) {
-    int index;
-    int start_priority;
-    LruPage *lru_page;
-
-    LruMutexHolder(this->_m.mutex);
-
-    start_priority = this->_m.start_priority_index;
-
-    {
-      for(index = start_priority;  index < LPP_TotalPriorities; index++) {
-
-        LruPage *next_lru_page;
-
-        if(index == start_priority) {
-          if(this->_m.start_update_lru_page) {
-            lru_page = this->_m.start_update_lru_page;
-          }
-          else {
-            lru_page = this->_m.lru_page_array[index];
-          }
-        }
-        else {
-          lru_page = this->_m.lru_page_array[index];
-        }
-        while(lru_page) {
-          next_lru_page = lru_page->_m.next;
-
-          this->update_lru_page(lru_page);
-
-          total_page_updates++;
-          if(total_page_updates >= maximum_updates) {
-            if(next_lru_page) {
-              this->_m.start_priority_index = index;
-              this->_m.start_update_lru_page = next_lru_page;
-            }
-            else {
-              if((index + 1) >= LPP_TotalPriorities) {
-                this->_m.start_priority_index = 0;
-              }
-              else {
-                this->_m.start_priority_index = index + 1;
-              }
-
-              this->_m.start_update_lru_page = 0;
-            }
-
-            break;
-          }
-
-          lru_page = next_lru_page;
-        }
-
-        if(total_page_updates >= maximum_updates) {
-          break;
-        }
-      }
-    }
-
-    if(total_page_updates < maximum_updates) {
-      for(index = 0;  index <= start_priority;  index++) {
-        LruPage *next_lru_page;
-
-        lru_page = this->_m.lru_page_array[index];
-        while(lru_page) {
-          next_lru_page = lru_page->_m.next;
-
-          this->update_lru_page(lru_page);
-
-          total_page_updates++;
-          if(total_page_updates >= maximum_updates) {
-            if(next_lru_page) {
-              this->_m.start_priority_index = index;
-              this->_m.start_update_lru_page = next_lru_page;
-            }
-            else {
-              if((index + 1) >= LPP_TotalPriorities) {
-                this->_m.start_priority_index = 0;
-              }
-              else {
-                this->_m.start_priority_index = index + 1;
-              }
-
-              this->_m.start_update_lru_page = 0;
-            }
-
-            break;
-          }
-
-          lru_page = next_lru_page;
-        }
-
-        if(total_page_updates >= maximum_updates) {
-          break;
-        }
-      }
-    }
-
-    if(total_page_updates < maximum_updates) {
-      this->_m.start_priority_index  = 0;
-      this->_m.start_update_lru_page = 0;
-    }
-
-    this->update_page_priorities( );
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Lru::unlock_all_pages
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-void Lru::unlock_all_pages (void)
-{
-  if(this->_m.total_pages > 0) {
-    int  index;
-
-    for(index = 0;  index < LPP_TotalPriorities; index++) {
-      LruPage *lru_page;
-      LruPage *next_lru_page;
-
-      lru_page = this->_m.lru_page_array[index];
-      while(lru_page) {
-        next_lru_page = lru_page->_m.next;
-
-        lru_page->_m.v.lock = false;
-
-        lru_page = next_lru_page;
-      }
-    }
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Lru::page_out_lru
-//       Access: Public
-//  Description: Pages out the lowest priority pages until the
-//               memory_required is satisfied.  This will unlock
-//               all pages if needed.
-////////////////////////////////////////////////////////////////////
-bool Lru::page_out_lru (int memory_required)
-{
-  bool state;
-  int attempts;
-
-  state = false;
-  attempts = 0;
-  if(this->_m.total_pages > 0) {
-    LruMutexHolder(this->_m.mutex);
-
-    do {
-      int index;
-      int minimum_frame_identifier;
-      
-      minimum_frame_identifier = this->_m.current_frame_identifier - 1;
-
-      // page out lower priority pages first
-      for(index = LPP_PageOut - 1; index >= 0; index--) {
-        LruPage *lru_page;
-        LruPage *next_lru_page;
-
-        lru_page = this->_m.lru_page_array[index];
-        while(lru_page) {
-          next_lru_page = lru_page->_m.next;
-
-          if(attempts == 0 && (lru_page->_m.current_frame_identifier >= minimum_frame_identifier)) {
-            // avoid swapping out pages used in the current and last frame on the first attempt
-          }
-          else {
-            if(lru_page->_m.v.lock == false && lru_page->_m.v.in_cache) {
-              memory_required -= lru_page->_m.size;
-              this->_m.available_memory += lru_page->_m.size;
-              lru_page->_m.v.in_cache = false;
-
-              // PAGE OUT CALLBACK
-              this->_m.page_out_function_array[lru_page->_m.v.type](lru_page);
-              this->_m.total_lifetime_page_outs++;
-
-              // MOVE THE PAGE TO THE LPP_PageOut PRIORITY
-              this->remove_page(lru_page);
-              this->add_page(LPP_PageOut, lru_page);
-
-              if(memory_required <= 0) {
-                break;
-              }
-            }
-          }
-          
-          lru_page = next_lru_page;
-        }
-
-        if(memory_required <= 0) {
-          break;
-        }
-      }
-
-      if(memory_required > 0) {
-        state = false;
-      }
-      else {
-        state = true;
-      }
-
-      attempts++;
-    } while(state == false && attempts < 2);
-  }
-
-  return state;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Lru::count_priority_level_pages
-//       Access: Public
-//  Description: Debug function. Counts the number of pages for each
-//               priority level.
-////////////////////////////////////////////////////////////////////
-void Lru::count_priority_level_pages (void)
-{
-  int  index;
-
-  LruMutexHolder(this->_m.mutex);
-
-  for(index = 0; index < LPP_TotalPriorities; index++) {
-    int total_pages;
-    LruPage *lru_page;
-    LruPage *next_lru_page;
-
-    total_pages = 0;
-    lru_page = this->_m.lru_page_array[index];
-    while(lru_page) {
-      next_lru_page = lru_page->_m.next;
-
-      total_pages++;
-
-      lru_page = next_lru_page;
-    }
-
-    this->_m.lru_page_count_array[index] = total_pages;
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Lru::calculate_lru_statistics
-//       Access: Public
-//  Description: Debug function.
-////////////////////////////////////////////////////////////////////
-void Lru::calculate_lru_statistics (void)
-{
-  LruMutexHolder(this->_m.mutex);
-
-  if(this->_m.maximum_page_types > 0) {
-    int  index;
-
-    memset(this->_m.page_type_statistics_array, 0,
-           sizeof (PageTypeStatistics) * this->_m.maximum_page_types);
-    for(index = 0;  index < LPP_TotalPriorities;  index++) {
-      LruPage *lru_page;
-      LruPage *next_lru_page;
-      PageTypeStatistics *page_type_statistics;
-
-      lru_page = this->_m.lru_page_array[index];
-      while(lru_page) {
-        int  type;
-
-        next_lru_page = lru_page->_m.next;
-
-        type = lru_page->_m.v.type;
-        page_type_statistics = &this->_m.page_type_statistics_array[type];
-        page_type_statistics->total_pages++;
-
-        if(lru_page->_m.v.in_cache) {
-          page_type_statistics->total_pages_in++;
-          page_type_statistics->total_memory_in += lru_page->_m.size;
-        }
-        else {
-          page_type_statistics->total_pages_out++;
-          page_type_statistics->total_memory_out += lru_page->_m.size;
-        }
-
-        lru_page = next_lru_page;
-      }
-    }
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: calculate_exponential_moving_average
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-PN_stdfloat calculate_exponential_moving_average(PN_stdfloat value,
-  PN_stdfloat weight, PN_stdfloat average)
-{
-  return ((value - average) * weight) + average;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: default_page_in_function
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-bool default_page_in_function(LruPage *lru_page)
-{
-
-#if LRU_UNIT_TEST
-  char  string[256];
-
-  sprintf(string, "  PAGE IN %d\n", lru_page->_m.identifier);
-  OutputDebugString(string);
-#endif
-
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: default_page_out_function
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-bool default_page_out_function(LruPage *lru_page)
-{
-
-#if LRU_UNIT_TEST
-  char  string[256];
-
-  sprintf(string, "  PAGE OUT %d\n", lru_page->_m.identifier);
-  OutputDebugString(string);
-#endif
-
-  return true;
-}
-
-#if LRU_UNIT_TEST
-
-////////////////////////////////////////////////////////////////////
-//     Function: test_ema
-//       Access:
-//  Description: Unit test function for ema.
-////////////////////////////////////////////////////////////////////
-void test_ema(void)
-{
-  int    index;
-  PN_stdfloat  usage;
-  PN_stdfloat  weight;
-  PN_stdfloat  average;
-
-  weight  = 0.2;
-  average = 1.0f;
-  for(index = 0; index < 50; index++) {
-    if(index < 25) {
-      usage = (PN_stdfloat) (index & 0x01);
-    }
-    else {
-      usage = 0.0f;
-    }
-    average =
-      calculate_exponential_moving_average(usage, weight, average);
-
-    char  string[256];
-    sprintf(string, "%d  %f\n", index, average);
-    OutputDebugString(string);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: test_lru
-//       Access:
-//  Description: Unit test function for Lru.
-////////////////////////////////////////////////////////////////////
-void test_lru(void)
-{
-  int maximum_memory;
-  int maximum_pages;
-  int maximum_page_types;
-  Lru *lru;
-
-  test_ema( );
-
-  maximum_memory = 3000000;
-  maximum_pages = 3;
-  maximum_page_types = 4;
-  lru = new Lru (maximum_memory, maximum_pages, maximum_page_types);
-  if(lru) {
-    lru->_m.minimum_memory = 1000000;
-
-    LruPage *lru_page_0;
-    LruPage *lru_page_1;
-    LruPage *lru_page_2;
-    LruPage *lru_page_3;
-    LruPage *lru_page_4;
-    LruPage *lru_page_5;
-
-    lru_page_0 = lru->allocate_page(1000000);
-    if(lru_page_0) {
-      lru->add_page(LPP_PageOut, lru_page_0);
-    }
-
-    lru_page_1 = lru->allocate_page(1000000);
-    if(lru_page_1) {
-      lru->add_page(LPP_PageOut, lru_page_1);
-    }
-
-    lru_page_2 = lru->allocate_page(1000000);
-    if(lru_page_2) {
-      lru->add_page(LPP_PageOut, lru_page_2);
-    }
-
-    lru_page_3 = lru->allocate_page(1000000);
-    if(lru_page_3) {
-      lru->add_page(LPP_PageOut, lru_page_3);
-    }
-
-    lru_page_4 = lru->allocate_page(1000000);
-    if(lru_page_4) {
-      lru->add_page(LPP_PageOut, lru_page_4);
-    }
-
-    lru_page_5 = lru->allocate_page(1000000);
-    if(lru_page_5) {
-      lru->add_page(LPP_PageOut, lru_page_5);
-    }
-
-    int index;
-    int total_frames;
-
-    total_frames = 300;
-    for(index = 0;  index < total_frames;  index++) {
-      char  string[256];
-
-      sprintf(string, "FRAME %d\n", index);
-      OutputDebugString(string);
-
-      lru->begin_frame( );
-
-      if(index <= 5) {
-        lru->access_page(lru_page_0);
-      }
-
-      lru->access_page(lru_page_1);
-      lru->access_page(lru_page_1);
-
-      if(index & 0x01) {
-        lru->access_page(lru_page_2);
-      }
-
-      if((index % 10) == 0) {
-        lru->access_page(lru_page_3);
-      }
-
-      if(index >= 100) {
-        lru->access_page(lru_page_4);
-      }
-
-      if(index >= 200) {
-        lru->access_page(lru_page_5);
-      }
-
-      if(false) {
-        lru->update_entire_lru( );
-      }
-      else {
-        int  maximum_updates;
-
-        maximum_updates = 3;
-        lru->partial_lru_update(maximum_updates);
-      }
-    }
-
-    if(!true) {
-      lru->remove_page(lru_page_2);
-      lru->free_page(lru_page_2);
-
-      lru->remove_page(lru_page_3);
-      lru->free_page(lru_page_3);
-
-      lru->remove_page(lru_page_1);
-      lru->free_page(lru_page_1);
-    }
-
-    delete lru;
-  }
-}
-
-#endif

+ 0 - 269
panda/src/display/lru.h

@@ -1,269 +0,0 @@
-// Filename: lru.h
-// Created by: aignacio (12Dec05)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) Carnegie Mellon University.  All rights reserved.
-//
-// All use of this software is subject to the terms of the revised BSD
-// license.  You should have received a copy of this license along
-// with this source code in a file named "LICENSE."
-//
-////////////////////////////////////////////////////////////////////
-
-#ifndef LRU_H
-#define LRU_H
-
-#define ENABLE_MUTEX 1
-
-#if ENABLE_MUTEX
-#include "lightMutex.h"
-#include "lightMutexHolder.h"
-#define LruMutexHolder(mutex) MutexHolder(mutex)
-#else
-#define LruMutexHolder(mutex)
-#endif
-
-
-static const int MAXIMUM_LRU_PAGE_TYPES = 8;
-static const int FRAME_MAXIMUM_PRIORITY_CHANGES = 256;
-
-
-class Lru;
-class LruPage;
-
-enum LruPagePriority
-{
-  LPP_Highest = 0,
-  LPP_High = 10,
-  LPP_New = 20,
-  LPP_Normal = 25,
-  LPP_Intermediate = 30,
-  LPP_Low = 40,
-  LPP_TotalPriorities = 50,
-
-  LPP_PageOut = LPP_TotalPriorities - 1
-};
-
-typedef union _LruPageType
-{
-  void *pointer;
-
-}
-LruPageType;
-
-typedef struct
-{
-  int total_pages;
-  int total_pages_in;
-  int total_pages_out;
-  int total_memory_in;
-  int total_memory_out;
-}
-PageTypeStatistics;
-
-typedef bool (*LruPageTypeFunction) (LruPage *lru_page);
-
-class EXPCL_PANDA_DISPLAY LruPage
-{
-
-protected:
-
-  LruPage ( );
-  ~LruPage ( );
-  void change_priority (int delta);
-
-public:
-
-  typedef struct _LruPageVariables
-  {
-    LruPageType lru_page_type;  // pointer to memory type
-
-    int size;
-    LruPagePriority priority;
-    int priority_change;
-
-    struct
-    {
-      unsigned int type : 8;
-      unsigned int lock : 1;
-      unsigned int in_cache : 1;
-      unsigned int in_memory : 1;
-      unsigned int on_disk : 1;
-      unsigned int pre_allocated : 1;
-      unsigned int allocated : 1;
-      unsigned int in_lru : 1;
-    } v;
-
-    int first_frame_identifier;   // creation time
-    int last_frame_identifier;    // previous time page was used
-    int current_frame_identifier;
-    int update_frame_identifier;
-
-    int current_frame_usage;
-    int last_frame_usage;
-
-    int total_frame_page_faults;
-    int total_page_faults;
-
-    int total_usage;
-    int update_total_usage;
-
-    int identifier;
-
-    PN_stdfloat average_frame_utilization;
-
-    LruPage *previous;
-    LruPage *next;
-    Lru *lru;
-    
-    string name;
-  }
-  LruPageVariables;
-
-  LruPageVariables _m;
-
-  friend class Lru;
-};
-
-////////////////////////////////////////////////////////////////////
-//       Class : Lru
-// Description : Least Recently Used algorithm implementation:
-// In the Lru, each "memory page" has an associated class LruPage.
-// The Lru has a range of priorities from LPP_Highest to
-// LPP_PagedOut. Each priority has a doubly linked list of LruPages.
-// The algorithim uses an adaptive method based on the average
-// utilization of each page per frame (or time slice). The
-// average utilization is calculated with an exponetial moving
-// average. This is superior to a standard average since a standard
-// average becomes less and less adaptive the longer a page exists.
-// The average utilization is used to set the priority of each page.
-// A higher average utilization automatically raises the priority
-// of a page and a lower average utilization automatically lowers
-// the priority of a page. Therefore, pages with a higher average
-// utilization have a higher chance of being kept in memory or
-// cached and pages with a lower average utilization have a higher
-// chance of being paged out.  When a page is paged in and there
-// is not enough memory available, then the lowest priority pages
-// will be paged out first until there is enough memory available.
-////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA_DISPLAY Lru
-{
-public:
-
-  Lru (int maximum_memory, int maximum_pages, int maximum_page_types);
-  ~Lru ( );
-
-  bool register_lru_page_type (int index, LruPageTypeFunction page_in_function, LruPageTypeFunction page_out_function);
-
-  LruPage *allocate_page (int size);
-  void update_start_update_lru_page (LruPage *lru_page);
-
-  void free_page (LruPage *lru_page);
-
-  void add_page (LruPagePriority priority, LruPage *lru_page);
-  void add_cached_page (LruPagePriority priority, LruPage *lru_page);
-  void remove_page (LruPage *lru_page);
-
-  void lock_page (LruPage *lru_page);
-  void unlock_page (LruPage *lru_page);
-
-  void access_page (LruPage *lru_page);
-
-  void set_maximum_frame_bandwidth_utilization (PN_stdfloat maximum_frame_bandwidth_utilization);
-
-  void begin_frame ( );
-
-  void update_entire_lru ( );
-  void partial_lru_update (int maximum_updates);
-
-  // set maximum number of page updates per frame
-  // pause/resume updates/current_frame_identifier
-
-  void unlock_all_pages (void);
-
-  void count_priority_level_pages (void);
-
-  void calculate_lru_statistics (void);
-
-  bool page_out_lru (int memory_required);
-
-private:
-  void update_page_priorities (void);
-  void update_lru_page (LruPage *lru_page);
-  void update_lru_page_old (LruPage *lru_page);
-
-public:
-  typedef struct _LruVariables
-  {
-    // LruPagePriority lists
-    LruPage *lru_page_array [LPP_TotalPriorities];
-
-    int total_pages;
-    int available_memory;
-    int current_frame_identifier;
-
-    int maximum_memory;
-    int minimum_memory; // target amount of memory to keep free if possible
-    int maximum_page_types;
-
-    int total_lifetime_page_ins;
-    int total_lifetime_page_outs;
-
-    int total_page_ins_last_frame;
-    int total_page_outs_last_frame;
-
-    int total_page_ins;
-    int total_page_outs;
-
-    int total_page_access;
-    double total_page_access_size;
-    double total_page_all_access_size;
-
-    int start_priority_index;
-    LruPage *start_update_lru_page;
-
-    int identifier; // the number of pages created during the lifetime of the LRU
-
-    PN_stdfloat weight; // used for exponential moving average
-    PN_stdfloat maximum_frame_bandwidth_utilization;
-
-    PN_stdfloat frame_bandwidth_factor;
-
-    LruPageTypeFunction page_in_function_array [MAXIMUM_LRU_PAGE_TYPES];
-    LruPageTypeFunction page_out_function_array [MAXIMUM_LRU_PAGE_TYPES];
-
-    int total_lru_page_priority_changes;
-    LruPage *lru_page_priority_change_array [FRAME_MAXIMUM_PRIORITY_CHANGES];
-
-    int maximum_pages;
-    int total_lru_pages_in_pool;
-    int total_lru_pages_in_free_pool;
-    LruPage **lru_page_pool;
-    LruPage **lru_page_free_pool;
-
-    int lru_page_count_array [LPP_TotalPriorities];
-    PageTypeStatistics *page_type_statistics_array;
-
-    void *context;  // user specified data
-
-#if ENABLE_MUTEX
-    Mutex *mutex;
-#endif
-  }
-  LruVariables;
-
-  LruVariables _m;
-
-  friend class LruPage;
-};
-
-PN_stdfloat calculate_exponential_moving_average (PN_stdfloat value, PN_stdfloat weight, PN_stdfloat average);
-bool default_page_in_function (LruPage *lru_page);
-bool default_page_out_function (LruPage *lru_page);
-
-void test_ema (void);
-void test_lru (void);
-
-#endif

+ 0 - 1
panda/src/display/p3display_composite2.cxx

@@ -5,7 +5,6 @@
 #include "graphicsWindowProc.cxx"
 #include "graphicsWindowProcCallbackData.cxx"
 #include "graphicsWindowInputDevice.cxx"
-#include "lru.cxx"
 #include "nativeWindowHandle.cxx"
 #include "parasiteBuffer.cxx"
 #include "standardMunger.cxx"

+ 13 - 0
panda/src/display/standardMunger.I

@@ -23,3 +23,16 @@ INLINE GraphicsStateGuardian *StandardMunger::
 get_gsg() const {
   return (GraphicsStateGuardian *)GeomMunger::get_gsg();
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: StandardMunger::get_render_mode
+//       Access: Protected
+//  Description: Returns the render mode active on this munger.
+//               Intended for derived classes that may have to munge
+//               differently depending on render mode.
+////////////////////////////////////////////////////////////////////
+INLINE RenderModeAttrib::Mode StandardMunger::
+get_render_mode() const {
+  return (_render_mode != NULL) ? _render_mode->get_mode()
+                                : RenderModeAttrib::M_filled;
+}

+ 2 - 0
panda/src/display/standardMunger.cxx

@@ -365,6 +365,7 @@ munge_state_impl(const RenderState *state) {
     munged_state = munged_state->remove_attrib(ColorScaleAttrib::get_class_slot());
   }
 
+#ifdef HAVE_CG
   if (_auto_shader) {
     CPT(RenderState) shader_state = munged_state->get_auto_shader_state();
     ShaderGenerator *shader_generator = get_gsg()->get_shader_generator();
@@ -379,6 +380,7 @@ munge_state_impl(const RenderState *state) {
     }
     munged_state = munged_state->set_attrib(shader_state->_generated_shader);
   }
+#endif
 
   return munged_state;
 }

+ 2 - 0
panda/src/display/standardMunger.h

@@ -49,6 +49,8 @@ protected:
   virtual int geom_compare_to_impl(const GeomMunger *other) const;
   virtual CPT(RenderState) munge_state_impl(const RenderState *state);
 
+  INLINE RenderModeAttrib::Mode get_render_mode() const;
+
 private:
   int _num_components;
   NumericType _numeric_type;

+ 1 - 0
panda/src/display/subprocessWindowBuffer.cxx

@@ -16,6 +16,7 @@
 #include <sys/mman.h>
 #include <fcntl.h>
 #include <string.h>
+#include <unistd.h>
 
 #include <iostream>
 using namespace std;

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

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

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

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

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

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

+ 0 - 2
panda/src/distort/oSphereLens.I

@@ -32,8 +32,6 @@
 #include "fog.h"
 #include "pointerToArray.h"
 
-#include "lru.h"
-
 #include "vertexElementArray.h"
 #include "dxShaderContext9.h"
 

+ 0 - 2
panda/src/dxgsg9/dxIndexBufferContext9.I

@@ -19,8 +19,6 @@
 #include "texture.h"
 #include "textureContext.h"
 
-#include "lru.h"
-
 ////////////////////////////////////////////////////////////////////
 //       Class : DXTextureContext9
 // Description :

+ 11 - 5
panda/src/dxgsg9/dxVertexBufferContext9.I

@@ -2216,7 +2216,7 @@ check_for_polysets(EggGroup *egg_group, bool &all_polysets, bool &any_hidden) {
 //               transform, just returns it.
 ////////////////////////////////////////////////////////////////////
 PT(GeomVertexData) EggLoader::
-make_vertex_data(const EggRenderState *render_state, 
+make_vertex_data(const EggRenderState *render_state,
                  EggVertexPool *vertex_pool, EggNode *primitive_home,
                  const LMatrix4d &transform, TransformBlendTable *blend_table,
                  bool is_dynamic, CharacterMaker *character_maker,
@@ -2231,7 +2231,7 @@ make_vertex_data(const EggRenderState *render_state,
   if (di != _vertex_pool_data.end()) {
     return (*di).second;
   }
-  
+
   PT(GeomVertexArrayFormat) array_format = new GeomVertexArrayFormat;
   array_format->add_column
     (InternalName::get_vertex(), vertex_pool->get_num_dimensions(),
@@ -2244,9 +2244,15 @@ make_vertex_data(const EggRenderState *render_state,
   }
 
   if (!ignore_color) {
-    array_format->add_column
-      (InternalName::get_color(), 1, 
-       Geom::NT_packed_dabc, Geom::C_color);
+    // Let's not use Direct3D-style colors on platforms where we only
+    // have OpenGL anyway.
+#ifdef _WIN32
+    array_format->add_column(InternalName::get_color(), 1,
+                             Geom::NT_packed_dabc, Geom::C_color);
+#else
+    array_format->add_column(InternalName::get_color(), 4,
+                             Geom::NT_uint8, Geom::C_color);
+#endif
   }
 
   vector_string uv_names, uvw_names, tbn_names;

+ 1 - 0
panda/src/egg2pg/eggSaver.I

@@ -21,6 +21,7 @@ forcetype OFileStream
 forcetype FileStream
 forcetype IDecryptStream
 forcetype OEncryptStream
+forcetype LineStream
 
 forcetype ofstream
 forcetype ifstream

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

@@ -25,8 +25,9 @@
 #include "configVariableList.h"
 #include "configVariableFilename.h"
 
-// Include this so interrogate can find it.
+// Include these so interrogate can find them.
 #include "executionEnvironment.h"
+#include "lineStream.h"
 
 #ifdef ANDROID
 #include <jni.h>

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

@@ -565,7 +565,7 @@ make_directory_full(const Filename &filename) {
 ////////////////////////////////////////////////////////////////////
 PT(VirtualFile) VirtualFileSystem::
 get_file(const Filename &filename, bool status_only) const {
-  int open_flags = status_only ? 0 : OF_status_only;
+  int open_flags = status_only ? OF_status_only : 0;
   ((VirtualFileSystem *)this)->_lock.acquire();
   PT(VirtualFile) result = do_get_file(filename, open_flags);
   ((VirtualFileSystem *)this)->_lock.release();

+ 7 - 0
panda/src/express/windowsRegistry.cxx

@@ -113,6 +113,13 @@ typedef char GLchar;
 #define GL_R32F GL_R32F_EXT
 #define GL_RG32F GL_RG32F_EXT
 #define GL_RGB8 GL_RGB8_OES
+#define GL_TEXTURE_COMPARE_FUNC_ARB GL_TEXTURE_COMPARE_FUNC_EXT
+#define GL_TEXTURE_COMPARE_MODE_ARB GL_TEXTURE_COMPARE_MODE_EXT
+#define GL_COMPARE_R_TO_TEXTURE_ARB GL_COMPARE_REF_TO_TEXTURE_EXT
+#define GL_SAMPLER_2D_SHADOW GL_SAMPLER_2D_SHADOW_EXT
+#define GL_MAX_DRAW_BUFFERS GL_MAX_DRAW_BUFFERS_NV
+#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE
+#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE
 
 #undef SUPPORT_IMMEDIATE_MODE
 #define APIENTRY

+ 1 - 0
panda/src/glesgsg/glesgsg.h

@@ -118,6 +118,7 @@
 #define GL_ALPHA8 GL_ALPHA8_EXT
 #define GL_LUMINANCE8 GL_LUMINANCE8_EXT
 #define GL_LUMINANCE8_ALPHA8 GL_LUMINANCE8_ALPHA8_EXT
+#define GL_MAX_VERTEX_UNITS_ARB GL_MAX_VERTEX_UNITS_OES
 
 #undef SUPPORT_IMMEDIATE_MODE
 #define APIENTRY

+ 4 - 3
panda/src/glesgsg/panda_esglext.h

@@ -1,7 +1,7 @@
 #ifndef __panda_esglext_h_
 #define __panda_esglext_h_
 
-/* $Revision$ on $Date$ */
+/* $Revision: 20798 $ on $Date:: 2013-03-07 01:19:34 -0800 #$ */
 
 #ifdef __cplusplus
 extern "C" {
@@ -1055,10 +1055,10 @@ typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) (GLenum
 #ifndef GL_EXT_multi_draw_arrays
 #define GL_EXT_multi_draw_arrays 1
 #ifdef GL_GLEXT_PROTOTYPES
-GL_API void GL_APIENTRY glMultiDrawArraysEXT (GLenum, GLint *, GLsizei *, GLsizei);
+GL_API void GL_APIENTRY glMultiDrawArraysEXT (GLenum, const GLint *, const GLsizei *, GLsizei);
 GL_API void GL_APIENTRY glMultiDrawElementsEXT (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei);
 #endif /* GL_GLEXT_PROTOTYPES */
-typedef void (GL_APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount);
+typedef void (GL_APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);
 typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount);
 #endif
 
@@ -1275,3 +1275,4 @@ typedef void (GL_APIENTRYP PFNGLENDTILINGQCOMPROC) (GLbitfield preserveMask);
 #endif
 
 #endif /* __glext_h_ */
+

+ 121 - 13
panda/src/glstuff/glCgShaderContext_src.I

@@ -87,6 +87,46 @@ munge_format_impl(const GeomVertexFormat *orig,
   CLP(GraphicsStateGuardian) *glgsg;
   DCAST_INTO_R(glgsg, get_gsg(), NULL);
 
+#ifndef OPENGLES
+  // OpenGL ES 1 does, but regular OpenGL doesn't support GL_BYTE vertices
+  // and texture coordinates.
+  const GeomVertexColumn *vertex_type = orig->get_vertex_column();
+  if (vertex_type != (GeomVertexColumn *)NULL &&
+      (vertex_type->get_numeric_type() == NT_int8 ||
+       vertex_type->get_numeric_type() == NT_uint8)) {
+    int vertex_array = orig->get_array_with(InternalName::get_vertex());
+
+    PT(GeomVertexArrayFormat) new_array_format = new_format->modify_array(vertex_array);
+
+    // Replace the existing vertex format with the new format.
+    new_array_format->add_column
+      (InternalName::get_vertex(), 3, NT_int16,
+       C_point, vertex_type->get_start(), vertex_type->get_column_alignment());
+  }
+
+  // Convert packed formats that OpenGL may not understand.
+  for (int i = 0; i < orig->get_num_columns(); ++i) {
+    const GeomVertexColumn *column = orig->get_column(i);
+    int array = orig->get_array_with(column->get_name());
+
+    if (column->get_numeric_type() == NT_packed_dabc &&
+        !glgsg->_supports_packed_dabc) {
+      // Unpack the packed ARGB color into its four byte components.
+      PT(GeomVertexArrayFormat) array_format = new_format->modify_array(array);
+      array_format->add_column(column->get_name(), 4, NT_uint8, C_color,
+                               column->get_start(), column->get_column_alignment());
+
+    } else if (column->get_numeric_type() == NT_packed_ufloat &&
+               !glgsg->_supports_packed_ufloat) {
+      // Unpack to three 32-bit floats.  (In future, should try 16-bit float)
+      PT(GeomVertexArrayFormat) array_format = new_format->modify_array(array);
+      array_format->add_column(column->get_name(), 3, NT_float32,
+                               column->get_contents(), column->get_start(),
+                               column->get_column_alignment());
+    }
+  }
+#endif  // !OPENGLES
+
   const GeomVertexColumn *color_type = orig->get_color_column();
   if (color_type != (GeomVertexColumn *)NULL &&
       color_type->get_numeric_type() == NT_packed_dabc &&
@@ -99,8 +139,8 @@ munge_format_impl(const GeomVertexFormat *orig,
 
     // Replace the existing color format with the new format.
     new_array_format->add_column
-      (InternalName::get_color(), 4, NT_uint8,
-       C_color, color_type->get_start(), color_type->get_column_alignment());
+      (InternalName::get_color(), 4, NT_uint8, C_color,
+       color_type->get_start(), color_type->get_column_alignment());
   }
 
   if (animation.get_animation_type() == AT_hardware) {
@@ -237,22 +277,46 @@ premunge_format_impl(const GeomVertexFormat *orig) {
   CLP(GraphicsStateGuardian) *glgsg;
   DCAST_INTO_R(glgsg, get_gsg(), NULL);
 
-  const GeomVertexColumn *color_type = orig->get_color_column();
-  if (color_type != (GeomVertexColumn *)NULL &&
-      color_type->get_numeric_type() == NT_packed_dabc &&
-      !glgsg->_supports_packed_dabc) {
-    // We need to convert the color format; OpenGL doesn't support the
-    // byte order of DirectX's packed ARGB format.
-    int color_array = orig->get_array_with(InternalName::get_color());
+#ifndef OPENGLES
+  // OpenGL ES 1 does, but regular OpenGL doesn't support GL_BYTE vertices
+  // and texture coordinates.
+  const GeomVertexColumn *vertex_type = orig->get_vertex_column();
+  if (vertex_type != (GeomVertexColumn *)NULL &&
+      (vertex_type->get_numeric_type() == NT_int8 ||
+       vertex_type->get_numeric_type() == NT_uint8)) {
+    int vertex_array = orig->get_array_with(InternalName::get_vertex());
 
-    PT(GeomVertexArrayFormat) new_array_format = new_format->modify_array(color_array);
+    PT(GeomVertexArrayFormat) new_array_format = new_format->modify_array(vertex_array);
 
-    // Replace the existing color format with the new format.
+    // Replace the existing vertex format with the new format.
     new_array_format->add_column
-      (InternalName::get_color(), 4, NT_uint8,
-       C_color, color_type->get_start(), color_type->get_column_alignment());
+      (InternalName::get_vertex(), 3, NT_int16,
+       C_point, vertex_type->get_start(), vertex_type->get_column_alignment());
   }
 
+  // Convert packed formats that OpenGL may not understand.
+  for (int i = 0; i < orig->get_num_columns(); ++i) {
+    const GeomVertexColumn *column = orig->get_column(i);
+    int array = orig->get_array_with(column->get_name());
+
+    if (column->get_numeric_type() == NT_packed_dabc &&
+        !glgsg->_supports_packed_dabc) {
+      // Unpack the packed ARGB color into its four byte components.
+      PT(GeomVertexArrayFormat) array_format = new_format->modify_array(array);
+      array_format->add_column(column->get_name(), 4, NT_uint8, C_color,
+                               column->get_start(), column->get_column_alignment());
+
+    } else if (column->get_numeric_type() == NT_packed_ufloat &&
+               !glgsg->_supports_packed_ufloat) {
+      // Unpack to three 32-bit floats.  (In future, should try 16-bit float)
+      PT(GeomVertexArrayFormat) array_format = new_format->modify_array(array);
+      array_format->add_column(column->get_name(), 3, NT_float32,
+                               column->get_contents(), column->get_start(),
+                               column->get_column_alignment());
+    }
+  }
+#endif  // !OPENGLES
+
   CPT(GeomVertexFormat) format = GeomVertexFormat::register_format(new_format);
 
   if ((_flags & F_parallel_arrays) != 0) {
@@ -362,6 +426,45 @@ premunge_format_impl(const GeomVertexFormat *orig) {
   return format;
 }
 
+#ifdef OPENGLES
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(GeomMunger)::munge_geom_impl
+//       Access: Protected, Virtual
+//  Description: Converts a Geom and/or its data as necessary.
+////////////////////////////////////////////////////////////////////
+void CLP(GeomMunger)::
+munge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data,
+                Thread *current_thread) {
+  StandardMunger::munge_geom_impl(geom, vertex_data, current_thread);
+
+  // OpenGL ES has no polygon mode, so we have to emulate it.
+  RenderModeAttrib::Mode render_mode = get_render_mode();
+  if (render_mode == RenderModeAttrib::M_point) {
+    geom = geom->make_points();
+  } else if (render_mode == RenderModeAttrib::M_wireframe) {
+    geom = geom->make_lines();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(GeomMunger)::premunge_geom_impl
+//       Access: Protected, Virtual
+//  Description: Converts a Geom and/or its data as necessary.
+////////////////////////////////////////////////////////////////////
+void CLP(GeomMunger)::
+premunge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data) {
+  StandardMunger::premunge_geom_impl(geom, vertex_data);
+
+  // OpenGL ES has no polygon mode, so we have to emulate it.
+  RenderModeAttrib::Mode render_mode = get_render_mode();
+  if (render_mode == RenderModeAttrib::M_point) {
+    geom = geom->make_points();
+  } else if (render_mode == RenderModeAttrib::M_wireframe) {
+    geom = geom->make_lines();
+  }
+}
+#endif  // OPENGLES
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CLP(GeomMunger)::compare_to_impl
 //       Access: Protected, Virtual
@@ -397,6 +500,11 @@ compare_to_impl(const GeomMunger *other) const {
 int CLP(GeomMunger)::
 geom_compare_to_impl(const GeomMunger *other) const {
   const CLP(GeomMunger) *om = DCAST(CLP(GeomMunger), other);
+#ifdef OPENGLES
+  if (get_render_mode() != om->get_render_mode()) {
+    return get_render_mode() < om->get_render_mode() ? -1 : 1;
+  }
+#endif
   if (_texture != om->_texture) {
     return _texture < om->_texture ? -1 : 1;
   }

+ 6 - 0
panda/src/glstuff/glGeomMunger_src.h

@@ -42,6 +42,12 @@ protected:
                                                   const GeomVertexAnimationSpec &animation);
   virtual CPT(GeomVertexFormat) premunge_format_impl(const GeomVertexFormat *orig);
 
+#ifdef OPENGLES
+  virtual void munge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &data,
+                               Thread *current_thread);
+  virtual void premunge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &data);
+#endif
+
   virtual int compare_to_impl(const GeomMunger *other) const;
   virtual int geom_compare_to_impl(const GeomMunger *other) const;
 

+ 52 - 28
panda/src/glstuff/glGraphicsStateGuardian_src.I

@@ -532,6 +532,7 @@ enable_depth_test(bool val) {
   }
 }
 
+#ifndef OPENGLES_2
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::enable_fog
 //       Access:
@@ -539,7 +540,6 @@ enable_depth_test(bool val) {
 ////////////////////////////////////////////////////////////////////
 INLINE void CLP(GraphicsStateGuardian)::
 enable_fog(bool val) {
-#ifndef OPENGLES_2
   if (_fog_enabled != val) {
     _fog_enabled = val;
     if (val) {
@@ -556,9 +556,10 @@ enable_fog(bool val) {
       glDisable(GL_FOG);
     }
   }
-#endif
 }
+#endif
 
+#ifndef OPENGLES_2
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::enable_alpha_test
 //       Access:
@@ -566,7 +567,6 @@ enable_fog(bool val) {
 ////////////////////////////////////////////////////////////////////
 INLINE void CLP(GraphicsStateGuardian)::
 enable_alpha_test(bool val) {
-#ifndef OPENGLES_2
   if (_alpha_test_enabled != val) {
     _alpha_test_enabled = val;
     if (val) {
@@ -583,9 +583,8 @@ enable_alpha_test(bool val) {
       glDisable(GL_ALPHA_TEST);
     }
   }
-#endif // OPENGLES_2
 }
-
+#endif
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::enable_polygon_offset
@@ -616,6 +615,36 @@ enable_polygon_offset(bool val) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::set_color_write_mask
+//       Access: Protected
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void CLP(GraphicsStateGuardian)::
+set_color_write_mask(int mask) {
+  if (gl_color_mask && _active_color_write_mask != mask) {
+    _active_color_write_mask = mask;
+    glColorMask((_color_write_mask & ColorWriteAttrib::C_red) != 0,
+                (_color_write_mask & ColorWriteAttrib::C_green) != 0,
+                (_color_write_mask & ColorWriteAttrib::C_blue) != 0,
+                (_color_write_mask & ColorWriteAttrib::C_alpha) != 0);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::clear_color_write_mask
+//       Access: Protected
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void CLP(GraphicsStateGuardian)::
+clear_color_write_mask() {
+  if (gl_color_mask && _active_color_write_mask != ColorWriteAttrib::C_all) {
+    _active_color_write_mask = ColorWriteAttrib::C_all;
+    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+  }
+}
+
+#ifndef OPENGLES_2
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::call_glFogfv
 //       Access: Public
@@ -624,16 +653,16 @@ enable_polygon_offset(bool val) {
 ////////////////////////////////////////////////////////////////////
 INLINE void CLP(GraphicsStateGuardian)::
 call_glFogfv(GLenum pname, const LColor &color) {
-#ifndef OPENGLES_2
 #ifndef STDFLOAT_DOUBLE
   glFogfv(pname, color.get_data());
 #else  // STDFLOAT_DOUBLE
   LColorf fcolor = LCAST(float, color);
   glFogfv(pname, fcolor.get_data());
 #endif  //  STDFLOAT_DOUBLE
-#endif
 }
+#endif
 
+#ifndef OPENGLES_2
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::call_glMaterialfv
 //       Access: Public
@@ -642,16 +671,16 @@ call_glFogfv(GLenum pname, const LColor &color) {
 ////////////////////////////////////////////////////////////////////
 INLINE void CLP(GraphicsStateGuardian)::
 call_glMaterialfv(GLenum face, GLenum pname, const LColor &color) {
-#ifndef OPENGLES_2
 #ifndef STDFLOAT_DOUBLE
   glMaterialfv(face, pname, color.get_data());
 #else  // STDFLOAT_DOUBLE
   LColorf fcolor = LCAST(float, color);
   glMaterialfv(face, pname, fcolor.get_data());
 #endif  //  STDFLOAT_DOUBLE
-#endif
 }
+#endif
 
+#ifndef OPENGLES_2
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::call_glLightfv
 //       Access: Public
@@ -660,16 +689,16 @@ call_glMaterialfv(GLenum face, GLenum pname, const LColor &color) {
 ////////////////////////////////////////////////////////////////////
 INLINE void CLP(GraphicsStateGuardian)::
 call_glLightfv(GLenum light, GLenum pname, const LVecBase4 &value) {
-#ifndef OPENGLES_2
 #ifndef STDFLOAT_DOUBLE
   glLightfv(light, pname, value.get_data());
 #else  // STDFLOAT_DOUBLE
   LVecBase4f fvalue = LCAST(float, value);
   glLightfv(light, pname, fvalue.get_data());
 #endif  //  STDFLOAT_DOUBLE
-#endif
 }
+#endif
 
+#ifndef OPENGLES_2
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::call_glLightfv
 //       Access: Public
@@ -678,16 +707,16 @@ call_glLightfv(GLenum light, GLenum pname, const LVecBase4 &value) {
 ////////////////////////////////////////////////////////////////////
 INLINE void CLP(GraphicsStateGuardian)::
 call_glLightfv(GLenum light, GLenum pname, const LVecBase3 &value) {
-#ifndef OPENGLES_2
 #ifndef STDFLOAT_DOUBLE
   glLightfv(light, pname, value.get_data());
 #else  // STDFLOAT_DOUBLE
   LVecBase3f fvalue = LCAST(float, value);
   glLightfv(light, pname, fvalue.get_data());
 #endif  //  STDFLOAT_DOUBLE
-#endif
 }
+#endif
 
+#ifndef OPENGLES_2
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::call_glLightModelfv
 //       Access: Public
@@ -696,16 +725,16 @@ call_glLightfv(GLenum light, GLenum pname, const LVecBase3 &value) {
 ////////////////////////////////////////////////////////////////////
 INLINE void CLP(GraphicsStateGuardian)::
 call_glLightModelfv(GLenum pname, const LVecBase4 &value) {
-#ifndef OPENGLES_2
 #ifndef STDFLOAT_DOUBLE
   glLightModelfv(pname, value.get_data());
 #else  // STDFLOAT_DOUBLE
   LVecBase4f fvalue = LCAST(float, value);
   glLightModelfv(pname, fvalue.get_data());
 #endif  //  STDFLOAT_DOUBLE
-#endif  // OPENGLES_2
 }
+#endif
 
+#ifndef OPENGLES_2
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::call_glTexEnvfv
 //       Access: Public
@@ -714,15 +743,14 @@ call_glLightModelfv(GLenum pname, const LVecBase4 &value) {
 ////////////////////////////////////////////////////////////////////
 INLINE void CLP(GraphicsStateGuardian)::
 call_glTexEnvfv(GLenum target, GLenum pname, const LVecBase4 &value) {
-#ifndef OPENGLES_2
 #ifndef STDFLOAT_DOUBLE
   glTexEnvfv(target, pname, value.get_data());
 #else  // STDFLOAT_DOUBLE
   LVecBase4f fvalue = LCAST(float, value);
   glTexEnvfv(target, pname, fvalue.get_data());
 #endif  //  STDFLOAT_DOUBLE
-#endif
 }
+#endif
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::call_glTexParameterfv
@@ -740,6 +768,7 @@ call_glTexParameterfv(GLenum target, GLenum pname, const LVecBase4 &value) {
 #endif  //  STDFLOAT_DOUBLE
 }
 
+#ifndef OPENGLES_2
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::get_light_id
 //       Access: Public
@@ -747,13 +776,11 @@ call_glTexParameterfv(GLenum target, GLenum pname, const LVecBase4 &value) {
 ////////////////////////////////////////////////////////////////////
 INLINE GLenum CLP(GraphicsStateGuardian)::
 get_light_id(int index) const {
-#ifndef OPENGLES_2
   return GL_LIGHT0 + index;
-#else
-  return 0;
-#endif
 }
+#endif
 
+#ifndef OPENGLES_2
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::get_clip_plane_id
 //       Access: Public
@@ -761,12 +788,9 @@ get_light_id(int index) const {
 ////////////////////////////////////////////////////////////////////
 INLINE GLenum CLP(GraphicsStateGuardian)::
 get_clip_plane_id(int index) const {
-#ifndef OPENGLES_2
   return GL_CLIP_PLANE0 + index;
-#else
-  return 0;
-#endif
 }
+#endif
 
 ////////////////////////////////////////////////////////////////////
 //     Function: CLP(GraphicsStateGuardian)::get_supports_framebuffer_multisample
@@ -776,7 +800,7 @@ get_clip_plane_id(int index) const {
 ////////////////////////////////////////////////////////////////////
 INLINE bool CLP(GraphicsStateGuardian)::
 get_supports_framebuffer_multisample() {
-    return _supports_framebuffer_multisample;
+  return _supports_framebuffer_multisample;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -787,7 +811,7 @@ get_supports_framebuffer_multisample() {
 ////////////////////////////////////////////////////////////////////
 INLINE bool CLP(GraphicsStateGuardian)::
 get_supports_framebuffer_multisample_coverage_nv() {
-    return _supports_framebuffer_multisample_coverage_nv;
+  return _supports_framebuffer_multisample_coverage_nv;
 }
 
 
@@ -799,7 +823,7 @@ get_supports_framebuffer_multisample_coverage_nv() {
 ////////////////////////////////////////////////////////////////////
 INLINE bool CLP(GraphicsStateGuardian)::
 get_supports_framebuffer_blit() {
-    return _supports_framebuffer_blit;
+  return _supports_framebuffer_blit;
 }
 
 #ifndef NDEBUG

File diff suppressed because it is too large
+ 354 - 121
panda/src/glstuff/glGraphicsStateGuardian_src.cxx


+ 60 - 12
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -21,6 +21,7 @@
 #include "texture.h"
 #include "displayRegion.h"
 #include "material.h"
+#include "colorWriteAttrib.h"
 #include "depthTestAttrib.h"
 #include "textureAttrib.h"
 #include "texMatrixAttrib.h"
@@ -179,10 +180,14 @@ typedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, con
 typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
 typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
 typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v);
 typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer);
 typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
 typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
 typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor);
+typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
+typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount);
 #endif  // OPENGLES_1
 #ifndef OPENGLES
 typedef void (APIENTRYP PFNGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers);
@@ -193,8 +198,6 @@ typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pna
 typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFPROC) (GLuint sampler, GLenum pname, GLfloat param);
 typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat *param);
 typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value);
-typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
-typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount);
 typedef void (APIENTRYP PFNGLCLEARTEXIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data);
 typedef void (APIENTRYP PFNGLCLEARTEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
 typedef void (APIENTRYP PFNGLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);
@@ -280,15 +283,19 @@ public:
                            bool force);
   virtual void end_draw_primitives();
 
+#ifndef OPENGLES
   void issue_memory_barrier(GLbitfield barrier);
+#endif
 
   virtual TextureContext *prepare_texture(Texture *tex, int view);
   virtual bool update_texture(TextureContext *tc, bool force);
   virtual void release_texture(TextureContext *tc);
   virtual bool extract_texture_data(Texture *tex);
 
+#ifndef OPENGLES
   virtual SamplerContext *prepare_sampler(const SamplerState &sampler);
   virtual void release_sampler(SamplerContext *sc);
+#endif
 
   virtual GeomContext *prepare_geom(Geom *geom);
   virtual void release_geom(GeomContext *gc);
@@ -317,12 +324,16 @@ public:
                        const GeomPrimitivePipelineReader *reader,
                        bool force);
 
+#ifndef OPENGLES
   virtual void begin_occlusion_query();
   virtual PT(OcclusionQueryContext) end_occlusion_query();
+#endif
 
   virtual PT(TimerQueryContext) issue_timer_query(int pstats_index);
 
+#ifndef OPENGLES
   virtual void dispatch_compute(int size_x, int size_y, int size_z);
+#endif
 
   virtual PT(GeomMunger) make_geom_munger(const RenderState *state,
                                           Thread *current_thread);
@@ -336,6 +347,7 @@ public:
   virtual bool framebuffer_copy_to_ram
     (Texture *tex, int view, int z, const DisplayRegion *dr, const RenderBuffer &rb);
 
+#ifndef OPENGLES_2
   void apply_fog(Fog *fog);
 
   virtual void bind_light(PointLight *light_obj, const NodePath &light,
@@ -344,6 +356,7 @@ public:
                           int light_id);
   virtual void bind_light(Spotlight *light_obj, const NodePath &light,
                           int light_id);
+#endif
 
   void print_gfx_visual();
 
@@ -379,18 +392,26 @@ protected:
   void do_issue_rescale_normal();
   void do_issue_color_write();
   void do_issue_depth_test();
+#ifndef OPENGLES_2
   void do_issue_alpha_test();
+#endif
   void do_issue_depth_write();
   void do_issue_cull_face();
+#ifndef OPENGLES_2
   void do_issue_fog();
+#endif
   void do_issue_depth_offset();
   void do_issue_shade_model();
   void do_issue_shader(bool state_has_changed = false);
+#ifndef OPENGLES_2
   void do_issue_material();
+#endif
   void do_issue_texture();
   void do_issue_blending();
+#ifndef OPENGLES_2
   void do_issue_tex_gen();
   void do_issue_tex_matrix();
+#endif
   void do_issue_stencil();
   void do_issue_scissor();
 
@@ -413,6 +434,8 @@ protected:
   virtual void *do_get_extension_func(const char *name);
 
   virtual void reissue_transforms();
+
+#ifndef OPENGLES_2
   virtual void enable_lighting(bool enable);
   virtual void set_ambient_light(const LColor &color);
   virtual void enable_light(int light_id, bool enable);
@@ -423,6 +446,7 @@ protected:
   virtual void begin_bind_clip_planes();
   virtual void bind_clip_plane(const NodePath &plane, int plane_id);
   virtual void end_bind_clip_planes();
+#endif
 
   virtual void free_pointers();
 
@@ -443,16 +467,24 @@ protected:
   INLINE void enable_alpha_test(bool val);
   INLINE void enable_polygon_offset(bool val);
 
+  INLINE void set_color_write_mask(int mask);
+  INLINE void clear_color_write_mask();
+
+#ifndef OPENGLES_2
   INLINE void call_glFogfv(GLenum pname, const LColor &color);
   INLINE void call_glMaterialfv(GLenum face, GLenum pname, const LColor &color);
   INLINE void call_glLightfv(GLenum light, GLenum pname, const LVecBase4 &value);
   INLINE void call_glLightfv(GLenum light, GLenum pname, const LVecBase3 &value);
   INLINE void call_glLightModelfv(GLenum pname, const LVecBase4 &value);
   INLINE void call_glTexEnvfv(GLenum target, GLenum pname, const LVecBase4 &value);
+#endif
+
   INLINE void call_glTexParameterfv(GLenum target, GLenum pname, const LVecBase4 &value);
 
+#ifndef OPENGLES_2
   INLINE GLenum get_light_id(int index) const;
   INLINE GLenum get_clip_plane_id(int index) const;
+#endif
 
   void set_draw_buffer(int rbtype);
   void set_read_buffer(int rbtype);
@@ -481,10 +513,12 @@ protected:
   static GLenum get_usage(Geom::UsageHint usage_hint);
 
   void unbind_buffers();
+#ifndef OPENGLES_2
   void disable_standard_vertex_arrays();
   bool update_standard_vertex_arrays(bool force);
   void disable_standard_texture_bindings();
   void update_standard_texture_bindings();
+#endif
 
 #ifndef NDEBUG
   void update_show_usage_texture_bindings(int show_stage_index);
@@ -539,6 +573,7 @@ protected:
   bool _polygon_offset_enabled;
   bool _flat_shade_model;
   int  _decal_level;
+  int _active_color_write_mask;
 
   bool _dithering_enabled;
 
@@ -565,7 +600,7 @@ protected:
   ShaderContext *_texture_binding_shader_context;
 #endif
 #ifdef OPENGLES_2
-  static PT(Shader)  _default_shader;
+  static PT(Shader) _default_shader;
 #endif
 
 #ifdef HAVE_CG
@@ -635,27 +670,35 @@ public:
   PFNGLWEIGHTDVARBPROC _glWeightdv;
 
   bool _supports_matrix_palette;
-#ifdef OPENGLES
+#ifdef OPENGLES_1
   PFNGLCURRENTPALETTEMATRIXOESPROC _glCurrentPaletteMatrix;
   PFNGLMATRIXINDEXPOINTEROESPROC _glMatrixIndexPointer;
-#else
+#endif
+#ifndef OPENGLES
   PFNGLCURRENTPALETTEMATRIXARBPROC _glCurrentPaletteMatrix;
   PFNGLMATRIXINDEXPOINTERARBPROC _glMatrixIndexPointer;
   PFNGLMATRIXINDEXUIVARBPROC _glMatrixIndexuiv;
 #endif
 
-  bool _supports_draw_range_elements;
+#ifndef OPENGLES
   PFNGLDRAWRANGEELEMENTSPROC _glDrawRangeElements;
+#endif
 
+#ifndef OPENGLES_1
   PFNGLTEXIMAGE3DPROC_P _glTexImage3D;
   PFNGLTEXSUBIMAGE3DPROC _glTexSubImage3D;
   PFNGLCOPYTEXSUBIMAGE3DPROC _glCopyTexSubImage3D;
+#endif
 
   bool _supports_tex_storage;
   PFNGLTEXSTORAGE1DPROC _glTexStorage1D;
   PFNGLTEXSTORAGE2DPROC _glTexStorage2D;
   PFNGLTEXSTORAGE3DPROC _glTexStorage3D;
 
+#ifndef OPENGLES
+  PFNGLTEXBUFFERPROC _glTexBuffer;
+#endif
+
   bool _supports_clear_texture;
 #ifndef OPENGLES
   PFNGLCLEARTEXIMAGEPROC _glClearTexImage;
@@ -672,9 +715,11 @@ public:
   bool _supports_bgr;
   bool _supports_rescale_normal;
   bool _supports_packed_dabc;
+  bool _supports_packed_ufloat;
 
-  bool _supports_multitexture;
   PFNGLACTIVETEXTUREPROC _glActiveTexture;
+#ifndef OPENGLES_2
+  bool _supports_multitexture;
   PFNGLCLIENTACTIVETEXTUREPROC _glClientActiveTexture;
   PFNGLMULTITEXCOORD1FPROC _glMultiTexCoord1f;
   PFNGLMULTITEXCOORD2FPROC _glMultiTexCoord2f;
@@ -684,6 +729,7 @@ public:
   PFNGLMULTITEXCOORD2DPROC _glMultiTexCoord2d;
   PFNGLMULTITEXCOORD3DPROC _glMultiTexCoord3d;
   PFNGLMULTITEXCOORD4DPROC _glMultiTexCoord4d;
+#endif
 
   bool _supports_buffers;
   PFNGLGENBUFFERSPROC _glGenBuffers;
@@ -789,11 +835,15 @@ public:
   PFNGLUNIFORMMATRIX3FVPROC _glUniformMatrix3fv;
   PFNGLUNIFORMMATRIX4FVPROC _glUniformMatrix4fv;
   PFNGLVALIDATEPROGRAMPROC _glValidateProgram;
+  PFNGLVERTEXATTRIB4FVPROC _glVertexAttrib4fv;
+  PFNGLVERTEXATTRIB4DVPROC _glVertexAttrib4dv;
   PFNGLVERTEXATTRIBPOINTERPROC _glVertexAttribPointer;
   PFNGLVERTEXATTRIBIPOINTERPROC _glVertexAttribIPointer;
   PFNGLVERTEXATTRIBLPOINTERPROC _glVertexAttribLPointer;
   PFNGLVERTEXATTRIBDIVISORPROC _glVertexAttribDivisor;
-#endif  // OPENGLES_1
+  PFNGLDRAWARRAYSINSTANCEDPROC _glDrawArraysInstanced;
+  PFNGLDRAWELEMENTSINSTANCEDPROC _glDrawElementsInstanced;
+#endif  // !OPENGLES_1
 #ifndef OPENGLES
   PFNGLGENSAMPLERSPROC _glGenSamplers;
   PFNGLDELETESAMPLERSPROC _glDeleteSamplers;
@@ -804,8 +854,6 @@ public:
   PFNGLSAMPLERPARAMETERFVPROC _glSamplerParameterfv;
   PFNGLPROGRAMPARAMETERIPROC _glProgramParameteri;
   PFNGLPATCHPARAMETERIPROC _glPatchParameteri;
-  PFNGLDRAWARRAYSINSTANCEDPROC _glDrawArraysInstanced;
-  PFNGLDRAWELEMENTSINSTANCEDPROC _glDrawElementsInstanced;
   PFNGLBINDTEXTURESPROC _glBindTextures;
   PFNGLBINDSAMPLERSPROC _glBindSamplers;
   PFNGLBINDIMAGETEXTUREPROC _glBindImageTexture;
@@ -823,7 +871,7 @@ public:
   PFNGLMAKETEXTUREHANDLENONRESIDENTPROC _glMakeTextureHandleNonResident;
   PFNGLUNIFORMHANDLEUI64PROC _glUniformHandleui64;
   PFNGLUNIFORMHANDLEUI64VPROC _glUniformHandleui64v;
-#endif  // OPENGLES
+#endif  // !OPENGLES
 
   GLenum _edge_clamp;
   GLenum _border_clamp;
@@ -831,7 +879,7 @@ public:
   GLenum _mirror_clamp;
   GLenum _mirror_edge_clamp;
   GLenum _mirror_border_clamp;
-#ifndef OPENGLES
+#ifndef OPENGLES_1
   GLsizei _instance_count;
 #endif
 

+ 319 - 102
panda/src/glstuff/glShaderContext_src.I

@@ -196,6 +196,8 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
   _glgsg = glgsg;
   _glsl_program = 0;
   _uses_standard_vertex_arrays = false;
+  _has_divisor = false;
+  _color_attrib_index = -1;
 
   nassertv(s->get_language() == Shader::SL_GLSL);
 
@@ -315,10 +317,14 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
                 bind._part[1] = Shader::SMO_view_to_model;
               }
 
-              if (transpose) {
-                bind._piece = Shader::SMP_upper3x3;
+              if (param_type != GL_FLOAT_MAT3) {
+                GLCAT.error() << "p3d_NormalMatrix input should be mat3, not mat4!\n";
               } else {
-                bind._piece = Shader::SMP_transpose3x3;
+                if (transpose) {
+                  bind._piece = Shader::SMP_upper3x3;
+                } else {
+                  bind._piece = Shader::SMP_transpose3x3;
+                }
               }
 
             } else if (matrix_name == "ModelMatrix") {
@@ -356,13 +362,26 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
             continue;
           }
           if (size > 7 && noprefix.substr(0, 7) == "Texture") {
-            _glgsg->_glUniform1i(p, s->_tex_spec.size());
             Shader::ShaderTexSpec bind;
             bind._id = arg_id;
             bind._name = 0;
-            bind._desired_type = Texture::TT_2d_texture;
-            bind._stage = atoi(noprefix.substr(7).c_str());
-            s->_tex_spec.push_back(bind);
+
+            string tail;
+            bind._stage = string_to_int(noprefix.substr(7), tail);
+            if (!tail.empty()) {
+              GLCAT.error()
+                << "Error parsing shader input name: unexpected '"
+                << tail << "' in '" << param_name << "'\n";
+              continue;
+            }
+
+            if (get_sampler_texture_type(bind._desired_type, param_type)) {
+              _glgsg->_glUniform1i(p, s->_tex_spec.size());
+              s->_tex_spec.push_back(bind);
+            } else {
+              GLCAT.error()
+                << "Could not bind texture input " << param_name << "\n";
+            }
             continue;
           }
           if (size > 9 && noprefix.substr(0, 9) == "Material.") {
@@ -377,22 +396,46 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
             bind._dep[1] = Shader::SSD_NONE;
 
             if (noprefix == "Material.ambient") {
+              if (param_type != GL_FLOAT_VEC4) {
+                GLCAT.error()
+                  << "p3d_Material.ambient should be vec4\n";
+              }
               bind._piece = Shader::SMP_row0;
               s->_mat_spec.push_back(bind);
               continue;
+
             } else if (noprefix == "Material.diffuse") {
+              if (param_type != GL_FLOAT_VEC4) {
+                GLCAT.error()
+                  << "p3d_Material.diffuse should be vec4\n";
+              }
               bind._piece = Shader::SMP_row1;
               s->_mat_spec.push_back(bind);
               continue;
+
             } else if (noprefix == "Material.emission") {
+              if (param_type != GL_FLOAT_VEC4) {
+                GLCAT.error()
+                  << "p3d_Material.emission should be vec4\n";
+              }
               bind._piece = Shader::SMP_row2;
               s->_mat_spec.push_back(bind);
               continue;
+
             } else if (noprefix == "Material.specular") {
+              if (param_type != GL_FLOAT_VEC3) {
+                GLCAT.error()
+                  << "p3d_Material.specular should be vec3\n";
+              }
               bind._piece = Shader::SMP_row3x3;
               s->_mat_spec.push_back(bind);
               continue;
+
             } else if (noprefix == "Material.shininess") {
+              if (param_type != GL_FLOAT) {
+                GLCAT.error()
+                  << "p3d_Material.shininess should be float\n";
+              }
               bind._piece = Shader::SMP_cell15;
               s->_mat_spec.push_back(bind);
               continue;
@@ -401,7 +444,6 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
           if (noprefix == "ColorScale") {
             Shader::ShaderMatSpec bind;
             bind._id = arg_id;
-            bind._piece = Shader::SMP_row3;
             bind._func = Shader::SMF_first;
             bind._part[0] = Shader::SMO_attr_colorscale;
             bind._arg[0] = NULL;
@@ -409,13 +451,22 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
             bind._part[1] = Shader::SMO_identity;
             bind._arg[1] = NULL;
             bind._dep[1] = Shader::SSD_NONE;
+
+            if (param_type == GL_FLOAT_VEC3) {
+              bind._piece = Shader::SMP_row3x3;
+            } else if (param_type == GL_FLOAT_VEC4) {
+              bind._piece = Shader::SMP_row3;
+            } else {
+              GLCAT.error()
+                << "p3d_ColorScale should be vec3 or vec4\n";
+              continue;
+            }
             s->_mat_spec.push_back(bind);
             continue;
           }
           if (noprefix == "Color") {
             Shader::ShaderMatSpec bind;
             bind._id = arg_id;
-            bind._piece = Shader::SMP_row3;
             bind._func = Shader::SMF_first;
             bind._part[0] = Shader::SMO_attr_color;
             bind._arg[0] = NULL;
@@ -423,10 +474,25 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
             bind._part[1] = Shader::SMO_identity;
             bind._arg[1] = NULL;
             bind._dep[1] = Shader::SSD_NONE;
+
+            if (param_type == GL_FLOAT_VEC3) {
+              bind._piece = Shader::SMP_row3x3;
+            } else if (param_type == GL_FLOAT_VEC4) {
+              bind._piece = Shader::SMP_row3;
+            } else {
+              GLCAT.error()
+                << "p3d_Color should be vec3 or vec4\n";
+              continue;
+            }
             s->_mat_spec.push_back(bind);
             continue;
           }
           if (noprefix == "ClipPlane") {
+            if (param_type != GL_FLOAT_VEC4) {
+              GLCAT.error()
+                << "p3d_ClipPlane should be vec4 or vec4[]\n";
+              continue;
+            }
             for (int i = 0; i < param_size; ++i) {
               Shader::ShaderMatSpec bind;
               bind._id = arg_id;
@@ -448,7 +514,6 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
           if (noprefix == "LightModel.ambient") {
             Shader::ShaderMatSpec bind;
             bind._id = arg_id;
-            bind._piece = Shader::SMP_row3;
             bind._func = Shader::SMF_first;
             bind._part[0] = Shader::SMO_light_ambient;
             bind._arg[0] = NULL;
@@ -456,6 +521,16 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
             bind._part[1] = Shader::SMO_identity;
             bind._arg[1] = NULL;
             bind._dep[1] = Shader::SSD_NONE;
+
+            if (param_type == GL_FLOAT_VEC3) {
+              bind._piece = Shader::SMP_row3x3;
+            } else if (param_type == GL_FLOAT_VEC4) {
+              bind._piece = Shader::SMP_row3;
+            } else {
+              GLCAT.error()
+                << "p3d_LightModel.ambient should be vec3 or vec4\n";
+              continue;
+            }
             s->_mat_spec.push_back(bind);
             continue;
           }
@@ -524,71 +599,39 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
           switch (param_type) {
 #ifndef OPENGLES
             case GL_INT_SAMPLER_1D:
-            case GL_UNSIGNED_INT_SAMPLER_1D:
-            case GL_SAMPLER_1D_SHADOW:
-            case GL_SAMPLER_1D: {
-              _glgsg->_glUniform1i(p, s->_tex_spec.size());
-              Shader::ShaderTexSpec bind;
-              bind._id = arg_id;
-              bind._name = InternalName::make(param_name);
-              bind._desired_type = Texture::TT_1d_texture;
-              bind._stage = texunitno++;
-              s->_tex_spec.push_back(bind);
-              continue; }
             case GL_INT_SAMPLER_2D:
-            case GL_UNSIGNED_INT_SAMPLER_2D:
-            case GL_SAMPLER_2D_SHADOW:
-#endif
-            case GL_SAMPLER_2D: {
-              _glgsg->_glUniform1i(p, s->_tex_spec.size());
-              Shader::ShaderTexSpec bind;
-              bind._id = arg_id;
-              bind._name = InternalName::make(param_name);
-              bind._desired_type = Texture::TT_2d_texture;
-              bind._stage = texunitno++;
-              s->_tex_spec.push_back(bind);
-              continue; }
-#ifndef OPENGLES
             case GL_INT_SAMPLER_3D:
-            case GL_UNSIGNED_INT_SAMPLER_3D:
-#endif
-            case GL_SAMPLER_3D: {
-              _glgsg->_glUniform1i(p, s->_tex_spec.size());
-              Shader::ShaderTexSpec bind;
-              bind._id = arg_id;
-              bind._name = InternalName::make(param_name);
-              bind._desired_type = Texture::TT_3d_texture;
-              bind._stage = texunitno++;
-              s->_tex_spec.push_back(bind);
-              continue; }
-#ifndef OPENGLES
+            case GL_INT_SAMPLER_2D_ARRAY:
             case GL_INT_SAMPLER_CUBE:
+            case GL_INT_SAMPLER_BUFFER:
+            case GL_UNSIGNED_INT_SAMPLER_1D:
+            case GL_UNSIGNED_INT_SAMPLER_2D:
+            case GL_UNSIGNED_INT_SAMPLER_3D:
             case GL_UNSIGNED_INT_SAMPLER_CUBE:
-            case GL_SAMPLER_CUBE_SHADOW:
-#endif
-            case GL_SAMPLER_CUBE: {
-              _glgsg->_glUniform1i(p, s->_tex_spec.size());
-              Shader::ShaderTexSpec bind;
-              bind._id = arg_id;
-              bind._name = InternalName::make(param_name);
-              bind._desired_type = Texture::TT_cube_map;
-              bind._stage = texunitno++;
-              s->_tex_spec.push_back(bind);
-              continue; }
-#ifndef OPENGLES
-            case GL_INT_SAMPLER_2D_ARRAY:
             case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
+            case GL_UNSIGNED_INT_SAMPLER_BUFFER:
+            case GL_SAMPLER_1D_SHADOW:
+            case GL_SAMPLER_1D:
+            case GL_SAMPLER_CUBE_SHADOW:
+            case GL_SAMPLER_2D_ARRAY:
             case GL_SAMPLER_2D_ARRAY_SHADOW:
-            case GL_SAMPLER_2D_ARRAY: {
-              _glgsg->_glUniform1i(p, s->_tex_spec.size());
+            case GL_SAMPLER_BUFFER:
+#endif  // !OPENGLES
+            case GL_SAMPLER_2D:
+            case GL_SAMPLER_2D_SHADOW:
+            case GL_SAMPLER_3D:
+            case GL_SAMPLER_CUBE: {
               Shader::ShaderTexSpec bind;
               bind._id = arg_id;
               bind._name = InternalName::make(param_name);
-              bind._desired_type = Texture::TT_2d_texture_array;
+              bind._desired_type = Texture::TT_2d_texture;
               bind._stage = texunitno++;
-              s->_tex_spec.push_back(bind);
-              continue; }
-#endif
+              if (get_sampler_texture_type(bind._desired_type, param_type)) {
+                _glgsg->_glUniform1i(p, s->_tex_spec.size());
+                s->_tex_spec.push_back(bind);
+              }
+              continue;
+            }
             case GL_FLOAT_MAT2:
 #ifndef OPENGLES
             case GL_FLOAT_MAT2x3:
@@ -598,7 +641,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
             case GL_FLOAT_MAT4x2:
             case GL_FLOAT_MAT4x3:
 #endif
-              GLCAT.warning() << "GLSL shader requested an unrecognized matrix type\n";
+              GLCAT.warning() << "GLSL shader requested an unsupported matrix type\n";
               continue;
             case GL_FLOAT_MAT3: {
               Shader::ShaderMatSpec bind;
@@ -722,16 +765,19 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
             case GL_IMAGE_3D_EXT:
             case GL_IMAGE_CUBE_EXT:
             case GL_IMAGE_2D_ARRAY_EXT:
+            case GL_IMAGE_BUFFER_EXT:
             case GL_INT_IMAGE_1D_EXT:
             case GL_INT_IMAGE_2D_EXT:
             case GL_INT_IMAGE_3D_EXT:
             case GL_INT_IMAGE_CUBE_EXT:
             case GL_INT_IMAGE_2D_ARRAY_EXT:
+            case GL_INT_IMAGE_BUFFER_EXT:
             case GL_UNSIGNED_INT_IMAGE_1D_EXT:
             case GL_UNSIGNED_INT_IMAGE_2D_EXT:
             case GL_UNSIGNED_INT_IMAGE_3D_EXT:
             case GL_UNSIGNED_INT_IMAGE_CUBE_EXT:
             case GL_UNSIGNED_INT_IMAGE_2D_ARRAY_EXT:
+            case GL_UNSIGNED_INT_IMAGE_BUFFER_EXT:
               // This won't really change at runtime, so we might as well
               // bind once and then forget about it.
               _glgsg->_glUniform1i(p, imgunitno++);
@@ -880,7 +926,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
                        param_type == GL_UNSIGNED_INT_VEC3 ||
                        param_type == GL_UNSIGNED_INT_VEC4 ||
 #endif
-                       param_type == GL_UNSIGNED_INT );
+                       param_type == GL_UNSIGNED_INT);
 
       if (noprefix.empty()) {
         // Arbitrarily named attribute.
@@ -895,6 +941,9 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
       } else if (noprefix == "Color") {
         bind._name = InternalName::get_color();
 
+        // Save the index, so we can apply special handling to this attrib.
+        _color_attrib_index = p;
+
       } else if (noprefix.substr(0, 7) == "Tangent") {
         bind._name = InternalName::get_tangent();
         if (noprefix.size() > 7) {
@@ -945,6 +994,119 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
   _glgsg->report_my_gl_errors();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GLShaderContext::get_sampler_texture_type
+//       Access: Public
+//  Description: Returns the texture type required for the given
+//               GL sampler type.  Returns false if unsupported.
+////////////////////////////////////////////////////////////////////
+bool CLP(ShaderContext)::
+get_sampler_texture_type(int &out, GLenum param_type) {
+  switch (param_type) {
+#ifndef OPENGLES
+  case GL_SAMPLER_1D_SHADOW:
+    if (!_glgsg->_supports_shadow_filter) {
+      GLCAT.error()
+        << "GLSL shader uses shadow sampler, which is unsupported by the driver.\n";
+      return false;
+    }
+    // Fall through
+  case GL_INT_SAMPLER_1D:
+  case GL_UNSIGNED_INT_SAMPLER_1D:
+  case GL_SAMPLER_1D:
+    out = Texture::TT_1d_texture;
+    return true;
+
+  case GL_INT_SAMPLER_2D:
+  case GL_UNSIGNED_INT_SAMPLER_2D:
+#endif
+  case GL_SAMPLER_2D:
+    out = Texture::TT_2d_texture;
+    return true;
+
+  case GL_SAMPLER_2D_SHADOW:
+    out = Texture::TT_2d_texture;
+    if (!_glgsg->_supports_shadow_filter) {
+      GLCAT.error()
+        << "GLSL shader uses shadow sampler, which is unsupported by the driver.\n";
+      return false;
+    }
+    return true;
+
+#ifndef OPENGLES
+  case GL_INT_SAMPLER_3D:
+  case GL_UNSIGNED_INT_SAMPLER_3D:
+#endif
+  case GL_SAMPLER_3D:
+    out = Texture::TT_3d_texture;
+    if (_glgsg->_supports_3d_texture) {
+      return true;
+    } else {
+      GLCAT.error()
+        << "GLSL shader uses 3D texture, which is unsupported by the driver.\n";
+      return false;
+    }
+
+#ifndef OPENGLES
+  case GL_SAMPLER_CUBE_SHADOW:
+    if (!_glgsg->_supports_shadow_filter) {
+      GLCAT.error()
+        << "GLSL shader uses shadow sampler, which is unsupported by the driver.\n";
+      return false;
+    }
+    // Fall through
+  case GL_INT_SAMPLER_CUBE:
+  case GL_UNSIGNED_INT_SAMPLER_CUBE:
+#endif
+  case GL_SAMPLER_CUBE:
+    out = Texture::TT_cube_map;
+    if (!_glgsg->_supports_cube_map) {
+      GLCAT.error()
+        << "GLSL shader uses cube map, which is unsupported by the driver.\n";
+      return false;
+    }
+    return true;
+
+#ifndef OPENGLES
+  case GL_SAMPLER_2D_ARRAY_SHADOW:
+    if (!_glgsg->_supports_shadow_filter) {
+      GLCAT.error()
+        << "GLSL shader uses shadow sampler, which is unsupported by the driver.\n";
+      return false;
+    }
+    // Fall through
+  case GL_INT_SAMPLER_2D_ARRAY:
+  case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
+  case GL_SAMPLER_2D_ARRAY:
+    out = Texture::TT_2d_texture_array;
+    if (_glgsg->_supports_2d_texture_array) {
+      return true;
+    } else {
+      GLCAT.error()
+        << "GLSL shader uses 2D texture array, which is unsupported by the driver.\n";
+      return false;
+    }
+
+  case GL_INT_SAMPLER_BUFFER:
+  case GL_UNSIGNED_INT_SAMPLER_BUFFER:
+  case GL_SAMPLER_BUFFER:
+    out = Texture::TT_buffer_texture;
+    if (_glgsg->_supports_buffer_texture) {
+      return true;
+    } else {
+      GLCAT.error()
+        << "GLSL shader uses buffer texture, which is unsupported by the driver.\n";
+      return false;
+    }
+#endif
+
+  default:
+    GLCAT.error()
+      << "GLSL shader uses unsupported sampler type for texture input.\n";
+    return false;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GLShaderContext::Destructor
 //       Access: Public
@@ -1063,7 +1225,7 @@ issue_parameters(int altered) {
             // Convert int data to float data.
             data = (float*) alloca(sizeof(float) * spec._dim[0] * spec._dim[1]);
             for (int i = 0; i < (spec._dim[0] * spec._dim[1]); ++i) {
-              data[i] = (int)(((float*)ptr_data->_ptr)[i]);
+              data[i] = (float)(((int*)ptr_data->_ptr)[i]);
             }
             break;
 
@@ -1084,12 +1246,12 @@ issue_parameters(int altered) {
           }
 
           switch (spec._dim[1]) {
-          case 1: _glgsg->_glUniform1fv(p, spec._dim[0], (float*)ptr_data->_ptr); continue;
-          case 2: _glgsg->_glUniform2fv(p, spec._dim[0], (float*)ptr_data->_ptr); continue;
-          case 3: _glgsg->_glUniform3fv(p, spec._dim[0], (float*)ptr_data->_ptr); continue;
-          case 4: _glgsg->_glUniform4fv(p, spec._dim[0], (float*)ptr_data->_ptr); continue;
-          case 9: _glgsg->_glUniformMatrix3fv(p, spec._dim[0], GL_FALSE, (float*)ptr_data->_ptr); continue;
-          case 16: _glgsg->_glUniformMatrix4fv(p, spec._dim[0], GL_FALSE, (float*)ptr_data->_ptr); continue;
+          case 1: _glgsg->_glUniform1fv(p, spec._dim[0], (float*)data); continue;
+          case 2: _glgsg->_glUniform2fv(p, spec._dim[0], (float*)data); continue;
+          case 3: _glgsg->_glUniform3fv(p, spec._dim[0], (float*)data); continue;
+          case 4: _glgsg->_glUniform4fv(p, spec._dim[0], (float*)data); continue;
+          case 9: _glgsg->_glUniformMatrix3fv(p, spec._dim[0], GL_FALSE, (float*)data); continue;
+          case 16: _glgsg->_glUniformMatrix4fv(p, spec._dim[0], GL_FALSE, (float*)data); continue;
           }
           nassertd(false) continue;
         }
@@ -1202,7 +1364,7 @@ disable_shader_vertex_arrays() {
   for (int i=0; i<(int)_shader->_var_spec.size(); i++) {
     const Shader::ShaderVarSpec &bind = _shader->_var_spec[i];
     const GLint p = _glsl_parameter_map[bind._id._seqno];
-    if (_glgsg->_supports_vertex_attrib_divisor) {
+    if (_has_divisor) {
       _glgsg->_glVertexAttribDivisor(p, 0);
     }
     for (int i = 0; i < bind._elements; ++i) {
@@ -1261,10 +1423,13 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
       }
       GLint p = _glsl_parameter_map[bind._id._seqno];
 
+      // Don't apply vertex colors if they are disabled with a ColorAttrib.
       int num_elements, element_stride, divisor;
-      if (_glgsg->_data_reader->get_array_info(name, array_reader,
+      bool normalized;
+      if ((p != _color_attrib_index || _glgsg->_vertex_colors_enabled) &&
+          _glgsg->_data_reader->get_array_info(name, array_reader,
                                                num_values, numeric_type,
-                                               start, stride, divisor,
+                                               normalized, start, stride, divisor,
                                                num_elements, element_stride)) {
         const unsigned char *client_pointer;
         if (!_glgsg->setup_array_data(client_pointer, array_reader, force)) {
@@ -1282,15 +1447,19 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
           } else
 #endif
           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),
-                                           GL_TRUE, stride, client_pointer);
+            _glgsg->_glVertexAttribPointer(p, num_values,
+                                           _glgsg->get_numeric_type(numeric_type),
+                                           normalized, stride, client_pointer);
           }
 
           if (_glgsg->_supports_vertex_attrib_divisor) {
             _glgsg->_glVertexAttribDivisor(p, divisor);
+            _has_divisor = true;
           }
 
           ++p;
@@ -1300,6 +1469,14 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
         for (int i = 0; i < bind._elements; ++i) {
           _glgsg->_glDisableVertexAttribArray(p + i);
         }
+        if (p == _color_attrib_index) {
+          // Vertex colors are disabled or not present.  Apply flat color.
+#if defined(STDFLOAT_DOUBLE) && !defined(OPENGLES)
+          _glgsg->_glVertexAttrib4dv(p, _glgsg->_scene_graph_color.get_data());
+#else
+          _glgsg->_glVertexAttrib4fv(p, _glgsg->_scene_graph_color.get_data());
+#endif
+        }
       }
     }
   }
@@ -1342,22 +1519,38 @@ disable_shader_texture_bindings() {
 
     _glgsg->_glActiveTexture(GL_TEXTURE0 + i);
 
+    switch (_shader->_tex_spec[i]._desired_type) {
+    case Texture::TT_1d_texture:
 #ifndef OPENGLES
-    glBindTexture(GL_TEXTURE_1D, 0);
-#endif  // OPENGLES
-    glBindTexture(GL_TEXTURE_2D, 0);
+      glBindTexture(GL_TEXTURE_1D, 0);
+#endif
+      break;
+
+    case Texture::TT_2d_texture:
+      glBindTexture(GL_TEXTURE_2D, 0);
+      break;
+
+    case Texture::TT_3d_texture:
 #ifndef OPENGLES_1
-    if (_glgsg->_supports_3d_texture) {
       glBindTexture(GL_TEXTURE_3D, 0);
-    }
-#endif  // OPENGLES_1
+#endif
+      break;
+
+    case Texture::TT_2d_texture_array:
 #ifndef OPENGLES
-    if (_glgsg->_supports_2d_texture_array) {
       glBindTexture(GL_TEXTURE_2D_ARRAY_EXT, 0);
-    }
 #endif
-    if (_glgsg->_supports_cube_map) {
+      break;
+
+    case Texture::TT_cube_map:
       glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
+      break;
+
+    case Texture::TT_buffer_texture:
+#ifndef OPENGLES
+      glBindTexture(GL_TEXTURE_BUFFER, 0);
+#endif
+      break;
     }
   }
 
@@ -1491,7 +1684,7 @@ update_shader_texture_bindings(ShaderContext *prev) {
   nassertv(texattrib != (TextureAttrib *)NULL);
 
   for (int i = 0; i < (int)_shader->_tex_spec.size(); ++i) {
-    const Shader::ShaderTexSpec &spec = _shader->_tex_spec[i];
+    Shader::ShaderTexSpec &spec = _shader->_tex_spec[i];
     const InternalName *id = spec._name;
     int texunit = spec._stage;
 
@@ -1519,9 +1712,15 @@ update_shader_texture_bindings(ShaderContext *prev) {
     }
 
     if (tex->get_texture_type() != spec._desired_type) {
-      GLCAT.error()
-        << "Sampler type of GLSL shader input '" << *id << "' does not "
-           "match type of texture " << *tex << ".\n";
+      if (id != NULL) {
+        GLCAT.error()
+          << "Sampler type of GLSL shader input '" << *id << "' does not "
+             "match type of texture " << *tex << ".\n";
+      } else {
+        GLCAT.error()
+          << "Sampler type of GLSL shader input p3d_Texture" << texunit
+          << " does not match type of texture " << *tex << ".\n";
+      }
       //TODO: also check whether shadow sampler textures have shadow filter enabled.
     }
 
@@ -1593,7 +1792,7 @@ update_shader_texture_bindings(ShaderContext *prev) {
 //  Description: This subroutine prints the infolog for a shader.
 ////////////////////////////////////////////////////////////////////
 void CLP(ShaderContext)::
-glsl_report_shader_errors(GLuint shader, Shader::ShaderType type) {
+glsl_report_shader_errors(GLuint shader, Shader::ShaderType type, bool fatal) {
   char *info_log;
   GLint length = 0;
   GLint num_chars  = 0;
@@ -1642,6 +1841,9 @@ glsl_report_shader_errors(GLuint shader, Shader::ShaderType type) {
       GLCAT.error(false)
         << fn << "(" << lineno << ") : " << (line.c_str() + prefixlen) << "\n";
 
+    } else if (!fatal) {
+      GLCAT.warning(false) << line << "\n";
+
     } else {
       GLCAT.error(false) << line << "\n";
     }
@@ -1654,7 +1856,7 @@ glsl_report_shader_errors(GLuint shader, Shader::ShaderType type) {
 //  Description: This subroutine prints the infolog for a program.
 ////////////////////////////////////////////////////////////////////
 void CLP(ShaderContext)::
-glsl_report_program_errors(GLuint program) {
+glsl_report_program_errors(GLuint program, bool fatal) {
   char *info_log;
   GLint length = 0;
   GLint num_chars  = 0;
@@ -1664,8 +1866,13 @@ glsl_report_program_errors(GLuint program) {
   if (length > 1) {
     info_log = (char *) alloca(length);
     _glgsg->_glGetProgramInfoLog(program, length, &num_chars, info_log);
+
     if (strcmp(info_log, "Success.\n") != 0 && strcmp(info_log, "No errors.\n") != 0) {
-      GLCAT.error(false) << info_log << "\n";
+      if (!fatal) {
+        GLCAT.warning(false) << info_log << "\n";
+      } else {
+        GLCAT.error(false) << info_log << "\n";
+      }
     }
   }
 }
@@ -1733,7 +1940,7 @@ glsl_compile_shader(Shader::ShaderType type) {
     GLCAT.error()
       << "An error occurred while compiling GLSL shader "
       << _shader->get_filename(type) << ":\n";
-    glsl_report_shader_errors(handle, type);
+    glsl_report_shader_errors(handle, type, true);
     _glgsg->_glDeleteShader(handle);
     _glgsg->report_my_gl_errors();
     return false;
@@ -1743,7 +1950,7 @@ glsl_compile_shader(Shader::ShaderType type) {
   _glsl_shaders.push_back(handle);
 
   // There might be warnings, so report those.
-  glsl_report_shader_errors(handle, type);
+  glsl_report_shader_errors(handle, type, false);
 
   return true;
 }
@@ -1776,9 +1983,8 @@ glsl_compile_and_link() {
     valid &= glsl_compile_shader(Shader::ST_fragment);
   }
 
-#ifdef OPENGLES
-    nassertr(false, false); // OpenGL ES has no geometry shaders.
-#else
+  // OpenGL ES has no geometry shaders.
+#ifndef OPENGLES
   if (!_shader->get_text(Shader::ST_geometry).empty()) {
     valid &= glsl_compile_shader(Shader::ST_geometry);
 
@@ -1810,6 +2016,17 @@ glsl_compile_and_link() {
   //  glsl_report_shader_errors(*it);
   //}
 
+  // Under OpenGL's compatibility profile, we have to make sure that we bind
+  // something to attribute 0.  Make sure that this is the position array.
+  _glgsg->_glBindAttribLocation(_glsl_program, 0, "p3d_Vertex");
+  _glgsg->_glBindAttribLocation(_glsl_program, 0, "vertex");
+
+  // While we're at it, let's also map these to fixed locations.  These
+  // attributes were historically fixed to these locations, so it might
+  // help a buggy driver.
+  _glgsg->_glBindAttribLocation(_glsl_program, 2, "p3d_Normal");
+  _glgsg->_glBindAttribLocation(_glsl_program, 3, "p3d_Color");
+
   // If we requested to retrieve the shader, we should indicate that before linking.
 #if !defined(NDEBUG) && !defined(OPENGLES)
   if (gl_dump_compiled_shaders && _glgsg->_supports_get_program_binary) {
@@ -1823,12 +2040,12 @@ glsl_compile_and_link() {
   _glgsg->_glGetProgramiv(_glsl_program, GL_LINK_STATUS, &status);
   if (status != GL_TRUE) {
     GLCAT.error() << "An error occurred while linking GLSL shader program!\n";
-    glsl_report_program_errors(_glsl_program);
+    glsl_report_program_errors(_glsl_program, true);
     return false;
   }
 
   // Report any warnings.
-  glsl_report_program_errors(_glsl_program);
+  glsl_report_program_errors(_glsl_program, false);
 
   // Dump the binary if requested.
 #if !defined(NDEBUG) && !defined(OPENGLES)

+ 6 - 2
panda/src/glstuff/glShaderContext_src.h

@@ -35,6 +35,8 @@ public:
   ~CLP(ShaderContext)();
   ALLOC_DELETED_CHAIN(CLP(ShaderContext));
 
+  bool get_sampler_texture_type(int &out, GLenum param_type);
+
   INLINE bool valid(void);
   void bind(bool reissue_parameters = true);
   void unbind();
@@ -63,6 +65,7 @@ private:
   //typedef pvector<ParamContext> ParamContexts;
   //ParamContexts _params;
 
+  GLint _color_attrib_index;
   pvector<GLint> _glsl_parameter_map;
   pmap<GLint, GLuint64> _glsl_uniform_handles;
 
@@ -72,9 +75,10 @@ private:
   CLP(GraphicsStateGuardian) *_glgsg;
 
   bool _uses_standard_vertex_arrays;
+  bool _has_divisor;
 
-  void glsl_report_shader_errors(GLuint shader, Shader::ShaderType type);
-  void glsl_report_program_errors(GLuint program);
+  void glsl_report_shader_errors(GLuint shader, Shader::ShaderType type, bool fatal);
+  void glsl_report_program_errors(GLuint program, bool fatal);
   bool glsl_compile_shader(Shader::ShaderType type);
   bool glsl_compile_and_link();
   bool parse_and_set_short_hand_shader_vars(Shader::ShaderArgId &arg_id, Shader *s);

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