Browse Source

Merge branch 'master' into cmake

Sam Edwards 11 years ago
parent
commit
57fb97053b
100 changed files with 2897 additions and 1571 deletions
  1. 8 7
      contrib/src/ai/aiNode.h
  2. 11 4
      direct/src/directscripts/Doxyfile.python
  3. 63 21
      direct/src/directscripts/extract_docs.py
  4. 59 1
      direct/src/filter/CommonFilters.py
  5. 27 17
      direct/src/filter/FilterManager.py
  6. 0 48
      direct/src/filter/filter-ssao.sha
  7. 1 1
      direct/src/motiontrail/cMotionTrail.cxx
  8. 42 45
      direct/src/motiontrail/cMotionTrail.h
  9. 0 21
      direct/src/plugin/FileSpec.py
  10. 0 4
      direct/src/plugin_activex/stdafx.h
  11. 1 1
      direct/src/plugin_installer/make_installer.py
  12. 1 0
      direct/src/task/Task.py
  13. 241 209
      dtool/metalibs/dtoolconfig/pydtool.cxx
  14. 2 2
      dtool/src/cppparser/Sources.pp
  15. 407 382
      dtool/src/cppparser/cppBison.cxx.prebuilt
  16. 84 66
      dtool/src/cppparser/cppBison.h.prebuilt
  17. 49 18
      dtool/src/cppparser/cppBison.yxx
  18. 10 1
      dtool/src/cppparser/cppDeclaration.cxx
  19. 3 4
      dtool/src/cppparser/cppDeclaration.h
  20. 3 3
      dtool/src/cppparser/cppEnumType.cxx
  21. 2 2
      dtool/src/cppparser/cppEnumType.h
  22. 29 2
      dtool/src/cppparser/cppExpression.cxx
  23. 99 0
      dtool/src/cppparser/cppMakeProperty.cxx
  24. 51 0
      dtool/src/cppparser/cppMakeProperty.h
  25. 181 31
      dtool/src/cppparser/cppManifest.cxx
  26. 7 2
      dtool/src/cppparser/cppManifest.h
  27. 220 161
      dtool/src/cppparser/cppPreprocessor.cxx
  28. 5 3
      dtool/src/cppparser/cppPreprocessor.h
  29. 26 1
      dtool/src/cppparser/cppScope.cxx
  30. 3 1
      dtool/src/cppparser/cppScope.h
  31. 3 2
      dtool/src/cppparser/cppTemplateScope.cxx
  32. 3 1
      dtool/src/cppparser/cppTemplateScope.h
  33. 0 4
      dtool/src/cppparser/cppToken.cxx
  34. 1 0
      dtool/src/cppparser/p3cppParser_composite1.cxx
  35. 4 2
      dtool/src/dtoolbase/Sources.pp
  36. 67 37
      dtool/src/dtoolbase/cmath.I
  37. 7 8
      dtool/src/dtoolbase/cmath.h
  38. 2 3
      dtool/src/dtoolbase/dtoolbase.h
  39. 61 0
      dtool/src/dtoolbase/epvector.h
  40. 86 49
      dtool/src/dtoolbase/pstrtod.cxx
  41. 0 42
      dtool/src/dtoolbase/pvector.h
  42. 11 1
      dtool/src/dtoolbase/typeHandle.I
  43. 1 0
      dtool/src/dtoolbase/typeHandle.h
  44. 3 0
      dtool/src/dtoolutil/Sources.pp
  45. 1 0
      dtool/src/dtoolutil/p3dtoolutil_composite2.cxx
  46. 0 0
      dtool/src/dtoolutil/string_utils.I
  47. 0 0
      dtool/src/dtoolutil/string_utils.cxx
  48. 21 21
      dtool/src/dtoolutil/string_utils.h
  49. 9 7
      dtool/src/interrogate/functionRemap.cxx
  50. 77 6
      dtool/src/interrogate/interfaceMaker.cxx
  51. 21 2
      dtool/src/interrogate/interfaceMaker.h
  52. 4 4
      dtool/src/interrogate/interfaceMakerC.cxx
  53. 2 1
      dtool/src/interrogate/interfaceMakerPython.cxx
  54. 176 62
      dtool/src/interrogate/interfaceMakerPythonNative.cxx
  55. 1 1
      dtool/src/interrogate/interfaceMakerPythonNative.h
  56. 9 9
      dtool/src/interrogate/interfaceMakerPythonObj.cxx
  57. 12 12
      dtool/src/interrogate/interfaceMakerPythonSimple.cxx
  58. 99 0
      dtool/src/interrogate/interrogateBuilder.cxx
  59. 6 0
      dtool/src/interrogate/interrogateBuilder.h
  60. 1 1
      dtool/src/interrogatedb/interrogateDatabase.cxx
  61. 21 0
      dtool/src/interrogatedb/interrogateElement.I
  62. 5 0
      dtool/src/interrogatedb/interrogateElement.cxx
  63. 4 0
      dtool/src/interrogatedb/interrogateElement.h
  64. 13 0
      dtool/src/interrogatedb/interrogateType.I
  65. 5 0
      dtool/src/interrogatedb/interrogateType.cxx
  66. 2 0
      dtool/src/interrogatedb/interrogateType.h
  67. 18 0
      dtool/src/interrogatedb/interrogate_interface.cxx
  68. 3 0
      dtool/src/interrogatedb/interrogate_interface.h
  69. 2 0
      dtool/src/pystub/pystub.cxx
  70. 7 6
      makepanda/makepanda.py
  71. 12 3
      makepanda/makepandacore.py
  72. 32 0
      panda/src/bullet/bulletBodyNode.cxx
  73. 2 0
      panda/src/bullet/bulletBodyNode.h
  74. 28 0
      panda/src/bullet/bulletShape.cxx
  75. 3 0
      panda/src/bullet/bulletShape.h
  76. 4 3
      panda/src/collide/collisionHandlerPusher.cxx
  77. 3 2
      panda/src/collide/collisionPolygon.cxx
  78. 38 0
      panda/src/display/displayRegion.I
  79. 5 3
      panda/src/display/displayRegion.cxx
  80. 9 3
      panda/src/display/displayRegion.h
  81. 3 3
      panda/src/display/graphicsBuffer.cxx
  82. 1 1
      panda/src/display/graphicsBuffer.h
  83. 27 8
      panda/src/display/graphicsOutput.I
  84. 11 12
      panda/src/display/graphicsOutput.cxx
  85. 8 8
      panda/src/display/graphicsOutput.h
  86. 1 2
      panda/src/display/graphicsWindow.cxx
  87. 17 19
      panda/src/display/parasiteBuffer.cxx
  88. 4 5
      panda/src/dxgsg8/wdxGraphicsBuffer8.cxx
  89. 12 13
      panda/src/dxgsg9/wdxGraphicsBuffer9.cxx
  90. 1 0
      panda/src/egg/eggGroupNode.cxx
  91. 1 1
      panda/src/egg/eggMorphList.h
  92. 1 1
      panda/src/egg/eggSwitchCondition.h
  93. 2 0
      panda/src/express/config_express.N
  94. 12 9
      panda/src/glstuff/glGraphicsBuffer_src.cxx
  95. 155 78
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  96. 3 0
      panda/src/glstuff/glGraphicsStateGuardian_src.h
  97. 85 47
      panda/src/glstuff/glShaderContext_src.cxx
  98. 0 1
      panda/src/glstuff/glTextureContext_src.I
  99. 13 4
      panda/src/glstuff/glTextureContext_src.cxx
  100. 1 6
      panda/src/glstuff/glTextureContext_src.h

+ 8 - 7
contrib/src/ai/aiNode.h

@@ -29,13 +29,7 @@
 //               on the mesh.
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDAAI AINode {
-PUBLISHED:
-  // This variable specifies whether the node is an obtacle or not.
-  // Used for dynamic obstacle addition to the environment.
-  // obstacle = false
-  // navigational = true
-  bool _type;
-
+public:
   // This variable specifies the node status whether open, close
   // or neutral.
   // open = belongs to _open_list.
@@ -48,6 +42,12 @@ PUBLISHED:
   };
   Status _status;
 
+  // This variable specifies whether the node is an obtacle or not.
+  // Used for dynamic obstacle addition to the environment.
+  // obstacle = false
+  // navigational = true
+  bool _type;
+
   // The score is used to compute the traversal expense to nodes
   // when using A*.
   // _score = _cost + heuristic
@@ -76,6 +76,7 @@ PUBLISHED:
   // is written into navmesh.csv file.
   AINode *_next;
 
+PUBLISHED:
   AINode(int grid_x, int grid_y, LVecBase3f pos, float w, float l, float h);
   ~AINode();
 

+ 11 - 4
direct/src/directscripts/Doxyfile.python

@@ -176,7 +176,7 @@ QT_AUTOBRIEF           = YES
 # The new default is to treat a multi-line C++ comment block as a detailed 
 # description. Set this tag to YES if you prefer the old behaviour instead.
 
-MULTILINE_CPP_IS_BRIEF = NO
+MULTILINE_CPP_IS_BRIEF = YES
 
 # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
 # member inherits the documentation from any documented member that it 
@@ -612,8 +612,7 @@ WARN_LOGFILE           =
 # directories like "/usr/src/myproject". Separate the files or directories 
 # with spaces.
 
-INPUT                  = pandadoc.hpp \
-                         direct
+INPUT                  = pandadoc.hpp built/direct
 
 # This tag can be used to specify the character encoding of the source files 
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is 
@@ -644,7 +643,15 @@ RECURSIVE              = YES
 # excluded from the INPUT source files. This way you can easily exclude a 
 # subdirectory from a directory tree whose root is specified with the INPUT tag.
 
-EXCLUDE                = direct/src/test
+EXCLUDE                = built/direct/test \
+                         built/direct/plugin \
+                         built/direct/plugin_npapi \
+                         built/direct/plugin_activex \
+                         built/direct/plugin_installer \
+                         built/direct/plugin_standalone \
+                         built/direct/extensions \
+                         built/direct/extensions_native \
+                         built/direct/directscripts
 
 # The EXCLUDE_SYMLINKS tag can be used select whether or not files or 
 # directories that are symbolic links (a Unix file system feature) are excluded 

+ 63 - 21
direct/src/directscripts/extract_docs.py

@@ -17,15 +17,34 @@ 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.\"""".split("\n")
 
-libraries = {}
-for m, lib in panda3d.modules.items():
-    if not isinstance(lib, str):
-        for l in lib:
-            libraries[l.replace("lib", "")] = m
+def comment(code):
+    if not code:
+        return ""
+
+    comment = ''
+
+    empty_line = False
+    for line in code.splitlines(False):
+        line = line.strip('\t\n /')
+        if line:
+            if empty_line:
+                # New paragraph.
+                comment += '\n\n'
+            elif comment:
+                comment += '\n'
+            comment += '/// ' + line
+        else:
+            empty_line = True
+
+    if comment:
+        return comment
     else:
-        libraries[lib.replace("lib", "")] = m
+        return ''
+
+def block_comment(code):
+    if not code:
+        return ""
 
-def comment(code):
     lines = code.split("\n")
     newlines = []
     indent = 0
@@ -38,18 +57,18 @@ def comment(code):
         line = line.rstrip()
         strline = line.lstrip('/ \t')
         if reading_desc:
-            newlines.append(line[min(indent, len(line) - len(strline)):])
+            newlines.append('/// ' + line[min(indent, len(line) - len(strline)):])
         else:
             # A "Description:" text starts the description.
             if strline.startswith("Description"):
                 strline = strline[11:].lstrip(': \t')
                 indent = len(line) - len(strline)
                 reading_desc = True
-                newlines.append(strline)
+                newlines.append('/// ' + strline)
 
-    newcode = "\n".join(newlines)
+    newcode = '\n'.join(newlines)
     if len(newcode) > 0:
-        return "/** " + newcode + " */"
+        return newcode
     else:
         return ""
 
@@ -67,6 +86,11 @@ def translateFunctionName(name):
     return new
 
 def translated_type_name(type):
+    if interrogate_type_is_atomic(type):
+        token = interrogate_type_atomic_token(type)
+        if token == 7:
+            return 'str'
+
     typename = interrogate_type_name(type)
     typename = typename.replace("< ", "").replace(" >", "")
     return typename
@@ -76,13 +100,24 @@ def translateTypeSpec(name):
     name = name.replace("BitMask< unsigned int, 32 >", "BitMask32")
     name = name.replace("atomic ", "")
     name = name.replace("< ", "").replace(" >", "")
+    if name == '_object':
+        name = 'object'
+    elif name == '_typeobject':
+        name = 'type'
     return name
 
+def processElement(handle, element):
+    if interrogate_element_has_comment(element):
+        print >>handle, comment(interrogate_element_comment(element))
+
+    print >>handle, translateTypeSpec(translated_type_name(interrogate_element_type(element))),
+    print >>handle, interrogate_element_name(element) + ';'
+
 def processFunction(handle, function, isConstructor = False):
     for i_wrapper in xrange(interrogate_function_number_of_python_wrappers(function)):
         wrapper = interrogate_function_python_wrapper(function, i_wrapper)
         if interrogate_wrapper_has_comment(wrapper):
-            print >>handle, comment(interrogate_wrapper_comment(wrapper))
+            print >>handle, block_comment(interrogate_wrapper_comment(wrapper))
         
         if not isConstructor:
             if not interrogate_wrapper_number_of_parameters(wrapper) > 0 or not interrogate_wrapper_parameter_is_this(wrapper, 0):
@@ -114,11 +149,14 @@ def processType(handle, type):
     derivations = [ translated_type_name(interrogate_type_get_derivation(type, n)) for n in range(interrogate_type_number_of_derivations(type)) ]
     
     if interrogate_type_has_comment(type):
-        print >>handle, comment(interrogate_type_comment(type))
+        print >>handle, block_comment(interrogate_type_comment(type))
     
     if interrogate_type_is_enum(type):
         print >>handle, "enum %s {" % typename
         for i_value in range(interrogate_type_number_of_enum_values(type)):
+            docstring = comment(interrogate_type_enum_value_comment(type, i_value))
+            if docstring:
+                print >>handle, docstring
             print >>handle, translateFunctionName(interrogate_type_enum_value_name(type, i_value)), "=", interrogate_type_enum_value(type, i_value), ","
     else:
         if interrogate_type_is_struct(type):
@@ -148,6 +186,9 @@ def processType(handle, type):
     
     for i_method in xrange(interrogate_type_number_of_make_seqs(type)):
         print >>handle, "list", translateFunctionName(interrogate_make_seq_seq_name(interrogate_type_get_make_seq(type, i_method))), "();"
+
+    for i_element in xrange(interrogate_type_number_of_elements(type)):
+        processElement(handle, interrogate_type_get_element(type, i_element))
     
     print >>handle, "};"
 
@@ -161,20 +202,22 @@ if __name__ == "__main__":
     interrogate_add_search_directory(os.path.join(os.path.dirname(pandac.__file__), "..", "..", "etc"))
     interrogate_add_search_directory(os.path.join(os.path.dirname(pandac.__file__), "input"))
 
-    try:
-        panda3d.__load__()
-    except ImportError, msg:
-        print msg
+    import panda3d.core
+
+    for lib in os.listdir(os.path.dirname(panda3d.__file__)):
+        if lib.endswith(('.pyd', '.so')) and not lib.startswith('core.'):
+            __import__('panda3d.' + os.path.splitext(lib)[0])
 
     lastpkg = None
     for i_type in xrange(interrogate_number_of_global_types()):
         type = interrogate_get_global_type(i_type)
 
         if interrogate_type_has_module_name(type):
-            package = libraries[interrogate_type_module_name(type)]
+            package = interrogate_type_module_name(type)
             if lastpkg != package:
-                print >>handle, "}"
-                print >>handle, "namespace panda3d.%s {" % package
+                if lastpkg is not None:
+                    print >>handle, "}"
+                print >>handle, "namespace %s {" % package
                 lastpkg = package
 
             processType(handle, type)
@@ -184,4 +227,3 @@ if __name__ == "__main__":
     if lastpkg is not None:
         print >>handle, "}"
     handle.close()
-

+ 59 - 1
direct/src/filter/CommonFilters.py

@@ -39,6 +39,60 @@ float cartoon_thresh = saturate(dot(cartoon_mx - cartoon_mn, float4(3,3,0,0)) -
 o_color = lerp(o_color, k_cartooncolor, cartoon_thresh);
 """
 
+# Some GPUs do not support variable-length loops.
+#
+# We fill in the actual value of numsamples in the loop limit
+# when the shader is configured.
+#
+SSAO_BODY="""//Cg
+
+void vshader(float4 vtx_position : POSITION,
+             out float4 l_position : POSITION,
+             out float2 l_texcoord : TEXCOORD0,
+             out float2 l_texcoordD : TEXCOORD1,
+             out float2 l_texcoordN : TEXCOORD2,
+             uniform float4 texpad_depth,
+             uniform float4 texpad_normal,
+             uniform float4x4 mat_modelproj)
+{
+  l_position = mul(mat_modelproj, vtx_position);
+  l_texcoord = vtx_position.xz;
+  l_texcoordD = (vtx_position.xz * texpad_depth.xy) + texpad_depth.xy;
+  l_texcoordN = (vtx_position.xz * texpad_normal.xy) + texpad_normal.xy;
+}
+
+float3 sphere[16] = float3[](float3(0.53812504, 0.18565957, -0.43192),float3(0.13790712, 0.24864247, 0.44301823),float3(0.33715037, 0.56794053, -0.005789503),float3(-0.6999805, -0.04511441, -0.0019965635),float3(0.06896307, -0.15983082, -0.85477847),float3(0.056099437, 0.006954967, -0.1843352),float3(-0.014653638, 0.14027752, 0.0762037),float3(0.010019933, -0.1924225, -0.034443386),float3(-0.35775623, -0.5301969, -0.43581226),float3(-0.3169221, 0.106360726, 0.015860917),float3(0.010350345, -0.58698344, 0.0046293875),float3(-0.08972908, -0.49408212, 0.3287904),float3(0.7119986, -0.0154690035, -0.09183723),float3(-0.053382345, 0.059675813, -0.5411899),float3(0.035267662, -0.063188605, 0.54602677),float3(-0.47761092, 0.2847911, -0.0271716));
+
+void fshader(out float4 o_color : COLOR,
+             uniform float4 k_params1,
+             uniform float4 k_params2,
+             float2 l_texcoord : TEXCOORD0,
+             float2 l_texcoordD : TEXCOORD1,
+             float2 l_texcoordN : TEXCOORD2,
+             uniform sampler2D k_random : TEXUNIT0,
+             uniform sampler2D k_depth : TEXUNIT1,
+             uniform sampler2D k_normal : TEXUNIT2)
+{
+  float pixel_depth = tex2D(k_depth, l_texcoordD).a;
+  float3 pixel_normal = (tex2D(k_normal, l_texcoordN).xyz * 2.0 - 1.0);
+  float3 random_vector = normalize((tex2D(k_random, l_texcoord * 18.0 + pixel_depth + pixel_normal.xy).xyz * 2.0) - float3(1.0)).xyz;
+  float occlusion = 0.0;
+  float radius = k_params1.z / pixel_depth;
+  float depth_difference;
+  float3 sample_normal;
+  float3 ray;
+  for(int i = 0; i < %d; ++i) {
+   ray = radius * reflect(sphere[i], random_vector);
+   sample_normal = (tex2D(k_normal, l_texcoordN + ray.xy).xyz * 2.0 - 1.0);
+   depth_difference =  (pixel_depth - tex2D(k_depth,l_texcoordD + ray.xy).r);
+   occlusion += step(k_params2.y, depth_difference) * (1.0 - dot(sample_normal.xyz, pixel_normal)) * (1.0 - smoothstep(k_params2.y, k_params2.x, depth_difference));
+  }
+  o_color.rgb = 1.0 + (occlusion * k_params1.y);
+  o_color.a = 1.0;
+}
+"""
+
+
 class FilterConfig:
     pass
 
@@ -140,7 +194,7 @@ class CommonFilters:
                 self.ssao[0].setShaderInput("depth", self.textures["depth"])
                 self.ssao[0].setShaderInput("normal", self.textures["aux"])
                 self.ssao[0].setShaderInput("random", loader.loadTexture("maps/random.rgb"))
-                self.ssao[0].setShader(self.loadShader("filter-ssao.sha"))
+                self.ssao[0].setShader(Shader.make(SSAO_BODY % configuration["AmbientOcclusion"].numsamples))
                 self.ssao[1].setShaderInput("src", ssao0)
                 self.ssao[1].setShader(self.loadShader("filter-blurx.sha"))
                 self.ssao[2].setShaderInput("src", ssao1)
@@ -431,6 +485,10 @@ class CommonFilters:
 
     def setAmbientOcclusion(self, numsamples = 16, radius = 0.05, amount = 2.0, strength = 0.01, falloff = 0.000002):
         fullrebuild = (("AmbientOcclusion" in self.configuration) == False)
+
+        if (not fullrebuild):
+            fullrebuild = (numsamples != self.configuration["AmbientOcclusion"].numsamples)
+
         newconfig = FilterConfig()
         newconfig.numsamples = numsamples
         newconfig.radius = radius

+ 27 - 17
direct/src/filter/FilterManager.py

@@ -42,18 +42,18 @@ class FilterManager(DirectObject):
 
         # Create the notify category
 
-        if (FilterManager.notify == None):
+        if FilterManager.notify is None:
             FilterManager.notify = directNotify.newCategory("FilterManager")
 
         # Find the appropriate display region.
         
         region = None
-        for i in range(win.getNumDisplayRegions()):
-            dr = win.getDisplayRegion(i)
+        for dr in win.getDisplayRegions():
             drcam = dr.getCamera()
-            if (drcam == cam): region=dr
+            if drcam == cam:
+                region = dr
 
-        if (region == None):
+        if region is None:
             self.notify.error('Could not find appropriate DisplayRegion to filter')
             return False
         
@@ -218,16 +218,18 @@ class FilterManager(DirectObject):
         
         self.region.setCamera(quadcam)
 
-        dr = buffer.getDisplayRegion(0)
-        self.setStackedClears(dr, self.rclears, self.wclears)
+        self.setStackedClears(buffer, self.rclears, self.wclears)
         if (auxtex0):
-            dr.setClearActive(GraphicsOutput.RTPAuxRgba0, 1)
-            dr.setClearValue(GraphicsOutput.RTPAuxRgba0, Vec4(0.5, 0.5, 1.0, 0.0))
+            buffer.setClearActive(GraphicsOutput.RTPAuxRgba0, 1)
+            buffer.setClearValue(GraphicsOutput.RTPAuxRgba0, Vec4(0.5, 0.5, 1.0, 0.0))
         if (auxtex1):
-            dr.setClearActive(GraphicsOutput.RTPAuxRgba1, 1)
+            buffer.setClearActive(GraphicsOutput.RTPAuxRgba1, 1)
         self.region.disableClears()
         if (self.isFullscreen()):
             self.win.disableClears()
+
+        dr = buffer.makeDisplayRegion()
+        dr.disableClears()
         dr.setCamera(self.camera)
         dr.setActive(1)
 
@@ -249,7 +251,7 @@ class FilterManager(DirectObject):
         winx, winy = self.getScaledSize(mul, div, align)
         
         depthbits = bool(depthtex != None)
-        
+
         buffer = self.createBuffer("filter-stage", winx, winy, texgroup, depthbits)
 
         if (buffer == None):
@@ -269,9 +271,18 @@ class FilterManager(DirectObject):
         lens.setNearFar(-1000, 1000)
         quadcamnode.setLens(lens)
         quadcam = quad.attachNewNode(quadcamnode)
-        
-        buffer.getDisplayRegion(0).setCamera(quadcam)
-        buffer.getDisplayRegion(0).setActive(1)
+
+        dr = buffer.makeDisplayRegion((0, 1, 0, 1))
+        dr.disableClears()
+        dr.setCamera(quadcam)
+        dr.setActive(True)
+        dr.setScissorEnabled(False)
+
+        # This clear stage is important if the buffer is padded, so that
+        # any pixels accidentally sampled in the padded region won't
+        # be reading from unititialised memory.
+        buffer.setClearColor((0, 0, 0, 1))
+        buffer.setClearColorActive(True)
 
         self.buffers.append(buffer)
         self.sizes.append((mul, div, align))
@@ -283,7 +294,8 @@ class FilterManager(DirectObject):
 
         winprops = WindowProperties()
         winprops.setSize(xsize, ysize)
-        props = FrameBufferProperties()
+        props = FrameBufferProperties(self.win.getFbProperties())
+        props.setBackBuffers(0)
         props.setRgbColor(1)
         props.setDepthBits(depthbits)
         depthtex, colortex, auxtex0, auxtex1 = texgroup
@@ -307,7 +319,6 @@ class FilterManager(DirectObject):
             buffer.addRenderTexture(auxtex1, GraphicsOutput.RTMBindOrCopy, GraphicsOutput.RTPAuxRgba1)
         buffer.setSort(self.nextsort)
         buffer.disableClears()
-        buffer.getDisplayRegion(0).disableClears()
         self.nextsort += 1
         return buffer
 
@@ -339,4 +350,3 @@ class FilterManager(DirectObject):
         self.nextsort = self.win.getSort() - 1000
         self.basex = 0
         self.basey = 0
-

+ 0 - 48
direct/src/filter/filter-ssao.sha

@@ -1,48 +0,0 @@
-//Cg
-
-
-void vshader(float4 vtx_position : POSITION,
-             out float4 l_position : POSITION,
-             out float2 l_texcoord : TEXCOORD0,
-             out float2 l_texcoordD : TEXCOORD1,
-             out float2 l_texcoordN : TEXCOORD2,
-             uniform float4 texpad_depth,
-             uniform float4 texpad_normal,
-             uniform float4x4 mat_modelproj)
-{
-  l_position = mul(mat_modelproj, vtx_position);
-  l_texcoord = vtx_position.xz;
-  l_texcoordD = (vtx_position.xz * texpad_depth.xy) + texpad_depth.xy;
-  l_texcoordN = (vtx_position.xz * texpad_normal.xy) + texpad_normal.xy;
-}
-
-float3 sphere[16] = float3[](float3(0.53812504, 0.18565957, -0.43192),float3(0.13790712, 0.24864247, 0.44301823),float3(0.33715037, 0.56794053, -0.005789503),float3(-0.6999805, -0.04511441, -0.0019965635),float3(0.06896307, -0.15983082, -0.85477847),float3(0.056099437, 0.006954967, -0.1843352),float3(-0.014653638, 0.14027752, 0.0762037),float3(0.010019933, -0.1924225, -0.034443386),float3(-0.35775623, -0.5301969, -0.43581226),float3(-0.3169221, 0.106360726, 0.015860917),float3(0.010350345, -0.58698344, 0.0046293875),float3(-0.08972908, -0.49408212, 0.3287904),float3(0.7119986, -0.0154690035, -0.09183723),float3(-0.053382345, 0.059675813, -0.5411899),float3(0.035267662, -0.063188605, 0.54602677),float3(-0.47761092, 0.2847911, -0.0271716));
-
-void fshader(out float4 o_color : COLOR,
-             uniform float4 k_params1,
-             uniform float4 k_params2,
-             float2 l_texcoord : TEXCOORD0,
-             float2 l_texcoordD : TEXCOORD1,
-             float2 l_texcoordN : TEXCOORD2,
-             uniform sampler2D k_random : TEXUNIT0,
-             uniform sampler2D k_depth : TEXUNIT1,
-             uniform sampler2D k_normal : TEXUNIT2)
-{
-  float pixel_depth = tex2D(k_depth, l_texcoordD).a;
-  float3 pixel_normal = (tex2D(k_normal, l_texcoordN).xyz * 2.0 - 1.0);
-  float3 random_vector = normalize((tex2D(k_random, l_texcoord * 18.0 + pixel_depth + pixel_normal.xy).xyz * 2.0) - float3(1.0)).xyz;
-  float occlusion = 0.0;
-  float radius = k_params1.z / pixel_depth;
-  float depth_difference;
-  float3 sample_normal;
-  float3 ray;
-  for(int i = 0; i < k_params1.x; ++i) {
-   ray = radius * reflect(sphere[i], random_vector);
-   sample_normal = (tex2D(k_normal, l_texcoordN + ray.xy).xyz * 2.0 - 1.0);
-   depth_difference =  (pixel_depth - tex2D(k_depth,l_texcoordD + ray.xy).r);
-   occlusion += step(k_params2.y, depth_difference) * (1.0 - dot(sample_normal.xyz, pixel_normal)) * (1.0 - smoothstep(k_params2.y, k_params2.x, depth_difference));
-  }
-  o_color.rgb = 1.0 + (occlusion * k_params1.y);
-  o_color.a = 1.0;
-}
-

+ 1 - 1
direct/src/motiontrail/cMotionTrail.cxx

@@ -114,7 +114,7 @@ enable (bool enable) {
 //  Description: Set the GeomNode.
 ////////////////////////////////////////////////////////////////////
 void CMotionTrail::
-set_geom_node (PT(GeomNode) geom_node) {
+set_geom_node (GeomNode *geom_node) {
   _geom_node = geom_node;
 }
 

+ 42 - 45
direct/src/motiontrail/cMotionTrail.h

@@ -24,7 +24,7 @@
 #include "luse.h"
 #include "nurbsCurveEvaluator.h"
 #include "plist.h"
-#include "pvector.h"
+#include "epvector.h"
 
 class CMotionTrailVertex {
 public:
@@ -32,7 +32,7 @@ public:
   LVecBase4 _start_color;
   LVecBase4 _end_color;
   PN_stdfloat _v;
-  
+
   PT(NurbsCurveEvaluator) _nurbs_curve_evaluator;
 };
 
@@ -44,71 +44,68 @@ public:
 
 ////////////////////////////////////////////////////////////////////
 //       Class : CMotionTrail
-// Description : The method used in creating the motion trail is 
-//               based on taking samples of time and transformations 
+// Description : The method used in creating the motion trail is
+//               based on taking samples of time and transformations
 //               (the position and orientation matrix) in real-time.
-//               The method also requires a number of vertices 
-//               (positions) that determines "shape" of the motion 
-//               trail (i.e. the edge of a blade).  A start color 
-//               and end color is also required for each vertex. 
+//               The method also requires a number of vertices
+//               (positions) that determines "shape" of the motion
+//               trail (i.e. the edge of a blade).  A start color
+//               and end color is also required for each vertex.
 //               The color is interpolated as function of time.
 //               The colors are typically used to fade the motion
 //               trail so the end color is typically black.
 //
-//               The vertices are submitted via the "add_vertex" 
-//               function.  For each frame, a sample is submited via 
-//               the "update_motion_trail" function.  During the 
-//               "update_motion_trail" function, the motion trail 
-//               geometry is created dynamically from the sample 
-//               history and the vertices.  
+//               The vertices are submitted via the "add_vertex"
+//               function.  For each frame, a sample is submited via
+//               the "update_motion_trail" function.  During the
+//               "update_motion_trail" function, the motion trail
+//               geometry is created dynamically from the sample
+//               history and the vertices.
 //
-//               The user must specifiy a GeomNode via 
+//               The user must specifiy a GeomNode via
 //               "set_geom_node".
 //
-//               The duration of the sample history is specified by 
-//               a time window. A larger time window creates longer 
-//               motion trails (given constant speed).  Samples that 
-//               are no longer within the time window are 
+//               The duration of the sample history is specified by
+//               a time window. A larger time window creates longer
+//               motion trails (given constant speed).  Samples that
+//               are no longer within the time window are
 //               automatically discarded.
 //
-//               The nurbs option can be used to create smooth 
-//               interpolated curves from the samples.  The nurbs 
-//               option is useful for animations that lack sampling 
-//               to begin with, animations that move very quickly, 
+//               The nurbs option can be used to create smooth
+//               interpolated curves from the samples.  The nurbs
+//               option is useful for animations that lack sampling
+//               to begin with, animations that move very quickly,
 //               or low frame rates.
 //
-//               The texture option be used to create variation to 
-//               the motion trail.  The u coordinate of the texture 
-//               corresponds to time and the v coordinate 
+//               The texture option be used to create variation to
+//               the motion trail.  The u coordinate of the texture
+//               corresponds to time and the v coordinate
 //               corresponds to the "shape" of the motion trail.
 ////////////////////////////////////////////////////////////////////
-
 class EXPCL_DIRECT CMotionTrail : public TypedReferenceCount {
-
 PUBLISHED:
+  CMotionTrail();
+  ~CMotionTrail();
 
-  CMotionTrail ( );
-  ~CMotionTrail ( );
+  void reset();
+  void reset_vertex_list();
 
-  void reset ( );  
-  void reset_vertex_list ( );
+  void enable(bool enable);
 
-  void enable (bool enable);
+  void set_geom_node(GeomNode *geom_node);
+  void add_vertex(LVector4 *vertex, LVector4 *start_color, LVector4 *end_color, PN_stdfloat v);
 
-  void set_geom_node (PT(GeomNode) geom_node);
-  void add_vertex (LVector4 *vertex, LVector4 *start_color, LVector4 *end_color, PN_stdfloat v);
+  void set_parameters(PN_stdfloat sampling_time, PN_stdfloat time_window, bool use_texture, bool calculate_relative_matrix, bool use_nurbs, PN_stdfloat resolution_distance);
 
-  void set_parameters (PN_stdfloat sampling_time, PN_stdfloat time_window, bool use_texture, bool calculate_relative_matrix, bool use_nurbs, PN_stdfloat resolution_distance);
-
-  int check_for_update (PN_stdfloat current_time);
-  void update_motion_trail (PN_stdfloat current_time, LMatrix4 *transform);
+  int check_for_update(PN_stdfloat current_time);
+  void update_motion_trail(PN_stdfloat current_time, LMatrix4 *transform);
 
 public:
 
-  void begin_geometry ( );
-  void add_geometry_quad (LVector3 &v0, LVector3 &v1, LVector3 &v2, LVector3 &v3, LVector4 &c0, LVector4 &c1, LVector4 &c2, LVector4 &c3, LVector2 &t0, LVector2 &t1, LVector2 &t2, LVector2 &t3);
-  void add_geometry_quad (LVector4 &v0, LVector4 &v1, LVector4 &v2, LVector4 &v3, LVector4 &c0, LVector4 &c1, LVector4 &c2, LVector4 &c3, LVector2 &t0, LVector2 &t1, LVector2 &t2, LVector2 &t3);
-  void end_geometry ( );
+  void begin_geometry();
+  void add_geometry_quad(LVector3 &v0, LVector3 &v1, LVector3 &v2, LVector3 &v3, LVector4 &c0, LVector4 &c1, LVector4 &c2, LVector4 &c3, LVector2 &t0, LVector2 &t1, LVector2 &t2, LVector2 &t3);
+  void add_geometry_quad(LVector4 &v0, LVector4 &v1, LVector4 &v2, LVector4 &v3, LVector4 &c0, LVector4 &c1, LVector4 &c2, LVector4 &c3, LVector2 &t0, LVector2 &t1, LVector2 &t2, LVector2 &t3);
+  void end_geometry();
 
   int _active;
   int _enable;
@@ -143,14 +140,14 @@ public:
 
   // geom
   PT(GeomNode) _geom_node;
-      
+
   // real-time data
   int _vertex_index;
   PT(GeomVertexData) _vertex_data;
   GeomVertexWriter _vertex_writer;
   GeomVertexWriter _color_writer;
   GeomVertexWriter _texture_writer;
-  PT(GeomTriangles) _triangles;  
+  PT(GeomTriangles) _triangles;
 
   CMotionTrailVertex *_vertex_array;
 

+ 0 - 21
direct/src/plugin/FileSpec.py

@@ -1,21 +0,0 @@
-from pandac.PandaModules import HashVal
-
-class FileSpec:
-    """ Used by make_package and make_contents.  Represents a single
-    file in the directory, and its associated timestamp, size, and md5
-    hash. """
-    
-    def __init__(self, filename, pathname):
-        self.filename = filename
-        self.pathname = pathname
-
-        self.size = pathname.getFileSize()
-        self.timestamp = pathname.getTimestamp()
-
-        hv = HashVal()
-        hv.hashFile(pathname)
-        self.hash = hv.asHex()
-
-    def getParams(self):
-        return 'filename="%s" size="%s" timestamp="%s" hash="%s"' % (
-            self.filename, self.size, self.timestamp, self.hash)

+ 0 - 4
direct/src/plugin_activex/stdafx.h

@@ -35,10 +35,6 @@
 #include <afxcmn.h>         // MFC support for Windows Common Controls
 #endif // _AFX_NO_AFXCMN_SUPPORT
 
-// Delete the two includes below if you do not wish to use the MFC
-//  database classes
-#include <afxdb.h>          // MFC database classes
-#include <afxdao.h>         // MFC DAO database classes
 #include <afxwin.h>
 
 #include <dispex.h>

+ 1 - 1
direct/src/plugin_installer/make_installer.py

@@ -441,7 +441,7 @@ def makeInstaller():
         if not os.path.exists(dst_panda3dapp): os.makedirs(os.path.dirname(dst_panda3dapp))
         shutil.copytree(pluginFiles[npapi], dst_npapi)
         shutil.copyfile(pluginFiles[panda3d], dst_panda3d)
-        os.chmod(dst_panda3d, 0o755)
+        os.chmod(dst_panda3d, 493) # 0o755
         shutil.copytree(pluginFiles[panda3dapp], dst_panda3dapp)
         
         tmpresdir = tempfile.mktemp('', 'p3d-resources')

+ 1 - 0
direct/src/task/Task.py

@@ -136,6 +136,7 @@ class TaskManager:
 
     def destroy(self):
         # This should be safe to call multiple times.
+        self.running = False
         self.notify.info("TaskManager.destroy()")
         self.destroyed = True
         self._frameProfileQueue.clear()

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


+ 2 - 2
dtool/src/cppparser/Sources.pp

@@ -15,7 +15,7 @@
      cppExpressionParser.h cppExtensionType.h cppFile.h  \
      cppFunctionGroup.h cppFunctionType.h cppGlobals.h  \
      cppIdentifier.h cppInstance.h cppInstanceIdentifier.h  \
-     cppMakeSeq.h cppManifest.h \
+     cppMakeProperty.h cppMakeSeq.h cppManifest.h \
      cppNameComponent.h cppNamespace.h  \
      cppParameterList.h cppParser.h cppPointerType.h  \
      cppPreprocessor.h cppReferenceType.h cppScope.h  \
@@ -31,7 +31,7 @@
      cppExtensionType.cxx cppFile.cxx cppFunctionGroup.cxx  \
      cppFunctionType.cxx cppGlobals.cxx cppIdentifier.cxx  \
      cppInstance.cxx cppInstanceIdentifier.cxx \
-     cppMakeSeq.cxx cppManifest.cxx  \
+     cppMakeProperty.cxx cppMakeSeq.cxx cppManifest.cxx  \
      cppNameComponent.cxx cppNamespace.cxx cppParameterList.cxx  \
      cppParser.cxx cppPointerType.cxx cppPreprocessor.cxx  \
      cppReferenceType.cxx cppScope.cxx cppSimpleType.cxx  \

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


+ 84 - 66
dtool/src/cppparser/cppBison.h.prebuilt

@@ -1,10 +1,8 @@
+/* A Bison parser, made by GNU Bison 2.7.  */
 
-/* A Bison parser, made by GNU Bison 2.4.1.  */
-
-/* Skeleton interface for Bison's Yacc-like parsers in C
+/* Bison interface for Yacc-like parsers in C
    
-      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
-   Free Software Foundation, Inc.
+      Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -32,6 +30,15 @@
    This special exception was added by the Free Software Foundation in
    version 2.2 of Bison.  */
 
+#ifndef YY_CPPYY_BUILT_TMP_CPPBISON_YXX_H_INCLUDED
+# define YY_CPPYY_BUILT_TMP_CPPBISON_YXX_H_INCLUDED
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int cppyydebug;
+#endif
 
 /* Tokens.  */
 #ifndef YYTOKENTYPE
@@ -79,35 +86,35 @@
      XOREQUAL = 295,
      LSHIFTEQUAL = 296,
      RSHIFTEQUAL = 297,
-     TOKENPASTE = 298,
-     KW_BEGIN_PUBLISH = 299,
-     KW_BLOCKING = 300,
-     KW_BOOL = 301,
-     KW_CATCH = 302,
-     KW_CHAR = 303,
-     KW_WCHAR_T = 304,
-     KW_CLASS = 305,
-     KW_CONST = 306,
-     KW_DELETE = 307,
-     KW_DOUBLE = 308,
-     KW_DYNAMIC_CAST = 309,
-     KW_ELSE = 310,
-     KW_END_PUBLISH = 311,
-     KW_ENUM = 312,
-     KW_EXTENSION = 313,
-     KW_EXTERN = 314,
-     KW_EXPLICIT = 315,
-     KW_PUBLISHED = 316,
-     KW_FALSE = 317,
-     KW_FLOAT = 318,
-     KW_FRIEND = 319,
-     KW_FOR = 320,
-     KW_GOTO = 321,
-     KW_IF = 322,
-     KW_INLINE = 323,
-     KW_INT = 324,
-     KW_LONG = 325,
-     KW_LONGLONG = 326,
+     KW_BEGIN_PUBLISH = 298,
+     KW_BLOCKING = 299,
+     KW_BOOL = 300,
+     KW_CATCH = 301,
+     KW_CHAR = 302,
+     KW_WCHAR_T = 303,
+     KW_CLASS = 304,
+     KW_CONST = 305,
+     KW_DELETE = 306,
+     KW_DOUBLE = 307,
+     KW_DYNAMIC_CAST = 308,
+     KW_ELSE = 309,
+     KW_END_PUBLISH = 310,
+     KW_ENUM = 311,
+     KW_EXTENSION = 312,
+     KW_EXTERN = 313,
+     KW_EXPLICIT = 314,
+     KW_PUBLISHED = 315,
+     KW_FALSE = 316,
+     KW_FLOAT = 317,
+     KW_FRIEND = 318,
+     KW_FOR = 319,
+     KW_GOTO = 320,
+     KW_IF = 321,
+     KW_INLINE = 322,
+     KW_INT = 323,
+     KW_LONG = 324,
+     KW_LONGLONG = 325,
+     KW_MAKE_PROPERTY = 326,
      KW_MAKE_SEQ = 327,
      KW_MUTABLE = 328,
      KW_NAMESPACE = 329,
@@ -183,35 +190,35 @@
 #define XOREQUAL 295
 #define LSHIFTEQUAL 296
 #define RSHIFTEQUAL 297
-#define TOKENPASTE 298
-#define KW_BEGIN_PUBLISH 299
-#define KW_BLOCKING 300
-#define KW_BOOL 301
-#define KW_CATCH 302
-#define KW_CHAR 303
-#define KW_WCHAR_T 304
-#define KW_CLASS 305
-#define KW_CONST 306
-#define KW_DELETE 307
-#define KW_DOUBLE 308
-#define KW_DYNAMIC_CAST 309
-#define KW_ELSE 310
-#define KW_END_PUBLISH 311
-#define KW_ENUM 312
-#define KW_EXTENSION 313
-#define KW_EXTERN 314
-#define KW_EXPLICIT 315
-#define KW_PUBLISHED 316
-#define KW_FALSE 317
-#define KW_FLOAT 318
-#define KW_FRIEND 319
-#define KW_FOR 320
-#define KW_GOTO 321
-#define KW_IF 322
-#define KW_INLINE 323
-#define KW_INT 324
-#define KW_LONG 325
-#define KW_LONGLONG 326
+#define KW_BEGIN_PUBLISH 298
+#define KW_BLOCKING 299
+#define KW_BOOL 300
+#define KW_CATCH 301
+#define KW_CHAR 302
+#define KW_WCHAR_T 303
+#define KW_CLASS 304
+#define KW_CONST 305
+#define KW_DELETE 306
+#define KW_DOUBLE 307
+#define KW_DYNAMIC_CAST 308
+#define KW_ELSE 309
+#define KW_END_PUBLISH 310
+#define KW_ENUM 311
+#define KW_EXTENSION 312
+#define KW_EXTERN 313
+#define KW_EXPLICIT 314
+#define KW_PUBLISHED 315
+#define KW_FALSE 316
+#define KW_FLOAT 317
+#define KW_FRIEND 318
+#define KW_FOR 319
+#define KW_GOTO 320
+#define KW_IF 321
+#define KW_INLINE 322
+#define KW_INT 323
+#define KW_LONG 324
+#define KW_LONGLONG 325
+#define KW_MAKE_PROPERTY 326
 #define KW_MAKE_SEQ 327
 #define KW_MUTABLE 328
 #define KW_NAMESPACE 329
@@ -247,15 +254,12 @@
 
 
 
-
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
 #endif
 
-
-
 #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
 typedef struct YYLTYPE
 {
@@ -270,4 +274,18 @@ typedef struct YYLTYPE
 #endif
 
 
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int cppyyparse (void *YYPARSE_PARAM);
+#else
+int cppyyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int cppyyparse (void);
+#else
+int cppyyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
 
+#endif /* !YY_CPPYY_BUILT_TMP_CPPBISON_YXX_H_INCLUDED  */

+ 49 - 18
dtool/src/cppparser/cppBison.yxx

@@ -14,6 +14,7 @@
 #include "cppEnumType.h"
 #include "cppFunctionType.h"
 #include "cppTBDType.h"
+#include "cppMakeProperty.h"
 #include "cppMakeSeq.h"
 #include "cppParameterList.h"
 #include "cppInstance.h"
@@ -234,7 +235,6 @@ pop_struct() {
 %token XOREQUAL
 %token LSHIFTEQUAL
 %token RSHIFTEQUAL
-%token TOKENPASTE
 
 %token KW_BEGIN_PUBLISH
 %token KW_BLOCKING
@@ -264,6 +264,7 @@ pop_struct() {
 %token KW_INT
 %token KW_LONG
 %token KW_LONGLONG
+%token KW_MAKE_PROPERTY
 %token KW_MAKE_SEQ
 %token KW_MUTABLE
 %token KW_NAMESPACE
@@ -475,7 +476,35 @@ declaration:
 {
   current_scope->set_current_vis(V_private);
 }
-	| KW_MAKE_SEQ '(' name ',' name ',' name ')' ';'
+        | KW_MAKE_PROPERTY '(' IDENTIFIER ',' IDENTIFIER ')' ';'
+{
+
+  CPPDeclaration *getter = $5->find_symbol(current_scope, global_scope, current_lexer);
+  if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) {
+    yyerror("Reference to non-existent or invalid getter: " + $5->get_fully_scoped_name(), @1);
+  }
+
+  CPPMakeProperty *make_property = new CPPMakeProperty($3, getter->as_function_group(), NULL, current_scope, @1.file);
+  current_scope->add_declaration(make_property, global_scope, current_lexer, @1);
+}
+        | KW_MAKE_PROPERTY '(' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ')' ';'
+{
+  CPPDeclaration *getter = $5->find_symbol(current_scope, global_scope, current_lexer);
+  if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) {
+    yyerror("Reference to non-existent or invalid getter: " + $5->get_fully_scoped_name(), @1);
+  }
+
+  CPPDeclaration *setter = $7->find_symbol(current_scope, global_scope, current_lexer);
+  if (setter == (CPPDeclaration *)NULL || setter->get_subtype() != CPPDeclaration::ST_function_group) {
+    yyerror("Reference to non-existent or invalid setter: " + $7->get_fully_scoped_name(), @1);
+  }
+
+  CPPMakeProperty *make_property = new CPPMakeProperty($3, getter->as_function_group(),
+                                                           setter->as_function_group(),
+                                                           current_scope, @1.file);
+  current_scope->add_declaration(make_property, global_scope, current_lexer, @1);
+}
+         | KW_MAKE_SEQ '(' name ',' name ',' name ')' ';'
 {
   CPPMakeSeq *make_seq = new CPPMakeSeq($3->get_simple_name(), $5->get_simple_name(), $7->get_simple_name(), @1.file);
   current_scope->add_declaration(make_seq, global_scope, current_lexer, @1);
@@ -1828,32 +1857,34 @@ named_enum:
 }
         ;
 
-enum_body:
+enum_body_trailing_comma:
         empty
-        | enum_body_no_trailing_comma
-        | enum_body_no_trailing_comma ','
-        ;
-
-enum_body_no_trailing_comma:
-        name
+        | enum_body_trailing_comma name ','
 {
   assert(current_enum != NULL);
-  current_enum->add_element($1->get_simple_name(), current_scope);
+  CPPInstance *inst = current_enum->add_element($2->get_simple_name());
+  current_scope->add_enum_value(inst, current_lexer, @2);
 }
-        | name '=' const_expr
+        | enum_body_trailing_comma name '=' const_expr ','
 {
   assert(current_enum != NULL);
-  current_enum->add_element($1->get_simple_name(), current_scope, $3);
-}
-        | enum_body_no_trailing_comma ',' name
+  CPPInstance *inst = current_enum->add_element($2->get_simple_name(), $4);
+  current_scope->add_enum_value(inst, current_lexer, @2);
+};
+
+enum_body:
+        enum_body_trailing_comma
+        | enum_body_trailing_comma name
 {
   assert(current_enum != NULL);
-  current_enum->add_element($3->get_simple_name(), current_scope);
+  CPPInstance *inst = current_enum->add_element($2->get_simple_name());
+  current_scope->add_enum_value(inst, current_lexer, @2);
 }
-        | enum_body_no_trailing_comma ',' name '=' const_expr
+        | enum_body_trailing_comma name '=' const_expr
 {
   assert(current_enum != NULL);
-  current_enum->add_element($3->get_simple_name(), current_scope, $5);
+  CPPInstance *inst = current_enum->add_element($2->get_simple_name(), $4);
+  current_scope->add_enum_value(inst, current_lexer, @2);
 }
         ;
 
@@ -2086,7 +2117,7 @@ element:
         | KW_SHORT | KW_SIGNED | KW_SIZEOF | KW_STATIC | KW_STATIC_CAST
         | KW_STRUCT | KW_THROW | KW_TRUE | KW_TRY | KW_TYPEDEF | KW_TYPENAME
         | KW_UNION | KW_UNSIGNED | KW_VIRTUAL | KW_VOID | KW_VOLATILE
-        | KW_WHILE | TOKENPASTE
+        | KW_WHILE
         | KW_OPERATOR
 {
 }

+ 10 - 1
dtool/src/cppparser/cppDeclaration.cxx

@@ -356,6 +356,16 @@ as_type_proxy() {
   return (CPPTypeProxy *)NULL;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPDeclaration::as_make_property
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+CPPMakeProperty *CPPDeclaration::
+as_make_property() {
+  return (CPPMakeProperty *)NULL;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPDeclaration::as_make_seq
 //       Access: Public, Virtual
@@ -366,7 +376,6 @@ as_make_seq() {
   return (CPPMakeSeq *)NULL;
 }
 
-
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPDeclaration::is_equal
 //       Access: Protected, Virtual

+ 3 - 4
dtool/src/cppparser/cppDeclaration.h

@@ -47,6 +47,7 @@ class CPPExtensionType;
 class CPPStructType;
 class CPPEnumType;
 class CPPTypeProxy;
+class CPPMakeProperty;
 class CPPMakeSeq;
 class CPPClassTemplateParameter;
 class CPPTBDType;
@@ -69,6 +70,7 @@ public:
     ST_type,
     ST_namespace,
     ST_using,
+    ST_make_property,
     ST_make_seq,
 
     // Subtypes of CPPType
@@ -136,6 +138,7 @@ public:
   virtual CPPEnumType *as_enum_type();
   virtual CPPTBDType *as_tbd_type();
   virtual CPPTypeProxy *as_type_proxy();
+  virtual CPPMakeProperty *as_make_property();
   virtual CPPMakeSeq *as_make_seq();
 
   CPPVisibility _vis;
@@ -154,8 +157,4 @@ operator << (ostream &out, const CPPDeclaration &decl) {
   return out;
 }
 
-
 #endif
-
-
-

+ 3 - 3
dtool/src/cppparser/cppEnumType.cxx

@@ -38,8 +38,8 @@ CPPEnumType(CPPIdentifier *ident, CPPScope *current_scope,
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-void CPPEnumType::
-add_element(const string &name, CPPScope *scope, CPPExpression *value) {
+CPPInstance *CPPEnumType::
+add_element(const string &name, CPPExpression *value) {
   CPPType *type =
     CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int,
                                         CPPSimpleType::F_unsigned));
@@ -47,7 +47,7 @@ add_element(const string &name, CPPScope *scope, CPPExpression *value) {
   CPPInstance *inst = new CPPInstance(type, ident);
   inst->_initializer = value;
   _elements.push_back(inst);
-  scope->add_enum_value(inst);
+  return inst;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 2 - 2
dtool/src/cppparser/cppEnumType.h

@@ -35,8 +35,8 @@ public:
   CPPEnumType(CPPIdentifier *ident, CPPScope *current_scope,
               const CPPFile &file);
 
-  void add_element(const string &name, CPPScope *scope,
-                   CPPExpression *value = (CPPExpression *)NULL);
+  CPPInstance *add_element(const string &name,
+                           CPPExpression *value = (CPPExpression *)NULL);
 
   virtual bool is_incomplete() const;
 

+ 29 - 2
dtool/src/cppparser/cppExpression.cxx

@@ -132,10 +132,10 @@ void *CPPExpression::Result::
 as_pointer() const {
   switch (_type) {
   case RT_integer:
-    return (void *)_u._integer;
+    return reinterpret_cast<void*>((long)_u._integer);
 
   case RT_real:
-    return (void *)(int)_u._real;
+    return reinterpret_cast<void*>((long)_u._real);
 
   case RT_pointer:
     return _u._pointer;
@@ -400,6 +400,16 @@ evaluate() const {
     return Result();
 
   case T_variable:
+    if (_u._variable->_type != NULL &&
+        _u._variable->_initializer != NULL) {
+      // A const variable.  Fetch its assigned value.
+      CPPConstType *const_type = _u._variable->_type->as_const_type();
+      if (const_type != NULL) {
+        return _u._variable->_initializer->evaluate();
+      }
+    }
+    return Result();
+
   case T_function:
     return Result();
 
@@ -889,6 +899,14 @@ bool CPPExpression::
 is_tbd() const {
   switch (_type) {
   case T_variable:
+    if (_u._variable->_type != NULL &&
+        _u._variable->_initializer != NULL) {
+      CPPConstType *const_type = _u._variable->_type->as_const_type();
+      if (const_type != NULL) {
+        return false;
+      }
+    }
+
     return true;
 
   case T_typecast:
@@ -978,6 +996,15 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
     break;
 
   case T_variable:
+    if (_u._variable->_type != NULL &&
+        _u._variable->_initializer != NULL) {
+      // A const variable.  Fetch its assigned value.
+      CPPConstType *const_type = _u._variable->_type->as_const_type();
+      if (const_type != NULL) {
+        _u._variable->_initializer->output(out, indent_level, scope, false);
+        break;
+      }
+    }
     _u._variable->_ident->output(out, scope);
     break;
 

+ 99 - 0
dtool/src/cppparser/cppMakeProperty.cxx

@@ -0,0 +1,99 @@
+// Filename: cppMakeProperty.cxx
+// Created by:  rdb (18Sep14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "cppMakeProperty.h"
+#include "cppFunctionGroup.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPMakeProperty::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+CPPMakeProperty::
+CPPMakeProperty(CPPIdentifier *ident,
+                CPPFunctionGroup *getter, CPPFunctionGroup *setter,
+                CPPScope *current_scope, const CPPFile &file) :
+  CPPDeclaration(file),
+  _ident(ident),
+  _getter(getter),
+  _setter(setter)
+{
+  _ident->_native_scope = current_scope;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPMakeProperty::get_simple_name
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+string CPPMakeProperty::
+get_simple_name() const {
+  return _ident->get_simple_name();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPMakeProperty::get_local_name
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+string CPPMakeProperty::
+get_local_name(CPPScope *scope) const {
+  return _ident->get_local_name(scope);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPMakeProperty::get_fully_scoped_name
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+string CPPMakeProperty::
+get_fully_scoped_name() const {
+  return _ident->get_fully_scoped_name();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPMakeProperty::output
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+void CPPMakeProperty::
+output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
+  out << "__make_property(" << _ident->get_local_name(scope)
+      << ", " << _getter->_name;
+
+  if (_setter != NULL) {
+    out << ", " << _setter->_name;
+  }
+  out << ");";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPMakeProperty::get_subtype
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+CPPDeclaration::SubType CPPMakeProperty::
+get_subtype() const {
+  return ST_make_property;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPMakeProperty::as_make_property
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+CPPMakeProperty *CPPMakeProperty::
+as_make_property() {
+  return this;
+}

+ 51 - 0
dtool/src/cppparser/cppMakeProperty.h

@@ -0,0 +1,51 @@
+// Filename: cppMakeProperty.h
+// Created by:  rdb (18Sep14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 CPPMAKEPROPERTY_H
+#define CPPMAKEPROPERTY_H
+
+#include "dtoolbase.h"
+
+#include "cppDeclaration.h"
+
+///////////////////////////////////////////////////////////////////
+//       Class : CPPMakeProperty
+// Description : This is a MAKE_PROPERTY() declaration appearing
+//               within a class body.  It means to generate a property
+//               within Python, replacing (for instance)
+//               get_something()/set_something() with a synthetic
+//               'something' attribute.
+////////////////////////////////////////////////////////////////////
+class CPPMakeProperty : public CPPDeclaration {
+public:
+  CPPMakeProperty(CPPIdentifier *ident,
+                  CPPFunctionGroup *getter, CPPFunctionGroup *setter,
+                  CPPScope *current_scope, const CPPFile &file);
+
+  virtual string get_simple_name() const;
+  virtual string get_local_name(CPPScope *scope = NULL) const;
+  virtual string get_fully_scoped_name() const;
+
+  virtual void output(ostream &out, int indent_level, CPPScope *scope,
+                      bool complete) const;
+
+  virtual SubType get_subtype() const;
+  virtual CPPMakeProperty *as_make_property();
+
+  CPPIdentifier *_ident;
+  CPPFunctionGroup *_getter;
+  CPPFunctionGroup *_setter;
+};
+
+#endif

+ 181 - 31
dtool/src/cppparser/cppManifest.cxx

@@ -24,8 +24,8 @@
 //  Description:
 ////////////////////////////////////////////////////////////////////
 CPPManifest::ExpansionNode::
-ExpansionNode(int parm_number) :
-  _parm_number(parm_number)
+ExpansionNode(int parm_number, bool stringify, bool paste) :
+  _parm_number(parm_number), _stringify(stringify), _paste(paste)
 {
 }
 
@@ -35,8 +35,8 @@ ExpansionNode(int parm_number) :
 //  Description:
 ////////////////////////////////////////////////////////////////////
 CPPManifest::ExpansionNode::
-ExpansionNode(const string &str) :
-  _parm_number(-1), _str(str)
+ExpansionNode(const string &str, bool paste) :
+  _parm_number(-1), _stringify(false), _paste(paste), _str(str)
 {
 }
 
@@ -46,7 +46,11 @@ ExpansionNode(const string &str) :
 //  Description:
 ////////////////////////////////////////////////////////////////////
 CPPManifest::
-CPPManifest(const string &args, const CPPFile &file) : _file(file) {
+CPPManifest(const string &args, const CPPFile &file) :
+  _file(file),
+  _variadic_param(-1),
+  _expr((CPPExpression *)NULL)
+{
   assert(!args.empty());
   assert(!isspace(args[0]));
 
@@ -69,6 +73,7 @@ CPPManifest(const string &args, const CPPFile &file) : _file(file) {
     _has_parameters = true;
     parse_parameters(args, p, parameter_names);
     _num_parameters = parameter_names.size();
+
     p++;
   } else {
     _has_parameters = false;
@@ -83,7 +88,6 @@ CPPManifest(const string &args, const CPPFile &file) : _file(file) {
   save_expansion(args.substr(p), parameter_names);
 }
 
-
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPManifest::Destructor
 //       Access: Public
@@ -96,7 +100,58 @@ CPPManifest::
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPManifest::stringify
+//       Access: Public, Static
+//  Description: This implements the stringification operator, #.
+////////////////////////////////////////////////////////////////////
+string CPPManifest::
+stringify(const string &source) {
+  string result("\"");
+
+  enum {
+    S_escaped = 0x01,
+    S_single_quoted = 0x02,
+    S_double_quoted = 0x04,
+    S_quoted = 0x06,
+  };
+  int state = 0;
+
+  string::const_iterator it;
+  for (it = source.begin(); it != source.end(); ++it) {
+    char c = *it;
+
+    if ((state & S_escaped) == 0) {
+      switch (c) {
+      case '\\':
+        if (state & S_quoted) {
+          state |= S_escaped;
+          result += '\\';
+        }
+        break;
+
+      case '\'':
+        state ^= S_single_quoted;
+        break;
+
+      case '"':
+        state ^= S_double_quoted;
+        result += '\\';
+        break;
+      }
+    } else {
+      if (c == '\\' || c == '"') {
+        result += '\\';
+      }
+      state &= ~S_escaped;
+    }
+
+    result += c;
+  }
 
+  result += '"';
+  return result;
+}
 
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPManifest::expand
@@ -111,14 +166,45 @@ expand(const vector_string &args) const {
   for (ei = _expansion.begin(); ei != _expansion.end(); ++ei) {
     if ((*ei)._parm_number >= 0) {
       int i = (*ei)._parm_number;
+
+      string subst;
       if (i < (int)args.size()) {
-        result += " " + args[i] + " ";
-      } else {
-        result += " ";
+        subst = args[i];
+
+        if (i == _variadic_param) {
+          for (++i; i < (int)args.size(); ++i) {
+            subst += ", " + args[i];
+          }
+        }
+        if ((*ei)._stringify) {
+          subst = stringify(subst);
+        }
+      } else if (i == _variadic_param && (*ei)._paste) {
+        // Special case GCC behavior: if __VA_ARGS__ is pasted
+        // to a comma and no arguments are passed, the comma
+        // is removed.  MSVC does this automatically.  Not sure
+        // if we should allow MSVC behavior as well.
+        if (*result.rbegin() == ',') {
+          result.resize(result.size() - 1);
+        }
+      }
+
+      if (!subst.empty()) {
+        if (result.empty() || (*ei)._paste) {
+          result += subst;
+        } else {
+          result += ' ';
+          result += subst;
+        }
       }
     }
     if (!(*ei)._str.empty()) {
-      result += (*ei)._str;
+      if (result.empty() || (*ei)._paste) {
+        result += (*ei)._str;
+      } else {
+        result += ' ';
+        result += (*ei)._str;
+      }
     }
   }
 
@@ -151,20 +237,40 @@ output(ostream &out) const {
   if (_has_parameters) {
     out << "(";
     if (_num_parameters > 0) {
-      out << "$1";
+      if (_variadic_param == 0) {
+        out << "...";
+      } else {
+        out << "$1";
+      }
+
       for (int i = 1; i < _num_parameters; ++i) {
-        out << ", $" << i + 1;
+        if (_variadic_param == i) {
+          out << ", ...";
+        } else {
+          out << ", $" << i + 1;
+        }
       }
     }
     out << ")";
   }
 
-  out << " ";
-
   Expansion::const_iterator ei;
   for (ei = _expansion.begin(); ei != _expansion.end(); ++ei) {
+    if ((*ei)._paste) {
+      out << " ## ";
+    } else {
+      out << " ";
+    }
+
     if ((*ei)._parm_number >= 0) {
-      out << " $" << (*ei)._parm_number + 1 << " ";
+      if (stringify) {
+        out << "#";
+      }
+      if ((*ei)._parm_number == _variadic_param) {
+        out << "__VA_ARGS__";
+      } else {
+        out << "$" << (*ei)._parm_number + 1;
+      }
     }
     if (!(*ei)._str.empty()) {
       out << (*ei)._str;
@@ -172,8 +278,6 @@ output(ostream &out) const {
   }
 }
 
-
-
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPManifest::parse_parameters
 //       Access: Private
@@ -197,7 +301,16 @@ parse_parameters(const string &args, size_t &p,
            args[p] != ')' && args[p] != ',') {
       p++;
     }
-    parameter_names.push_back(args.substr(q, p - q));
+
+    // Check if it's a variadic parameter by checking if it ends
+    // with "...".  This picks up both C99-style variadic macros
+    // and GCC-style variadic macros.
+    if (p - q >= 3 && args.compare(p - 3, 3, "...") == 0) {
+      _variadic_param = parameter_names.size();
+      parameter_names.push_back(args.substr(q, p - q - 3));
+    } else {
+      parameter_names.push_back(args.substr(q, p - q));
+    }
 
     // Skip whitespace after the parameter name.
     while (p < args.size() && isspace(args[p])) {
@@ -221,16 +334,12 @@ parse_parameters(const string &args, size_t &p,
 ////////////////////////////////////////////////////////////////////
 void CPPManifest::
 save_expansion(const string &exp, const vector_string &parameter_names) {
-  if (parameter_names.empty()) {
-    // No parameters; this is an easy case.
-    _expansion.push_back(ExpansionNode(exp));
-    return;
-  }
-
   // Walk through the expansion string.  For each substring that is an
   // identifier, check it against parameter_names.
   size_t p = 0;
   size_t last = 0;
+  bool stringify = false;
+  bool paste = false;
   while (p < exp.size()) {
     if (isalpha(exp[p]) || exp[p] == '_') {
       // Here's the start of an identifier.  Find the end of it.
@@ -244,26 +353,67 @@ save_expansion(const string &exp, const vector_string &parameter_names) {
 
       // Is this identifier one of our parameters?
       int pnum = -1;
-      for (int i = 0; pnum == -1 && i < (int)parameter_names.size(); ++i) {
-        if (parameter_names[i] == ident) {
-          pnum = i;
+      bool va_args = false;
+
+      if (ident == "__VA_ARGS__") {
+        va_args = true;
+        // C99-style variadics, ie. #define macro(...) __VA_ARGS__
+        pnum = _variadic_param;
+
+      } else {
+        for (int i = 0; pnum == -1 && i < (int)parameter_names.size(); ++i) {
+          const string &pname = parameter_names[i];
+          if (pname == ident) {
+            pnum = i;
+          }
         }
       }
 
       if (pnum != -1) {
         // Yep!
         if (last != q) {
-          _expansion.push_back(ExpansionNode(exp.substr(last, q - last)));
+          _expansion.push_back(ExpansionNode(exp.substr(last, q - last), paste));
+          paste = false;
         }
-        _expansion.push_back(pnum);
+        _expansion.push_back(ExpansionNode(pnum, stringify, paste));
+        stringify = false;
+        paste = false;
         last = p;
       }
+    } else if (exp[p] == '#') {
+      // This may be a stringification operator.
+      if (last != p) {
+        _expansion.push_back(ExpansionNode(exp.substr(last, p - last), paste));
+        paste = false;
+      }
+
+      ++p;
+
+      if (p < exp.size() && exp[p] == '#') {
+        // Woah, this is a token-pasting operator.
+        paste = true;
+        ++p;
+      } else {
+        // Mark that the next argument should be stringified.
+        stringify = true;
+      }
+      last = p;
+
+    } else if (isspace(exp[p])) {
+      if (last != p) {
+        _expansion.push_back(ExpansionNode(exp.substr(last, p - last), paste));
+        paste = false;
+      }
+
+      ++p;
+      last = p;
+
     } else {
-      p++;
+      ++p;
     }
   }
 
   if (last != p) {
-    _expansion.push_back(exp.substr(last, p - last));
+    _expansion.push_back(ExpansionNode(exp.substr(last, p - last), paste));
   }
 }

+ 7 - 2
dtool/src/cppparser/cppManifest.h

@@ -33,6 +33,8 @@ class CPPManifest {
 public:
   CPPManifest(const string &args, const CPPFile &file = CPPFile());
   ~CPPManifest();
+
+  static string stringify(const string &source);
   string expand(const vector_string &args = vector_string()) const;
 
   CPPType *determine_type() const;
@@ -42,6 +44,7 @@ public:
   string _name;
   bool _has_parameters;
   int _num_parameters;
+  int _variadic_param;
   CPPFile _file;
   CPPExpression *_expr;
 
@@ -59,9 +62,11 @@ private:
 
   class ExpansionNode {
   public:
-    ExpansionNode(int parm_number);
-    ExpansionNode(const string &str);
+    ExpansionNode(int parm_number, bool stringify, bool paste);
+    ExpansionNode(const string &str, bool paste = false);
     int _parm_number;
+    bool _stringify;
+    bool _paste;
     string _str;
   };
   typedef vector<ExpansionNode> Expansion;

+ 220 - 161
dtool/src/cppparser/cppPreprocessor.cxx

@@ -315,23 +315,6 @@ get_next_token0() {
   int first_col = token._lloc.first_column;
   CPPFile first_file = token._lloc.file;
 
-  if (token._token == '#') {
-    // Stringify.
-    token = internal_get_next_token();
-    if (token._token == SIMPLE_IDENTIFIER || 
-        token._token == INTEGER ||
-        token._token == REAL ||
-        token._token == STRING) {
-      token._token = STRING;
-    } else {
-      // Stringify nothing.
-
-      _saved_tokens.push_back(token);
-      token._token = STRING;
-      token._lval.str = "";
-    }
-  }
-
   if (_resolve_identifiers &&
       (token._token == SIMPLE_IDENTIFIER || token._token == SCOPE)) {
     // We will be returning a scoped identifier, or a scoping.  Keep
@@ -366,58 +349,40 @@ get_next_token0() {
       }
     }
 
-    while (token._token == SCOPE || token._token == TOKENPASTE) {
-      if (token._token == TOKENPASTE) {
-        // The token-pasting operator creates one continuous
-        // identifier across whitespace.
+    while (token._token == SCOPE) {
+      name += "::";
+      token = internal_get_next_token();
+      string token_prefix;
+
+      if (token._token == '~') {
+        // A scoping operator followed by a tilde can only be the
+        // start of a scoped destructor name.  Make the tilde be part
+        // of the name.
+        name += "~";
+        token_prefix = "~";
         token = internal_get_next_token();
-        if (token._token == SIMPLE_IDENTIFIER ||
-            token._token == INTEGER ||
-            token._token == REAL) {
-          name += token._lval.str;
-          ident->_names.back().append_name(token._lval.str);
-
-          token = internal_get_next_token();
+      }
 
-        } else {
-          // Token-paste with nothing.
-        }
+      if (token._token != SIMPLE_IDENTIFIER) {
+        // The last useful token was a SCOPE, thus this is a scoping
+        // token.
 
-      } else { // token._token == SCOPE
-        name += "::";
-        token = internal_get_next_token();
-        string token_prefix;
-
-        if (token._token == '~') {
-          // A scoping operator followed by a tilde can only be the
-          // start of a scoped destructor name.  Make the tilde be part
-          // of the name.
-          name += "~";
-          token_prefix = "~";
-          token = internal_get_next_token();
-        }
-
-        if (token._token != SIMPLE_IDENTIFIER) {
-          // The last useful token was a SCOPE, thus this is a scoping
-          // token.
-
-          if (token._token == KW_OPERATOR) {
-            // Unless the last token we came across was the "operator"
-            // keyword.  We make a special case for this, because it's
-            // occasionally scoped in normal use.
-            token._lval = result;
-            return token;
-          }
-          _saved_tokens.push_back(token);
-          return CPPToken(SCOPING, first_line, first_col, first_file,
-                          name, result);
+        if (token._token == KW_OPERATOR) {
+          // Unless the last token we came across was the "operator"
+          // keyword.  We make a special case for this, because it's
+          // occasionally scoped in normal use.
+          token._lval = result;
+          return token;
         }
+        _saved_tokens.push_back(token);
+        return CPPToken(SCOPING, first_line, first_col, first_file,
+                        name, result);
+      }
 
-        name += token._lval.str;
-        ident->_names.push_back(token_prefix + token._lval.str);
+      name += token._lval.str;
+      ident->_names.push_back(token_prefix + token._lval.str);
 
-        token = internal_get_next_token();
-      }
+      token = internal_get_next_token();
 
       if (token._token == '<') {
         // If the next token is an angle bracket and the current
@@ -563,6 +528,34 @@ get_comment_before(int line, CPPFile file) {
   return (CPPCommentBlock *)NULL;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPPreprocessor::get_comment_on
+//       Access: Public
+//  Description: Returns the CPPCommentBlock that starts on the
+//               indicated line, if any.  If there is no such
+//               comment, returns NULL.
+////////////////////////////////////////////////////////////////////
+CPPCommentBlock *CPPPreprocessor::
+get_comment_on(int line, CPPFile file) {
+  CPPComments::reverse_iterator ci;
+  ci = _comments.rbegin();
+
+  while (ci != _comments.rend()) {
+    CPPCommentBlock *comment = (*ci);
+    if (comment->_file == file) {
+      if (comment->_line_number == line) {
+        return comment;
+      } else if (comment->_line_number < line) {
+        return (CPPCommentBlock *)NULL;
+      }
+    }
+
+    ++ci;
+  }
+
+  return (CPPCommentBlock *)NULL;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPPreprocessor::init_cpp
 //       Access: Protected
@@ -887,11 +880,6 @@ internal_get_next_token() {
   case '%':
     if (next_c == '=') return CPPToken(MODEQUAL, first_line, first_col, first_file);
     break;
-
-    // These are actually preprocessor operators, but it's useful to
-    // treat them as tokens.
-  case '#':
-    if (next_c == '#') return CPPToken(TOKENPASTE, first_line, first_col, first_file);
   }
 
   // It wasn't any of the two- or three-character tokens, so put back
@@ -931,6 +919,10 @@ internal_get_next_token() {
     }
   }
 
+  // We skip whitespace here again, so that we can read any comments
+  // after this point before we parse this line.
+  _last_c = skip_whitespace(_last_c);
+
   return CPPToken(c, first_line, first_col, first_file);
 }
 
@@ -945,11 +937,13 @@ skip_whitespace(int c) {
     c = skip_comment(c);
 
     if (c == '\\') {
-      // A backslash character is an unusual thing to encounter in the
-      // middle of unquoted C++ code.  But it seems to be legal, and
-      // it seems to mean the same thing it does within quotes: to
-      // escape the following character.  We simply ignore it.
+      // This does not usually occur in the middle of unquoted C++
+      // code, except before a newline character.
       c = get();
+      if (c != '\n') {
+        unget(c);
+        return '\\';
+      }
     }
 
     if (!isspace(c)) {
@@ -1057,11 +1051,19 @@ skip_cpp_comment(int c) {
   if (_save_comments) {
     CPPCommentBlock *comment;
 
-    if (_last_cpp_comment) {
+    int line_number = get_line_number();
+    if (c == '\n') {
+      // We have to subtract one from the line number as we just
+      // fetched a newline.
+      --line_number;
+    }
+
+    if (_last_cpp_comment && !_comments.empty() &&
+        _comments.back()->_last_line >= line_number - 1) {
       // If the last non-whitespace character read was also part of a
       // C++ comment, then this is just a continuation of that comment
-      // block.
-      assert(!_comments.empty());
+      // block.  However, if there was a line without comment in between,
+      // it starts a new block anyway.
       comment = _comments.back();
       assert(!comment->_c_style);
       comment->_comment += "//";
@@ -1071,8 +1073,8 @@ skip_cpp_comment(int c) {
       comment = new CPPCommentBlock;
 
       comment->_file = get_file();
-      comment->_line_number = get_line_number();
-      comment->_last_line = get_line_number();
+      comment->_line_number = line_number;
+      comment->_last_line = line_number;
       comment->_col_number = get_col_number() - 2;
       comment->_c_style = false;
       comment->_comment = "//";
@@ -1086,7 +1088,7 @@ skip_cpp_comment(int c) {
     }
 
     comment->_comment += '\n';
-    comment->_last_line = get_line_number();
+    comment->_last_line = line_number;
 
     _last_cpp_comment = true;
 
@@ -1633,7 +1635,8 @@ expand_manifest(const CPPManifest *manifest) {
 
   if (manifest->_has_parameters) {
     // Hmm, we're expecting arguments.
-    extract_manifest_args(manifest->_name, manifest->_num_parameters, args);
+    extract_manifest_args(manifest->_name, manifest->_num_parameters,
+                          manifest->_variadic_param, args);
   }
 
   string expanded = " " + manifest->expand(args) + " ";
@@ -1659,7 +1662,7 @@ expand_manifest(const CPPManifest *manifest) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void CPPPreprocessor::
-extract_manifest_args(const string &name, int num_args,
+extract_manifest_args(const string &name, int num_args, int va_arg,
                       vector_string &args) {
   CPPFile first_file = get_file();
   int first_line = get_line_number();
@@ -1683,12 +1686,14 @@ extract_manifest_args(const string &name, int num_args,
 
   } else {
     // Skip paren.
-    c = get();
+    c = skip_whitespace(get());
+    int paren_level = 1;
     string arg;
-    while (c != EOF && c != ')') {
-      if (c == ',') {
+    while (c != EOF) {
+      if (c == ',' && paren_level == 1) {
         args.push_back(arg);
         arg = "";
+        c = get();
 
       } else if (c == '"' || c == '\'') {
         // Quoted string or character.
@@ -1706,35 +1711,55 @@ extract_manifest_args(const string &name, int num_args,
           }
         }
         arg += c;
+        c = get();
 
       } else if (c == '(') {
-        // Nested parens.
-        int paren_level = 1;
-        while (c != EOF && paren_level > 0) {
-          arg += c;
-          c = get();
-          if (c == '(') {
-            paren_level++;
-          } else if (c == ')') {
-            paren_level--;
-          }
+        arg += '(';
+        ++paren_level;
+        c = get();
+
+      } else if (c == ')') {
+        --paren_level;
+        if (paren_level == 0) {
+          break;
+        }
+        arg += ')';
+        c = get();
+
+      } else if (isspace(c)) {
+        // Skip extra whitespace.
+        c = skip_whitespace(c);
+        if (!arg.empty()) {
+          arg += ' ';
         }
-        if (c != EOF) {
-          arg += c;
+
+      } else if (c == '\\') {
+        // It could be a slash before a newline.
+        // If so, that's whitespace as well.
+        c = get();
+        if (c != '\n') {
+          arg += '\\';
+        } else if (!arg.empty()) {
+          arg += ' ';
+          c = skip_whitespace(get());
         }
 
       } else {
         arg += c;
+        c = get();
       }
-      c = get();
     }
     if (num_args != 0 || !arg.empty()) {
       args.push_back(arg);
     }
   }
 
-  if ((int)args.size() != num_args) {
-    warning("Wrong number of arguments for manifest " + name,
+  if ((int)args.size() < num_args) {
+    warning("Not enough arguments for manifest " + name,
+            first_line, first_col, first_file);
+
+  } else if (va_arg < 0 && (int)args.size() > num_args) {
+    warning("Too many arguments for manifest " + name,
             first_line, first_col, first_file);
   }
 }
@@ -1742,14 +1767,15 @@ extract_manifest_args(const string &name, int num_args,
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPPreprocessor::expand_defined_function
 //       Access: Private
-//  Description:
+//  Description: Expands the defined(manifest) function to either
+//               1 or 0, depending on whether the manifest exists.
 ////////////////////////////////////////////////////////////////////
 void CPPPreprocessor::
 expand_defined_function(string &expr, size_t q, size_t &p) {
   string result;
 
   vector_string args;
-  extract_manifest_args_inline("defined", 1, args, expr, p);
+  extract_manifest_args_inline("defined", 1, -1, args, expr, p);
   if (args.size() >= 1) {
     const string &manifest_name = args[0];
     Manifests::const_iterator mi = _manifests.find(manifest_name);
@@ -1777,7 +1803,7 @@ expand_manifest_inline(string &expr, size_t q, size_t &p,
   vector_string args;
   if (manifest->_has_parameters) {
     extract_manifest_args_inline(manifest->_name, manifest->_num_parameters,
-                                 args, expr, p);
+                                 manifest->_variadic_param, args, expr, p);
   }
   string result = manifest->expand(args);
 
@@ -1792,7 +1818,7 @@ expand_manifest_inline(string &expr, size_t q, size_t &p,
 ////////////////////////////////////////////////////////////////////
 void CPPPreprocessor::
 extract_manifest_args_inline(const string &name, int num_args,
-                             vector_string &args,
+                             int va_arg, vector_string &args,
                              const string &expr, size_t &p) {
   // Skip whitespace till paren.
   while (p < expr.size() && isspace(expr[p])) {
@@ -1819,7 +1845,7 @@ extract_manifest_args_inline(const string &name, int num_args,
       }
     }
     p++;
-    
+
   } else {
     // Skip paren.
     p++;
@@ -1850,8 +1876,11 @@ extract_manifest_args_inline(const string &name, int num_args,
     }
   }
 
-  if ((int)args.size() != num_args) {
-    warning("Wrong number of arguments for manifest " + name);
+  if ((int)args.size() < num_args) {
+    warning("Not enough arguments for manifest " + name);
+
+  } else if (va_arg < 0 && (int)args.size() > num_args) {
+    warning("Too many arguments for manifest " + name);
   }
 }
 
@@ -1998,6 +2027,7 @@ check_keyword(const string &name) {
   if (name == "inline") return KW_INLINE;
   if (name == "int") return KW_INT;
   if (name == "long") return KW_LONG;
+  if (name == "__make_property") return KW_MAKE_PROPERTY;
   if (name == "__make_seq") return KW_MAKE_SEQ;
   if (name == "mutable") return KW_MUTABLE;
   if (name == "namespace") return KW_NAMESPACE;
@@ -2035,6 +2065,90 @@ check_keyword(const string &name) {
   return 0;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPPreprocessor::scan_escape_sequence
+//       Access: Private
+//  Description:
+////////////////////////////////////////////////////////////////////
+int CPPPreprocessor::
+scan_escape_sequence(int c) {
+  if (c != '\\') {
+    return c;
+  }
+
+  c = get();
+  switch (c) {
+  case 'a':
+    return '\a';
+
+  case 'b':
+    return '\b';
+
+  case 'f':
+    return '\f';
+
+  case 'n':
+    return '\n';
+
+  case 'r':
+    return '\r';
+
+  case 't':
+    return '\t';
+
+  case 'v':
+    return '\v';
+
+  case 'e':
+    // \e is non-standard, buT GCC supports it.
+    return '\x1B';
+
+  case 'x':
+    // hex character.
+    c = get();
+    if (isxdigit(c)) {
+      int val = hex_val(c);
+      c = get();
+      if (isxdigit(c)) {
+        val = (val << 4) | hex_val(c);
+      } else {
+        unget(c);
+      }
+      return val;
+    }
+    break;
+
+  case '0':
+  case '1':
+  case '2':
+  case '3':
+  case '4':
+  case '5':
+  case '6':
+  case '7':
+    // Octal character.
+    {
+      int val = (c - '0');
+      c = get();
+      if (c >= '0' && c <= '7') {
+        val = (val << 3) | (c - '0');
+        c = get();
+        if (c >= '0' && c <= '7') {
+          val = (val << 3) | (c - '0');
+        } else {
+          unget(c);
+        }
+      } else {
+        unget(c);
+      }
+      return val;
+    }
+  }
+
+  // Simply output the following character.
+  return c;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPPreprocessor::scan_quoted
 //       Access: Private
@@ -2049,62 +2163,7 @@ scan_quoted(int c) {
   while (c != EOF && c != '\n' && c != quote_mark) {
     if (c == '\\') {
       // Backslash means a special character follows.
-      c = get();
-      switch (c) {
-      case 'n':
-        c = '\n';
-        break;
-
-      case 't':
-        c = '\t';
-        break;
-
-      case 'r':
-        c = '\r';
-        break;
-
-      case 'x':
-        // hex character.
-        c = get();
-        if (isxdigit(c)) {
-          int val = hex_val(c);
-          c = get();
-          if (isxdigit(c)) {
-            val = (val << 4) | hex_val(c);
-          } else {
-            unget(c);
-          }
-          c = val;
-        }
-        break;
-
-      case '0':
-      case '1':
-      case '2':
-      case '3':
-      case '4':
-      case '5':
-      case '6':
-      case '7':
-        // Octal character.
-        {
-          int val = (c - '0');
-          c = get();
-          if (c >= '0' && c <= '7') {
-            val = (val << 3) | (c - '0');
-            c = get();
-            if (c >= '0' && c <= '7') {
-              val = (val << 3) | (c - '0');
-            } else {
-              unget(c);
-            }
-          } else {
-            unget(c);
-          }
-          c = val;
-        }
-        break;
-      }
+      c = scan_escape_sequence(c);
     }
 
     str += c;

+ 5 - 3
dtool/src/cppparser/cppPreprocessor.h

@@ -64,6 +64,7 @@ public:
              CPPFile file = CPPFile());
 
   CPPCommentBlock *get_comment_before(int line, CPPFile file);
+  CPPCommentBlock *get_comment_on(int line, CPPFile file);
 
   int get_warning_count() const;
   int get_error_count() const;
@@ -75,7 +76,7 @@ public:
   DSearchPath _quote_include_path;
   DSearchPath _angle_include_path;
   bool _noangles;
-  
+
   CPPComments _comments;
 
   typedef set<CPPFile> ParsedFiles;
@@ -142,16 +143,17 @@ private:
   CPPToken get_identifier(int c);
   CPPToken expand_manifest(const CPPManifest *manifest);
   void extract_manifest_args(const string &name, int num_args,
-                             vector_string &args);
+                             int va_arg, vector_string &args);
   void expand_defined_function(string &expr, size_t q, size_t &p);
   void expand_manifest_inline(string &expr, size_t q, size_t &p,
                               const CPPManifest *manifest);
   void extract_manifest_args_inline(const string &name, int num_args,
-                                    vector_string &args,
+                                    int va_arg, vector_string &args,
                                     const string &expr, size_t &p);
 
   CPPToken get_number(int c, int c2 = 0);
   static int check_keyword(const string &name);
+  int scan_escape_sequence(int c);
   string scan_quoted(int c);
 
   bool should_ignore_manifest(const CPPManifest *manifest) const;

+ 26 - 1
dtool/src/cppparser/cppScope.cxx

@@ -145,9 +145,34 @@ add_declaration(CPPDeclaration *decl, CPPScope *global_scope,
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void CPPScope::
-add_enum_value(CPPInstance *inst) {
+add_enum_value(CPPInstance *inst, CPPPreprocessor *preprocessor,
+               const cppyyltype &pos) {
   inst->_vis = _current_vis;
 
+  if (inst->_leading_comment == (CPPCommentBlock *)NULL) {
+    // Same-line comment?
+    CPPCommentBlock *comment =
+      preprocessor->get_comment_on(pos.first_line, pos.file);
+
+    if (comment == (CPPCommentBlock *)NULL) {
+      // Nope.  Check for a comment before this line.
+      comment =
+        preprocessor->get_comment_before(pos.first_line, pos.file);
+
+      if (comment != NULL) {
+        // This is a bit of a hack, but it prevents us from picking
+        // up a same-line comment from the previous line.
+        if (comment->_line_number != pos.first_line - 1 ||
+            comment->_col_number <= pos.first_column) {
+
+          inst->_leading_comment = comment;
+        }
+      }
+    } else {
+      inst->_leading_comment = comment;
+    }
+  }
+
   string name = inst->get_simple_name();
   if (!name.empty()) {
     _enum_values[name] = inst;

+ 3 - 1
dtool/src/cppparser/cppScope.h

@@ -63,7 +63,9 @@ public:
   virtual void add_declaration(CPPDeclaration *decl, CPPScope *global_scope,
                                CPPPreprocessor *preprocessor,
                                const cppyyltype &pos);
-  virtual void add_enum_value(CPPInstance *inst);
+  virtual void add_enum_value(CPPInstance *inst,
+                              CPPPreprocessor *preprocessor,
+                              const cppyyltype &pos);
   virtual void define_extension_type(CPPExtensionType *type);
   virtual void define_namespace(CPPNamespace *scope);
   virtual void add_using(CPPUsing *using_decl, CPPScope *global_scope,

+ 3 - 2
dtool/src/cppparser/cppTemplateScope.cxx

@@ -51,10 +51,11 @@ add_declaration(CPPDeclaration *decl, CPPScope *global_scope,
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void CPPTemplateScope::
-add_enum_value(CPPInstance *inst) {
+add_enum_value(CPPInstance *inst, CPPPreprocessor *preprocessor,
+               const cppyyltype &pos) {
   inst->_template_scope = this;
   assert(_parent_scope != NULL);
-  _parent_scope->add_enum_value(inst);
+  _parent_scope->add_enum_value(inst, preprocessor, pos);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 3 - 1
dtool/src/cppparser/cppTemplateScope.h

@@ -36,7 +36,9 @@ public:
   virtual void add_declaration(CPPDeclaration *decl, CPPScope *global_scope,
                                CPPPreprocessor *preprocessor,
                                const cppyyltype &pos);
-  virtual void add_enum_value(CPPInstance *inst);
+  virtual void add_enum_value(CPPInstance *inst,
+                              CPPPreprocessor *preprocessor,
+                              const cppyyltype &pos);
   virtual void define_extension_type(CPPExtensionType *type);
   virtual void define_namespace(CPPNamespace *scope);
   virtual void add_using(CPPUsing *using_decl, CPPScope *global_scope,

+ 0 - 4
dtool/src/cppparser/cppToken.cxx

@@ -247,10 +247,6 @@ output(ostream &out) const {
     out << "RSHIFTEQUAL";
     break;
 
-  case TOKENPASTE:
-    out << "TOKENPASTE";
-    break;
-
   case KW_BOOL:
     out << "KW_BOOL";
     break;

+ 1 - 0
dtool/src/cppparser/p3cppParser_composite1.cxx

@@ -4,6 +4,7 @@
 #include "cppCommentBlock.cxx"
 #include "cppConstType.cxx"
 #include "cppDeclaration.cxx"
+#include "cppMakeProperty.cxx"
 #include "cppMakeSeq.cxx"
 #include "cppParameterList.cxx"
 #include "cppParser.cxx"

+ 4 - 2
dtool/src/dtoolbase/Sources.pp

@@ -39,7 +39,8 @@
     typeRegistryNode.I typeRegistryNode.h \
     typedObject.I typedObject.h \
     pallocator.T pallocator.h \
-    pdeque.h plist.h pmap.h pset.h pvector.h \
+    pdeque.h plist.h pmap.h pset.h \
+    pvector.h epvector.h \
     lookup3.h lookup3.c \
     dlmalloc_src.cxx ptmalloc2_smp_src.cxx
 
@@ -97,7 +98,8 @@
     typeRegistryNode.I typeRegistryNode.h \
     typedObject.I typedObject.h \
     pallocator.T pallocator.h \
-    pdeque.h plist.h pmap.h pset.h pvector.h \
+    pdeque.h plist.h pmap.h pset.h \
+    pvector.h epvector.h \
     lookup3.h
 
 #end lib_target

+ 67 - 37
dtool/src/dtoolbase/cmath.I

@@ -16,11 +16,11 @@
 // see float.h
 #define FPU_CONTROLWORD_WRITEMASK    0xFFFFF        // if you look at defn of _CW_DEFAULT, all settings fall within 0xFFFFF
 #define FPU_CONTROLWORD_NEW_SETTING  _CW_DEFAULT
-#endif  
+#endif
 
 ////////////////////////////////////////////////////////////////////
 //     Function: csqrt
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE float
 csqrt(float v) {
@@ -29,7 +29,7 @@ csqrt(float v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: csin
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE float
 csin(float v) {
@@ -38,7 +38,7 @@ csin(float v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ccos
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE float
 ccos(float v) {
@@ -47,7 +47,7 @@ ccos(float v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ctan
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE float ctan(float v) {
   return tanf(v);
@@ -55,7 +55,7 @@ INLINE float ctan(float v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: csincos
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE void
 csincos(float v, float *sin_result, float *cos_result) {
@@ -80,7 +80,7 @@ csincos(float v, float *sin_result, float *cos_result) {
 //     Function: csin_over_x
 //  Description: Computes sin(x) / x, well-behaved as x approaches 0.
 ////////////////////////////////////////////////////////////////////
-INLINE float 
+INLINE float
 csin_over_x(float v) {
   if (1.0f + v * v == 1.0f) {
     return 1.0f;
@@ -91,7 +91,7 @@ csin_over_x(float v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: cabs
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE float
 cabs(float v) {
@@ -100,7 +100,7 @@ cabs(float v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: catan
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE float
 catan(float v) {
@@ -109,7 +109,7 @@ catan(float v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: catan2
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE float
 catan2(float y, float x) {
@@ -118,7 +118,7 @@ catan2(float y, float x) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: casin
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE float
 casin(float v) {
@@ -127,7 +127,7 @@ casin(float v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: cacos
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE float
 cacos(float v) {
@@ -147,7 +147,7 @@ cmod(float x, float y) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: cpow
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE float
 cpow(float x, float y) {
@@ -157,7 +157,7 @@ cpow(float x, float y) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: cfloor
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE double
 cfloor(double f) {
@@ -169,13 +169,13 @@ cfloor(double f) {
     _controlfp(saved_fpu_control_word,FPU_CONTROLWORD_WRITEMASK);
     return retval;
   #else
-    return floor(f);  
+    return floor(f);
   #endif
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: cceil
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE double
 cceil(double f) {
@@ -187,7 +187,7 @@ cceil(double f) {
     _controlfp(saved_fpu_control_word,FPU_CONTROLWORD_WRITEMASK);
     return retval;
   #else
-    return ceil(f);  
+    return ceil(f);
   #endif
 }
 
@@ -202,7 +202,7 @@ cfrac(double f) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: csqrt
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE double
 csqrt(double v) {
@@ -211,7 +211,7 @@ csqrt(double v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: csin
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE double
 csin(double v) {
@@ -220,7 +220,7 @@ csin(double v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ccos
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE double
 ccos(double v) {
@@ -229,7 +229,7 @@ ccos(double v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ctan
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE double
 ctan(double v) {
@@ -238,7 +238,7 @@ ctan(double v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: csincos
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE void
 csincos(double v, double *sin_result, double *cos_result) {
@@ -262,7 +262,7 @@ csincos(double v, double *sin_result, double *cos_result) {
 //     Function: csin_over_x
 //  Description: Computes sin(x) / x, well-behaved as x approaches 0.
 ////////////////////////////////////////////////////////////////////
-INLINE double 
+INLINE double
 csin_over_x(double v) {
   if (1.0 + v * v == 1.0) {
     return 1.0;
@@ -273,7 +273,7 @@ csin_over_x(double v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: cabs
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE double
 cabs(double v) {
@@ -282,7 +282,7 @@ cabs(double v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: catan
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE double
 catan(double v) {
@@ -291,7 +291,7 @@ catan(double v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: catan2
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE double
 catan2(double y, double x) {
@@ -300,7 +300,7 @@ catan2(double y, double x) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: casin
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE double
 casin(double v) {
@@ -309,7 +309,7 @@ casin(double v) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: cacos
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE double
 cacos(double v) {
@@ -329,7 +329,7 @@ cmod(double x, double y) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: cpow
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE double
 cpow(double x, double y) {
@@ -338,7 +338,7 @@ cpow(double x, double y) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: cpow
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE int
 cpow(int x, int y) {
@@ -360,43 +360,73 @@ cpow(int x, int y) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: cnan
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE bool
 cnan(double v) {
 #ifndef _WIN32
-  return (std::isnan(v) != 0);
+  return std::isnan(v);
 #else
   return (_isnan(v) != 0);
 #endif
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: cinf
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool
+cinf(double v) {
+#ifndef _WIN32
+  return std::isinf(v);
+#else
+  return (_isnan(v) == 0 && _finite(v) == 0);
+#endif
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: make_nan
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE float
 make_nan(float) {
 #ifndef _WIN32
   return nanf("");
 #else
-  return numeric_limits<float>::quiet_NaN();
+  return std::numeric_limits<float>::quiet_NaN();
 #endif
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: make_nan
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE double 
+INLINE double
 make_nan(double) {
 #ifndef _WIN32
   return nan("");
 #else
-  return numeric_limits<double>::quiet_NaN();
+  return std::numeric_limits<double>::quiet_NaN();
 #endif
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: make_inf
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE float
+make_inf(float) {
+  return std::numeric_limits<float>::infinity();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: make_inf
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE double
+make_inf(double) {
+  return std::numeric_limits<double>::infinity();
+}
 
 ////////////////////////////////////////////////////////////////////
 //     Function: cmod

+ 7 - 8
dtool/src/dtoolbase/cmath.h

@@ -24,13 +24,8 @@
 #include "dtoolbase.h"
 
 #include <cmath>
-
-// Windows defines isnan() in a different place and with a different
-// name than everyone else.  Sheesh.
-#ifdef _WIN32
-#include <float.h>
+#include <cfloat>
 #include <limits>
-#endif
 
 INLINE float csqrt(float v);
 INLINE float csin(float v);
@@ -68,13 +63,17 @@ INLINE int cpow(int x, int y);
 // or infinity.
 INLINE bool cnan(double v);
 
-// Returns NaN.
+// Returns true if the number is infinity.
+INLINE bool cinf(double v);
+
+// Return NaN and infinity, respectively.
 INLINE float make_nan(float);
 INLINE double make_nan(double);
+INLINE float make_inf(float);
+INLINE double make_inf(double);
 
 INLINE int cmod(int x, int y);
 
 #include "cmath.I"
 
 #endif
-

+ 2 - 3
dtool/src/dtoolbase/dtoolbase.h

@@ -409,17 +409,16 @@
 #define BEGIN_PUBLISH __begin_publish
 #define END_PUBLISH __end_publish
 #define BLOCKING __blocking
+#define MAKE_PROPERTY(property_name, ...) __make_property(property_name, __VA_ARGS__)
 #define MAKE_SEQ(seq_name, num_name, element_name) __make_seq(seq_name, num_name, element_name)
 #undef USE_STL_ALLOCATOR  /* Don't try to parse these template classes in interrogate. */
 #define EXTENSION(x) __extension x
 #define EXTEND __extension
-#define EXT_FUNC(func) ::func()
-#define EXT_FUNC_ARGS(func, ...) ::func(__VA_ARGS__)
-#define CALL_EXT_FUNC(func, ...) ::func (__VA_ARGS__)
 #else
 #define BEGIN_PUBLISH
 #define END_PUBLISH
 #define BLOCKING
+#define MAKE_PROPERTY(property_name, ...)
 #define MAKE_SEQ(seq_name, num_name, element_name)
 #define EXTENSION(x)
 #define EXTEND

+ 61 - 0
dtool/src/dtoolbase/epvector.h

@@ -0,0 +1,61 @@
+// Filename: epvector.h
+// Created by:  drose (19Dec11)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 EPVECTOR_H
+#define EPVECTOR_H
+
+#include "pvector.h"
+
+#if defined(HAVE_EIGEN) && defined(_WIN32) && !defined(CPPPARSER)
+
+#include <Eigen/StdVector>
+
+////////////////////////////////////////////////////////////////////
+//       Class : epvector
+// Description : Unfortunately, on Windows, std::vector can't be used
+//               for classes with explicitly alignment requirements,
+//               due to a minor mistake in the template definition
+//               (one of the vector methods receives a concrete
+//               object, which the compiler flags as an error, even if
+//               the method is never called).
+//
+//               As a workaround, Eigen provides their own
+//               specialization of vector, using their own aligned
+//               allocator.  We define that here as epvector, which is
+//               meant to be a drop-in replacement for pvector for
+//               classes that include a linmath object that requires
+//               alignment.  Unfortunately, this means we can't use
+//               the Panda allocator, so memory allocated for this
+//               vector class won't be tracked as part of Panda's
+//               memory tracking system.  Them's the breaks, kids.
+////////////////////////////////////////////////////////////////////
+template<class Type>
+class epvector : public vector<Type, Eigen::aligned_allocator<Type> > {
+public:
+  typedef Eigen::aligned_allocator<Type> allocator;
+  typedef vector<Type, allocator> base_class;
+  typedef TYPENAME base_class::size_type size_type;
+
+  epvector(TypeHandle type_handle = pvector_type_handle) : base_class(allocator()) { }
+  epvector(const epvector<Type> &copy) : base_class(copy) { }
+  epvector(size_type n, TypeHandle type_handle = pvector_type_handle) : base_class(n, Type(), allocator()) { }
+  epvector(size_type n, const Type &value, TypeHandle type_handle = pvector_type_handle) : base_class(n, value, allocator()) { }
+  epvector(const Type *begin, const Type *end, TypeHandle type_handle = pvector_type_handle) : base_class(begin, end, allocator()) { }
+};
+
+#else  // HAVE_EIGEN
+#define epvector pvector
+#endif  // HAVE_EIGEN
+
+#endif

+ 86 - 49
dtool/src/dtoolbase/pstrtod.cxx

@@ -16,7 +16,11 @@
 
 #include <ctype.h>
 #include <math.h>
+#include <limits>
 
+#ifdef _WIN32
+#define strncasecmp _strnicmp
+#endif
 
 ////////////////////////////////////////////////////////////////////
 //     Function: pstrtod
@@ -45,67 +49,100 @@ pstrtod(const char *nptr, char **endptr) {
   double value = 0.0;
 
   if (isalpha(*p)) {
-    // For special cases like "inf" and "nan", pass these up to the
-    // system implementation of strtod.
-    return strtod(nptr, endptr);
-  }
+    // Windows' implementation of strtod doesn't support "inf" or
+    // "nan", so check for those here.
+    if (strncasecmp(p, "inf", 3) == 0) {
+      p += 3;
+      if (strncasecmp(p, "inity", 5) == 0) {
+        p += 5;
+      }
+      value = std::numeric_limits<double>::infinity();
 
-  // Start reading decimal digits to the left of the decimal point.
-  bool found_digits = false;
-  while (isdigit(*p)) {
-    value = (value * 10.0) + (*p - '0');
-    found_digits = true;
-    ++p;
-  }
-  
-  if (*p == '.') {
-    ++p;
-    // Read decimal digits to the right of the decimal point.
-    double multiplicand = 0.1;
+    } else if (strncasecmp(p, "nan", 3) == 0) {
+      p += 3;
+
+      if (*p == 's' || *p == 'S') {
+        value = std::numeric_limits<double>::signaling_NaN();
+        ++p;
+      } else {
+        if (*p == 'q' || *p == 'Q') {
+          ++p;
+        }
+        value = std::numeric_limits<double>::quiet_NaN();
+      }
+
+      // It is optionally possible to include a character sequence
+      // between parentheses after "nan", to be passed to the new
+      // nan() function.  Since it isn't supported universally, we
+      // will only accept a pair of empty parentheses.
+      if (strncmp(p, "()", 2) == 0) {
+        p += 2;
+      }
+
+    } else {
+      // Pass it up to the system implementation of strtod;
+      // perhaps it knows how to deal with this string.
+      return strtod(nptr, endptr);
+    }
+
+  } else {
+    // Start reading decimal digits to the left of the decimal point.
+    bool found_digits = false;
     while (isdigit(*p)) {
-      value += (*p - '0') * multiplicand;
-      ++p;
+      value = (value * 10.0) + (*p - '0');
       found_digits = true;
-      multiplicand *= 0.1;
-    }
-  }
-  
-  if (!found_digits) {
-    // Not a valid float.
-    if (endptr != NULL) {
-      *endptr = (char *)nptr;
-    }
-    return 0.0;
-  }
-  
-  if (tolower(*p) == 'e') {
-    // There's an exponent.
-    ++p;
-    
-    char esign = '+';
-    if (*p == '+' || *p == '-') {
-      esign = *p;
       ++p;
     }
-    
-    // Start reading decimal digits to the left of the decimal point.
-    double evalue = 0.0;
-    while (isdigit(*p)) {
-      evalue = (evalue * 10.0) + (*p - '0');
+
+    if (*p == '.') {
       ++p;
+      // Read decimal digits to the right of the decimal point.
+      double multiplicand = 0.1;
+      while (isdigit(*p)) {
+        value += (*p - '0') * multiplicand;
+        ++p;
+        found_digits = true;
+        multiplicand *= 0.1;
+      }
     }
-    
-    if (esign == '-') {
-      value /= pow(evalue, 10.0);
-    } else {
-      value *= pow(evalue, 10.0);
+
+    if (!found_digits) {
+      // Not a valid float.
+      if (endptr != NULL) {
+        *endptr = (char *)nptr;
+      }
+      return 0.0;
     }
-  }        
+
+    if (tolower(*p) == 'e') {
+      // There's an exponent.
+      ++p;
+
+      char esign = '+';
+      if (*p == '+' || *p == '-') {
+        esign = *p;
+        ++p;
+      }
+
+      // Start reading decimal digits to the left of the decimal point.
+      double evalue = 0.0;
+      while (isdigit(*p)) {
+        evalue = (evalue * 10.0) + (*p - '0');
+        ++p;
+      }
+
+      if (esign == '-') {
+        value /= pow(evalue, 10.0);
+      } else {
+        value *= pow(evalue, 10.0);
+      }
+    }
+  }
 
   if (sign == '-') {
     value = -value;
   }
-  
+
   if (endptr != NULL) {
     *endptr = (char *)p;
   }

+ 0 - 42
dtool/src/dtoolbase/pvector.h

@@ -51,46 +51,4 @@ public:
 
 #endif  // USE_STL_ALLOCATOR
 
-#if defined(HAVE_EIGEN) && defined(_WIN32) && !defined(CPPPARSER)
-
-#include <Eigen/StdVector>
-
-////////////////////////////////////////////////////////////////////
-//       Class : epvector
-// Description : Unfortunately, on Windows, std::vector can't be used
-//               for classes with explicitly alignment requirements,
-//               due to a minor mistake in the template definition
-//               (one of the vector methods receives a concrete
-//               object, which the compiler flags as an error, even if
-//               the method is never called).
-//
-//               As a workaround, Eigen provides their own
-//               specialization of vector, using their own aligned
-//               allocator.  We define that here as epvector, which is
-//               meant to be a drop-in replacement for pvector for
-//               classes that include a linmath object that requires
-//               alignment.  Unfortunately, this means we can't use
-//               the Panda allocator, so memory allocated for this
-//               vector class won't be tracked as part of Panda's
-//               memory tracking system.  Them's the breaks, kids.
-////////////////////////////////////////////////////////////////////
-template<class Type>
-class epvector : public vector<Type, Eigen::aligned_allocator<Type> > {
-public:
-  typedef Eigen::aligned_allocator<Type> allocator;
-  typedef vector<Type, allocator> base_class;
-  typedef TYPENAME base_class::size_type size_type;
-
-  epvector(TypeHandle type_handle = pvector_type_handle) : base_class(allocator()) { }
-  epvector(const epvector<Type> &copy) : base_class(copy) { }
-  epvector(size_type n, TypeHandle type_handle = pvector_type_handle) : base_class(n, Type(), allocator()) { }
-  epvector(size_type n, const Type &value, TypeHandle type_handle = pvector_type_handle) : base_class(n, value, allocator()) { }
-  epvector(const Type *begin, const Type *end, TypeHandle type_handle = pvector_type_handle) : base_class(begin, end, allocator()) { }
-};
-
-#else  // HAVE_EIGEN
-#define epvector pvector
-#endif  // HAVE_EIGEN
-
 #endif
-

+ 11 - 1
dtool/src/dtoolbase/typeHandle.I

@@ -275,6 +275,17 @@ none() {
   return _none;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TypeHandle::operator bool
+//       Access: Published
+//  Description: TypeHandle::none() evaluates to false, everything
+//               else evaluates to true.
+////////////////////////////////////////////////////////////////////
+INLINE TypeHandle::
+operator bool () const {
+  return (_index != 0);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: get_best_parent_from_Set
 //       Access: Published
@@ -295,4 +306,3 @@ INLINE  int TypeHandle::get_best_parent_from_Set(const std::set< int > &legal_va
     }
     return -1;
 }
-

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

@@ -146,6 +146,7 @@ PUBLISHED:
   INLINE int get_index() const;
   INLINE void output(ostream &out) const;
   INLINE static TypeHandle none();
+  INLINE operator bool () const;
 
 private:
   int _index;

+ 3 - 0
dtool/src/dtoolutil/Sources.pp

@@ -24,6 +24,7 @@
     panda_getopt.h panda_getopt_long.h panda_getopt_impl.h \
     pfstream.h pfstream.I pfstreamBuf.h \
     preprocess_argv.h \
+    string_utils.h string_utils.I \
     stringDecoder.h stringDecoder.I \
     textEncoder.h textEncoder.I \
     unicodeLatinMap.h \
@@ -43,6 +44,7 @@
     panda_getopt_impl.cxx \
     pfstreamBuf.cxx pfstream.cxx \
     preprocess_argv.cxx \
+    string_utils.cxx \
     stringDecoder.cxx \
     textEncoder.cxx \
     unicodeLatinMap.cxx \
@@ -63,6 +65,7 @@
     panda_getopt.h panda_getopt_long.h panda_getopt_impl.h \
     pfstream.h pfstream.I pfstreamBuf.h \
     preprocess_argv.h \
+    string_utils.h string_utils.I \
     stringDecoder.h stringDecoder.I \
     textEncoder.h textEncoder.I \
     unicodeLatinMap.h \

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

@@ -4,6 +4,7 @@
 #include "pfstream.cxx"
 #include "pfstreamBuf.cxx"
 #include "preprocess_argv.cxx"
+#include "string_utils.cxx"
 #include "stringDecoder.cxx"
 #include "textEncoder.cxx"
 #include "unicodeLatinMap.cxx"

+ 0 - 0
panda/src/putil/string_utils.I → dtool/src/dtoolutil/string_utils.I


+ 0 - 0
panda/src/putil/string_utils.cxx → dtool/src/dtoolutil/string_utils.cxx


+ 21 - 21
panda/src/putil/string_utils.h → dtool/src/dtoolutil/string_utils.h

@@ -15,51 +15,51 @@
 #ifndef STRING_UTILS_H
 #define STRING_UTILS_H
 
-#include "pandabase.h"
+#include "dtoolbase.h"
 
 #include <string>
 #include "vector_string.h"
 
 // Case-insensitive string comparison, from Stroustrup's C++ third edition.
 // Works like strcmp().
-EXPCL_PANDA_PUTIL int cmp_nocase(const string &s, const string &s2);
+EXPCL_DTOOL int cmp_nocase(const string &s, const string &s2);
 
 // Similar, except it also accepts hyphen and underscore as equivalent.
-EXPCL_PANDA_PUTIL int cmp_nocase_uh(const string &s, const string &s2);
+EXPCL_DTOOL int cmp_nocase_uh(const string &s, const string &s2);
 
 // Returns the string converted to lowercase.
-EXPCL_PANDA_PUTIL string downcase(const string &s);
+EXPCL_DTOOL string downcase(const string &s);
 
 // Returns the string converted to uppercase.
-EXPCL_PANDA_PUTIL string upcase(const string &s);
+EXPCL_DTOOL string upcase(const string &s);
 
 // Separates the string into words according to whitespace.
-EXPCL_PANDA_PUTIL int extract_words(const string &str, vector_string &words);
-EXPCL_PANDA_PUTIL int extract_words(const wstring &str, pvector<wstring> &words);
+EXPCL_DTOOL int extract_words(const string &str, vector_string &words);
+EXPCL_DTOOL int extract_words(const wstring &str, pvector<wstring> &words);
 
 // Separates the string into words according to the indicated delimiters.
-EXPCL_PANDA_PUTIL void tokenize(const string &str, vector_string &words,
+EXPCL_DTOOL void tokenize(const string &str, vector_string &words,
                           const string &delimiters,
                           bool discard_repeated_delimiters = false);
-EXPCL_PANDA_PUTIL void tokenize(const wstring &str, pvector<wstring> &words,
+EXPCL_DTOOL void tokenize(const wstring &str, pvector<wstring> &words,
                           const wstring &delimiters,
                           bool discard_repeated_delimiters = false);
 
 // Trims leading and/or trailing whitespace from the string.
-EXPCL_PANDA_PUTIL string trim_left(const string &str);
-EXPCL_PANDA_PUTIL wstring trim_left(const wstring &str);
-EXPCL_PANDA_PUTIL string trim_right(const string &str);
-EXPCL_PANDA_PUTIL wstring trim_right(const wstring &str);
-EXPCL_PANDA_PUTIL string trim(const string &str);
-EXPCL_PANDA_PUTIL wstring trim(const wstring &str);
+EXPCL_DTOOL string trim_left(const string &str);
+EXPCL_DTOOL wstring trim_left(const wstring &str);
+EXPCL_DTOOL string trim_right(const string &str);
+EXPCL_DTOOL wstring trim_right(const wstring &str);
+EXPCL_DTOOL string trim(const string &str);
+EXPCL_DTOOL wstring trim(const wstring &str);
 
 // Functions to parse numeric values out of a string.
-EXPCL_PANDA_PUTIL int string_to_int(const string &str, string &tail);
-EXPCL_PANDA_PUTIL bool string_to_int(const string &str, int &result);
-EXPCL_PANDA_PUTIL double string_to_double(const string &str, string &tail);
-EXPCL_PANDA_PUTIL bool string_to_double(const string &str, double &result);
-EXPCL_PANDA_PUTIL bool string_to_float(const string &str, float &result);
-EXPCL_PANDA_PUTIL bool string_to_stdfloat(const string &str, PN_stdfloat &result);
+EXPCL_DTOOL int string_to_int(const string &str, string &tail);
+EXPCL_DTOOL bool string_to_int(const string &str, int &result);
+EXPCL_DTOOL double string_to_double(const string &str, string &tail);
+EXPCL_DTOOL bool string_to_double(const string &str, double &result);
+EXPCL_DTOOL bool string_to_float(const string &str, float &result);
+EXPCL_DTOOL bool string_to_stdfloat(const string &str, PN_stdfloat &result);
 
 // Convenience function to make a string from anything that has an
 // ostream operator.

+ 9 - 7
dtool/src/interrogate/functionRemap.cxx

@@ -102,7 +102,8 @@ get_parameter_name(int n) const {
 //               are returning a value, or the empty string if we
 //               return nothing.
 ////////////////////////////////////////////////////////////////////
-string FunctionRemap::call_function(ostream &out, int indent_level, bool convert_result,
+string FunctionRemap::
+call_function(ostream &out, int indent_level, bool convert_result,
               const string &container, const vector_string &pexprs) const {
   string return_expr;
 
@@ -117,11 +118,11 @@ string FunctionRemap::call_function(ostream &out, int indent_level, bool convert
       InterfaceMaker::indent(out, indent_level)
         << "unref_delete(" << container << ");\n";
     } else {
-        if (inside_python_native) {
-          InterfaceMaker::indent(out, indent_level) << "Dtool_Py_Delete(self); \n";
-        } else {
-          InterfaceMaker::indent(out, indent_level) << " delete " << container << ";\n";
-        }
+      if (inside_python_native) {
+        InterfaceMaker::indent(out, indent_level) << "Dtool_Py_Delete(self);\n";
+      } else {
+        InterfaceMaker::indent(out, indent_level) << "delete " << container << ";\n";
+      }
     }
 
   } else if (_type == T_typecast_method) {
@@ -370,7 +371,8 @@ get_call_str(const string &container, const vector_string &pexprs) const {
     }
 
     call << " = ";
-    _parameters[0]._remap->pass_parameter(call, get_parameter_expr(_first_true_parameter, pexprs));
+    _parameters[_first_true_parameter]._remap->pass_parameter(call,
+                    get_parameter_expr(_first_true_parameter, pexprs));
 
   } else {
     const char *separator = "";

+ 77 - 6
dtool/src/interrogate/interfaceMaker.cxx

@@ -87,6 +87,19 @@ MakeSeq(const string &name, CPPMakeSeq *cpp_make_seq) :
 {
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::Property::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+InterfaceMaker::Property::
+Property(const InterrogateElement &ielement) :
+  _ielement(ielement),
+  _getter(NULL),
+  _setter(NULL)
+{
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: InterfaceMaker::Object::Constructor
 //       Access: Public
@@ -156,6 +169,8 @@ check_protocols() {
     _protocol_types |= PT_iter;
   }
 
+  InterrogateDatabase *idb = InterrogateDatabase::get_ptr();
+
   // Now are there any make_seq requests within this class?
   if (_itype._cpptype != NULL) {
     CPPStructType *stype = _itype._cpptype->as_struct_type();
@@ -230,9 +245,9 @@ InterfaceMaker::
     Object *object = (*oi).second;
     delete object;
   }
-  Functions::iterator fi;
+  FunctionsByIndex::iterator fi;
   for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
-    delete (*fi);
+    delete (*fi).second;
   }
 }
 
@@ -501,9 +516,9 @@ wrap_global_functions() {
 ////////////////////////////////////////////////////////////////////
 void InterfaceMaker::
 get_function_remaps(vector<FunctionRemap *> &remaps) {
-  Functions::iterator fi;
+  FunctionsByIndex::iterator fi;
   for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
-    Function *func = (*fi);
+    Function *func = (*fi).second;
     Function::Remaps::const_iterator ri;
     for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) {
       FunctionRemap *remap = (*ri);
@@ -617,12 +632,17 @@ get_unique_prefix() {
 ////////////////////////////////////////////////////////////////////
 InterfaceMaker::Function *InterfaceMaker::
 record_function(const InterrogateType &itype, FunctionIndex func_index) {
+  if (_functions.count(func_index)) {
+    // Already exists.
+    return _functions[func_index];
+  }
+
   InterrogateDatabase *idb = InterrogateDatabase::get_ptr();
   const InterrogateFunction &ifunc = idb->get_function(func_index);
 
   string wrapper_name = get_wrapper_name(itype, ifunc, func_index);
   Function *func = new Function(wrapper_name, itype, ifunc);
-  _functions.push_back(func);
+  _functions[func_index] = func;
 
 //  printf(" Function Name = %s\n", ifunc.get_name().c_str());
 
@@ -837,6 +857,27 @@ manage_return_value(ostream &out, int indent_level,
   return return_expr;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::delete_return_value
+//       Access: Protected
+//  Description: Cleans up the given return value by deleting it or
+//               decrementing its reference count or whatever is
+//               appropriate.
+////////////////////////////////////////////////////////////////////
+void InterfaceMaker::
+delete_return_value(ostream &out, int indent_level,
+                    FunctionRemap *remap, const string &return_expr) const {
+  if (remap->_manage_reference_count) {
+    // If we're managing reference counts, and we're about to return a
+    // reference countable object, then decrement its count.
+    output_unref(out, indent_level, remap, return_expr);
+
+  } else if (remap->_return_value_needs_management) {
+    // We should just delete it directly.
+    indent(out, indent_level) << "delete " << return_expr << ";\n";
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: InterfaceMaker::output_ref
 //       Access: Protected
@@ -859,7 +900,7 @@ output_ref(ostream &out, int indent_level, FunctionRemap *remap,
 
     indent(out, indent_level)
       << "if (" << varname << " != ("
-      << remap->_return_type->get_new_type()->get_local_name(&parser) << ")0) {\n";
+      << remap->_return_type->get_new_type()->get_local_name(&parser) << ")NULL) {\n";
     indent(out, indent_level + 2)
       << varname << "->ref();\n";
     indent(out, indent_level)
@@ -867,6 +908,36 @@ output_ref(ostream &out, int indent_level, FunctionRemap *remap,
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::output_unref
+//       Access: Protected
+//  Description: Outputs the code to decrement the reference count for
+//               the indicated variable name.
+////////////////////////////////////////////////////////////////////
+void InterfaceMaker::
+output_unref(ostream &out, int indent_level, FunctionRemap *remap, 
+             const string &varname) const {
+  if (remap->_type == FunctionRemap::T_constructor ||
+      remap->_type == FunctionRemap::T_typecast) {
+    // In either of these cases, we can safely assume the pointer will
+    // never be NULL.
+    indent(out, indent_level)
+      << "unref_delete(" << varname << ");\n";
+
+  } else {
+    // However, in the general case, we have to check for that before
+    // we attempt to ref it.
+
+    indent(out, indent_level)
+      << "if (" << varname << " != ("
+      << remap->_return_type->get_new_type()->get_local_name(&parser) << ")NULL) {\n";
+    indent(out, indent_level + 2)
+      << "unref_delete(" << varname << ");\n";
+    indent(out, indent_level)
+      << "}\n";
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: InterfaceMaker::hash_function_signature
 //       Access: Protected

+ 21 - 2
dtool/src/interrogate/interfaceMaker.h

@@ -31,8 +31,9 @@ class ParameterRemap;
 class CPPType;
 class CPPInstance;
 class InterrogateBuilder;
-class InterrogateType;
+class InterrogateElement;
 class InterrogateFunction;
+class InterrogateType;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : InterfaceMaker
@@ -109,8 +110,9 @@ public:
     int _flags;
     ArgsType _args_type;
   };
+  typedef map<FunctionIndex, Function *> FunctionsByIndex;
   typedef vector<Function *> Functions;
-  Functions _functions;
+  FunctionsByIndex _functions;
 
   class MakeSeq {
   public:
@@ -123,6 +125,16 @@ public:
   };
   typedef vector<MakeSeq *> MakeSeqs;
 
+  class Property {
+  public:
+    Property(const InterrogateElement &ielement);
+
+    const InterrogateElement &_ielement;
+    Function *_getter;
+    Function *_setter;
+  };
+  typedef vector<Property *> Properties;
+
   class Object {
   public:
     Object(const InterrogateType &itype);
@@ -135,6 +147,7 @@ public:
     Functions _constructors;
     Functions _methods;
     MakeSeqs _make_seqs;
+    Properties _properties;
 
     enum ProtocolTypes {
       PT_sequence         = 0x0001,
@@ -179,8 +192,14 @@ public:
   manage_return_value(ostream &out, int indent_level,
                       FunctionRemap *remap, const string &return_expr) const;
 
+  void
+  delete_return_value(ostream &out, int indent_level,
+                      FunctionRemap *remap, const string &return_expr) const;
+
   void output_ref(ostream &out, int indent_level, FunctionRemap *remap, 
                   const string &varname) const;
+  void output_unref(ostream &out, int indent_level, FunctionRemap *remap, 
+                    const string &varname) const;
   void write_spam_message(ostream &out, FunctionRemap *remap) const;
 
 protected:

+ 4 - 4
dtool/src/interrogate/interfaceMakerC.cxx

@@ -53,9 +53,9 @@ InterfaceMakerC::
 ////////////////////////////////////////////////////////////////////
 void InterfaceMakerC::
 write_prototypes(ostream &out,ostream *out_h) {
-  Functions::iterator fi;
+  FunctionsByIndex::iterator fi;
   for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
-    Function *func = (*fi);
+    Function *func = (*fi).second;
     write_prototype_for(out, func);
   }
 
@@ -72,9 +72,9 @@ write_prototypes(ostream &out,ostream *out_h) {
 ////////////////////////////////////////////////////////////////////
 void InterfaceMakerC::
 write_functions(ostream &out) {
-  Functions::iterator fi;
+  FunctionsByIndex::iterator fi;
   for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
-    Function *func = (*fi);
+    Function *func = (*fi).second;
     write_function_for(out, func);
   }
 

+ 2 - 1
dtool/src/interrogate/interfaceMakerPython.cxx

@@ -36,7 +36,8 @@ InterfaceMakerPython(InterrogateModuleDef *def) :
 void InterfaceMakerPython::
 write_includes(ostream &out) {
   InterfaceMaker::write_includes(out);
-  out << "#undef _POSIX_C_SOURCE\n\n"
+  out << "#undef _POSIX_C_SOURCE\n"
+      << "#define PY_SSIZE_T_CLEAN 1\n\n"
       << "#if PYTHON_FRAMEWORK\n"
       << "  #include \"Python/Python.h\"\n"
       << "#else\n"

+ 176 - 62
dtool/src/interrogate/interfaceMakerPythonNative.cxx

@@ -818,9 +818,9 @@ write_functions(ostream &out) {
   out << "//********************************************************************\n";
   out << "//*** Functions for .. Global\n" ;
   out << "//********************************************************************\n";
-  Functions::iterator fi;
+  FunctionsByIndex::iterator fi;
   for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
-    Function *func = (*fi);
+    Function *func = (*fi).second;
     if (!func->_itype.is_global() && is_function_legal(func)) {
       write_function_for_top(out, NULL, func);
     }
@@ -877,6 +877,23 @@ write_class_details(ostream &out, Object *obj) {
     }
   }
 
+  Properties::const_iterator pit;
+  for (pit = obj->_properties.begin(); pit != obj->_properties.end(); ++pit) {
+    Property *property = (*pit);
+    const InterrogateElement &ielem = property->_ielement;
+    bool coercion_attempted = false;
+
+    if (property->_getter != NULL) {
+      std::string fname = "PyObject *Dtool_" + ClassName + "_" + ielem.get_name() + "_Getter(PyObject *self, void *)";
+      write_function_for_name(out, obj, property->_getter, fname, true, coercion_attempted, AT_no_args, false, false);
+    }
+
+    if (property->_setter != NULL) {
+      std::string fname = "int Dtool_" + ClassName + "_" + ielem.get_name() + "_Setter(PyObject *self, PyObject *arg, void *)";
+      write_function_for_name(out, obj, property->_setter, fname, true, coercion_attempted, AT_single_arg, true, false);
+    }
+  }
+
   if (obj->_constructors.size() == 0) {
     out << "int Dtool_Init_" + ClassName + "(PyObject *self, PyObject *args, PyObject *kwds) {\n"
         << "  PyErr_SetString(PyExc_TypeError, \"cannot init constant class (" << cClassName << ")\");\n"
@@ -894,7 +911,7 @@ write_class_details(ostream &out, Object *obj) {
       Function *func = (*fi);
       std::string fname = "int Dtool_Init_" + ClassName + "(PyObject *self, PyObject *args, PyObject *kwds)";
 
-      write_function_for_name(out, obj, func, fname, true, coercion_attempted, AT_keyword_args, true);
+      write_function_for_name(out, obj, func, fname, true, coercion_attempted, AT_keyword_args, true, false);
     }
     if (coercion_attempted) {
       // If a coercion attempt was written into the above constructor,
@@ -904,7 +921,7 @@ write_class_details(ostream &out, Object *obj) {
         Function *func = (*fi);
         std::string fname = "int Dtool_InitNoCoerce_" + ClassName + "(PyObject *self, PyObject *args)";
 
-        write_function_for_name(out, obj, func, fname, false, coercion_attempted, AT_varargs, true);
+        write_function_for_name(out, obj, func, fname, false, coercion_attempted, AT_varargs, true, false);
       }
     } else {
       // Otherwise, since the above constructor didn't involve any
@@ -1115,9 +1132,9 @@ write_module_support(ostream &out, ostream *out_h, InterrogateModuleDef *def) {
   bool force_base_functions = true;
 
   out << "static PyMethodDef python_simple_funcs[] = {\n";
-  Functions::iterator fi;
+  FunctionsByIndex::iterator fi;
   for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
-    Function *func = (*fi);
+    Function *func = (*fi).second;
     if (!func->_itype.is_global() && is_function_legal(func)) {
       string name1 = methodNameFromCppName(func, "", false);
       string name2 = methodNameFromCppName(func, "", true);
@@ -1515,7 +1532,7 @@ write_module_class(ostream &out, Object *obj) {
           // *need* to raise IndexError if we're out of bounds.  We have to
           // assume the bounds are 0 .. this->size() (this is the same
           // assumption that Python makes).
-          out << "  if (index < 0 || index >= local_this->size()) {\n";
+          out << "  if (index < 0 || index >= (Py_ssize_t) local_this->size()) {\n";
           out << "    PyErr_SetString(PyExc_IndexError, \"" << ClassName << " index out of range\");\n";
           out << "    return NULL;\n";
           out << "  }\n";
@@ -1555,7 +1572,7 @@ write_module_class(ostream &out, Object *obj) {
           out << "    return -1;\n";
           out << "  }\n\n";
 
-          out << "  if (index < 0 || index >= local_this->size()) {\n";
+          out << "  if (index < 0 || index >= (Py_ssize_t) local_this->size()) {\n";
           out << "    PyErr_SetString(PyExc_IndexError, \"" << ClassName << " index out of range\");\n";
           out << "    return -1;\n";
           out << "  }\n";
@@ -2079,6 +2096,44 @@ write_module_class(ostream &out, Object *obj) {
     out << "}\n\n";
   }
 
+  if (obj->_properties.size() > 0) {
+    // Write out the array of properties, telling Python which getter and setter
+    // to call when they are assigned or queried in Python code.
+    out << "PyGetSetDef Dtool_Properties_" << ClassName << "[] = {\n";
+
+    Properties::const_iterator pit;
+    for (pit = obj->_properties.begin(); pit != obj->_properties.end(); ++pit) {
+      Property *property = (*pit);
+      const InterrogateElement &ielem = property->_ielement;
+      if (property->_getter == NULL || !is_function_legal(property->_getter)) {
+        continue;
+      }
+
+      out << "  {(char *)\"" << ielem.get_name() << "\","
+          << " &Dtool_" << ClassName << "_" << ielem.get_name() << "_Getter,";
+
+      if (property->_setter == NULL || !is_function_legal(property->_setter)) {
+        out << " NULL,";
+      } else {
+        out << " &Dtool_" << ClassName << "_" << ielem.get_name() << "_Setter,";
+      }
+
+      if (ielem.has_comment()) {
+        out << "(char *)\n";
+        output_quoted(out, 4, ielem.get_comment());
+        out << ",\n    ";
+      } else {
+        out << " NULL, ";
+      }
+
+      // Extra void* argument; we don't make use of it.
+      out << "NULL},\n";
+    }
+
+    out << "  {NULL},\n";
+    out << "};\n\n";
+  }
+
   out << "void Dtool_PyModuleClassInit_" << ClassName << "(PyObject *module) {\n";
   out << "  static bool initdone = false;\n";
   out << "  if (!initdone) {\n";
@@ -2191,6 +2246,11 @@ write_module_class(ostream &out, Object *obj) {
     out << "    Dtool_" << ClassName << ".As_PyTypeObject().tp_str = &Dtool_Repr_" << ClassName << ";\n";
   }
 
+  if (obj->_properties.size() > 0) {
+    // GetSet descriptor slots.
+    out << "    Dtool_" << ClassName << ".As_PyTypeObject().tp_getset = Dtool_Properties_" << ClassName << ";\n";
+  }
+
   int num_nested = obj->_itype.number_of_nested_types();
   for (int ni = 0; ni < num_nested; ni++) {
     TypeIndex nested_index = obj->_itype.get_nested_type(ni);
@@ -2396,7 +2456,7 @@ write_function_for_top(ostream &out, InterfaceMaker::Object *obj, InterfaceMaker
   fname += ")";
 
   bool coercion_attempted = false;
-  write_function_for_name(out, obj, func, fname, true, coercion_attempted, func->_args_type, false);
+  write_function_for_name(out, obj, func, fname, true, coercion_attempted, func->_args_type, false, true);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -2408,7 +2468,7 @@ void InterfaceMakerPythonNative::
 write_function_for_name(ostream &out1, InterfaceMaker::Object *obj, InterfaceMaker::Function *func,
                         const std::string &function_name,
                         bool coercion_allowed, bool &coercion_attempted,
-                        ArgsType args_type, bool return_int) {
+                        ArgsType args_type, bool return_int, bool write_comment) {
   ostringstream out;
 
   std::map<int, std::set<FunctionRemap *> > MapSets;
@@ -2463,7 +2523,11 @@ write_function_for_name(ostream &out1, InterfaceMaker::Object *obj, InterfaceMak
       // Other functions should raise an exception if the this
       // pointer isn't set or is the wrong type.
       out << "    PyErr_SetString(PyExc_AttributeError, \"C++ object is not yet constructed, or already destructed.\");\n";
-      out << "    return NULL;\n";
+      if (return_int) {
+        out << "    return -1;\n";
+      } else {
+        out << "    return NULL;\n";
+      }
     }
     out << "  }\n";
   }
@@ -2486,12 +2550,9 @@ write_function_for_name(ostream &out1, InterfaceMaker::Object *obj, InterfaceMak
     switch (args_type) {
     case AT_keyword_args:
       indent(out, 2) << "int parameter_count = PyTuple_Size(args);\n";
-
-      if (args_type == AT_keyword_args) {
-        indent(out, 2) << "if (kwds != NULL && PyDict_Check(kwds)) {\n";
-        indent(out, 2) << "  parameter_count += PyDict_Size(kwds);\n";
-        indent(out, 2) << "}\n";
-      }
+      indent(out, 2) << "if (kwds != NULL) {\n";
+      indent(out, 2) << "  parameter_count += PyDict_Size(kwds);\n";
+      indent(out, 2) << "}\n";
       break;
 
     case AT_varargs:
@@ -2499,7 +2560,7 @@ write_function_for_name(ostream &out1, InterfaceMaker::Object *obj, InterfaceMak
       break;
 
     case AT_single_arg:
-      // It shouldń't get here, but we'll handle these cases nonetheless.
+      // It shouldn't get here, but we'll handle these cases nonetheless.
       indent(out, 2) << "const int parameter_count = 1;\n";
       break;
 
@@ -2576,11 +2637,47 @@ write_function_for_name(ostream &out1, InterfaceMaker::Object *obj, InterfaceMak
 
   } else {
     string expected_params = "";
-    for (mii = MapSets.begin(); mii != MapSets.end(); mii++) {
-      write_function_forset(out, obj, func, mii->second, expected_params, 2, is_inplace,
-                            coercion_allowed, coercion_attempted, args_type, return_int);
+    mii = MapSets.begin();
+
+    // If no parameters are accepted, we do need to check that the argument
+    // count is indeed 0, since we won't check that in write_function_instance.
+    if (mii->first == 0 && args_type != AT_no_args) {
+      switch (args_type) {
+      case AT_keyword_args:
+        out << "  if (PyTuple_Size(args) > 0 || (kwds != NULL && PyDict_Size(kwds) > 0)) {\n";
+        out << "    int parameter_count = PyTuple_Size(args);\n";
+        out << "    if (kwds != NULL) {\n";
+        out << "      parameter_count += PyDict_Size(kwds);\n";
+        out << "    }\n";
+        break;
+      case AT_varargs:
+        out << "  if (PyTuple_Size(args) > 0) {\n";
+        out << "    const int parameter_count = PyTuple_GET_SIZE(args);\n";
+        break;
+      case AT_single_arg:
+      default:
+        // Shouldn't happen, but let's handle this case nonetheless.
+        out << "  {\n";
+        out << "    const int parameter_count = 1;\n";
+        break;
+      }
+
+      out << "    PyErr_Format(PyExc_TypeError,\n"
+          << "                 \"" << methodNameFromCppName(func, "", false)
+          << "() takes no arguments (%d given)\",\n"
+          << "                 parameter_count);\n";
+
+      if (return_int) {
+        out << "    return -1;\n";
+      } else {
+        out << "    return (PyObject *) NULL;\n";
+      }
+      out << "  }\n";
     }
 
+    write_function_forset(out, obj, func, mii->second, expected_params, 2, is_inplace,
+                          coercion_allowed, coercion_attempted, args_type, return_int);
+
     out << "  if (!PyErr_Occurred()) {\n";
     out << "    PyErr_SetString(PyExc_TypeError,\n";
     out << "      \"Arguments must match:\\n\"\n";
@@ -2607,7 +2704,7 @@ write_function_for_name(ostream &out1, InterfaceMaker::Object *obj, InterfaceMak
     FunctionComment = FunctionComment1 + "\n" + FunctionComment;
   }
 
-  if (!return_int) {
+  if (write_comment) {
     // Write out the function doc string.  We only do this if it is
     // not a constructor, since we don't have a place to put the
     // constructor doc string.
@@ -2922,7 +3019,6 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
   string extra_convert;
   string extra_param_check;
   string extra_cleanup;
-  string direct_assign;
 
   bool is_constructor = (remap->_type == FunctionRemap::T_constructor);
 
@@ -2954,7 +3050,7 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
 
   int num_params = 0;
   bool only_pyobjects = true;
-  bool check_exceptions = false;
+  //bool check_exceptions = false;
 
   int pn;
   for (pn = 0; pn < (int)remap->_parameters.size(); ++pn) {
@@ -3000,12 +3096,11 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
         parameter_list += ", &" + param_name;
 
         extra_convert += " Py_ssize_t " + param_name + "_len = PyUnicode_GetSize((PyObject *)" + param_name + ");"
-                         " wchar_t *" + param_name + "_str = new wchar_t[" + param_name + "_len + 1];"
+                         " wchar_t *" + param_name + "_str = (wchar_t *)alloca(sizeof(wchar_t) * (" + param_name + "_len + 1));"
                          " PyUnicode_AsWideChar(" + param_name + ", " + param_name + "_str, " + param_name + "_len);"
                          " " + param_name + "_str[" + param_name + "_len] = 0;";
 
         pexpr_string = param_name + "_str";
-        extra_cleanup += " delete[] " + param_name + "_str;";
         expected_params += "unicode";
 
       } else if (TypeManager::is_wstring(orig_type)) {
@@ -3018,14 +3113,13 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
         parameter_list += ", &" + param_name;
 
         extra_convert += " Py_ssize_t " + param_name + "_len = PyUnicode_GetSize((PyObject *)" + param_name + ");"
-                         " wchar_t *" + param_name + "_str = new wchar_t[" + param_name + "_len];"
+                         " wchar_t *" + param_name + "_str = (wchar_t *)alloca(sizeof(wchar_t) * " + param_name + "_len);"
                          " PyUnicode_AsWideChar(" + param_name + ", " + param_name + "_str, " + param_name + "_len);";
 
-        pexpr_string = "basic_string<wchar_t>((wchar_t *)" +
+        pexpr_string = "basic_string<wchar_t>(" +
           param_name + "_str, " +
           param_name + "_len)";
 
-        extra_cleanup += " delete[] " + param_name + "_str;";
         expected_params += "unicode";
 
       } else if (TypeManager::is_const_ptr_to_basic_string_wchar(orig_type)) {
@@ -3038,14 +3132,13 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
         parameter_list += ", &" + param_name;
 
         extra_convert += " Py_ssize_t " + param_name + "_len = PyUnicode_GetSize((PyObject *)" + param_name + ");"
-                         " wchar_t *" + param_name + "_str = new wchar_t[" + param_name + "_len];"
+                         " wchar_t *" + param_name + "_str = (wchar_t *)alloca(sizeof(wchar_t) * " + param_name + "_len);"
                          " PyUnicode_AsWideChar(" + param_name + ", " + param_name + "_str, " + param_name + "_len);";
 
-        pexpr_string = "&basic_string<wchar_t>((wchar_t *)" +
+        pexpr_string = "&basic_string<wchar_t>(" +
           param_name + "_str, " +
           param_name + "_len)";
 
-        extra_cleanup += " delete[] " + param_name + "_str;";
         expected_params += "unicode";
 
       } else {
@@ -3057,7 +3150,7 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
             << param_name << "_str = PyUnicode_AsUTF8AndSize(arg, &"
             << param_name << "_len);\n";
           out << "#else\n";
-          indent(out, indent_level) << "if (PyString_AsStringAndSize(arg, &" 
+          indent(out, indent_level) << "if (PyString_AsStringAndSize(arg, &"
             << param_name << "_str, &" << param_name << "_len) == -1) {\n";
           indent(out, indent_level + 2) << param_name << "_str = NULL;\n";
           indent(out, indent_level) << "}\n";
@@ -3142,14 +3235,9 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
       ++num_params;
 
     } else if (TypeManager::is_integer(type)) {
-      if (args_type == AT_single_arg) {
-        pexpr_string = "(" + type->get_local_name(&parser) + ")PyInt_AS_LONG(arg)";
-        extra_param_check += " && PyInt_Check(arg)";
-      } else {
-        indent(out, indent_level) << "int " << param_name << ";\n";
-        format_specifiers += "i";
-        parameter_list += ", &" + param_name;
-      }
+      indent(out, indent_level) << "int " << param_name << ";\n";
+      format_specifiers += "i";
+      parameter_list += ", &" + param_name;
       expected_params += "int";
       only_pyobjects = false;
       ++num_params;
@@ -3204,7 +3292,7 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
 
       // It's reasonable to assume that a function taking a PyObject
       // might also throw a TypeError if the type is incorrect.
-      check_exceptions = true;
+      //check_exceptions = true;
 
     } else if (TypeManager::is_pointer_to_Py_buffer(type)) {
       if (args_type == AT_single_arg) {
@@ -3220,7 +3308,7 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
       extra_cleanup += "Py_XDECREF(" + param_name + "_buffer);";
       expected_params += "memoryview";
       ++num_params;
-      check_exceptions = true;
+      //check_exceptions = true;
 
     } else if (TypeManager::is_pointer(type)) {
       CPPType *obj_type = TypeManager::unwrap(TypeManager::resolve_type(type));
@@ -3323,9 +3411,9 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
 
   // If this is the only overload, don't bother checking for type errors.
   // Any type error that is raised will simply pass through to below.
-  if (func->_remaps.size() == 1) {
-    check_exceptions = false;
-  }
+  //if (func->_remaps.size() == 1) {
+  //  check_exceptions = false;
+  //}
 
   // Track how many curly braces we've opened.
   short open_scopes = 0;
@@ -3396,6 +3484,7 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
   }
 
   string return_expr;
+
   if (!remap->_void_return &&
       remap->_return_type->new_type_is_atomic_string()) {
     // Treat strings as a special case.  We don't want to format the
@@ -3475,6 +3564,7 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
         type->output_instance(out, "return_value", &parser);
         out << " = " << return_expr << ";\n";
       }
+
       if (track_interpreter) {
         indent(out, indent_level) << "in_interpreter = 1;\n";
       }
@@ -3487,26 +3577,35 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
       if (!extra_cleanup.empty()) {
         indent(out, indent_level) << extra_cleanup << "\n";
       }
-
-      if (!is_inplace) {
-        return_expr = manage_return_value(out, indent_level, remap, "return_value");
-      }
       if (coercion_possible) {
         indent(out, indent_level)
           << "Py_XDECREF(coerced);\n";
       }
+      if (!is_inplace) {
+        if (remap->_return_type->return_value_needs_management()) {
+          // If a constructor returns NULL, that means allocation failed.
+          indent(out, indent_level) << "if (return_value == NULL) {\n";
+          if (return_int) {
+            indent(out, indent_level) << "  PyErr_NoMemory();\n";
+            indent(out, indent_level) << "  return -1;\n";
+          } else {
+            indent(out, indent_level) << "  return PyErr_NoMemory();\n";
+          }
+          indent(out, indent_level) << "}\n";
+        }
+
+        return_expr = manage_return_value(out, indent_level, remap, "return_value");
+      }
       return_expr = remap->_return_type->temporary_to_return(return_expr);
     }
   }
 
   // If a method raises TypeError, continue.
-  if (check_exceptions) {
+  //if (check_exceptions) {
+  if (true) {
     indent(out, indent_level)
       << "if (PyErr_Occurred()) {\n";
-    if (return_int && !return_expr.empty()) {
-      indent(out, indent_level + 2)
-        << "delete return_value;\n";
-    }
+    delete_return_value(out, indent_level, remap, return_expr);
     indent(out, indent_level)
       << "  if (PyErr_ExceptionMatches(PyExc_TypeError)) {\n";
     indent(out, indent_level)
@@ -3541,10 +3640,8 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
       << "PyErr_SetString(PyExc_AssertionError, notify->get_assert_error_message().c_str());\n";
     indent(out, indent_level + 2)
       << "notify->clear_assert_failed();\n";
+    delete_return_value(out, indent_level + 2, remap, return_expr);
     if (return_int) {
-      if (!return_expr.empty()) {
-        indent(out, indent_level + 2) << "delete return_value;\n";
-      }
       indent(out, indent_level + 2) << "return -1;\n";
     } else {
       indent(out, indent_level + 2) << "return (PyObject *)NULL;\n";
@@ -3967,13 +4064,30 @@ record_object(TypeIndex type_index) {
   for (int ei = 0; ei < num_elements; ei++) {
     ElementIndex element_index = itype.get_element(ei);
     const InterrogateElement &ielement = idb->get_element(element_index);
+
+    Property *property = new Property(ielement);
+
+    if (ielement.has_setter()) {
+      FunctionIndex func_index = ielement.get_setter();
+      Function *setter = record_function(itype, func_index);
+      if (is_function_legal(setter)) {
+        property->_setter = setter;
+      }
+    }
+
     if (ielement.has_getter()) {
       FunctionIndex func_index = ielement.get_getter();
-      record_function(itype, func_index);
+      Function *getter = record_function(itype, func_index);
+      if (is_function_legal(getter)) {
+        property->_getter = getter;
+      }
     }
-    if (ielement.has_setter()) {
-      FunctionIndex func_index = ielement.get_setter();
-      record_function(itype, func_index);
+
+    if (property->_getter != NULL) {
+      object->_properties.push_back(property);
+    } else {
+      // No use exporting a property without a getter.
+      delete property;
     }
   }
 

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

@@ -95,7 +95,7 @@ private:
   void write_function_for_name(ostream &out, Object *obj, Function *func,
                                const std::string &name,
                                bool coercion_allowed, bool &coercion_attempted,
-                               ArgsType args_type, bool return_int);
+                               ArgsType args_type, bool return_int, bool write_comment);
 
   void write_function_forset(ostream &out, Object *obj, Function *func,
                              std::set<FunctionRemap*> &remaps, string &expected_params,

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

@@ -55,9 +55,9 @@ InterfaceMakerPythonObj::
 ////////////////////////////////////////////////////////////////////
 void InterfaceMakerPythonObj::
 write_prototypes(ostream &out, ostream *out_h) {
-  Functions::iterator fi;
+  FunctionsByIndex::iterator fi;
   for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
-    Function *func = (*fi);
+    Function *func = (*fi).second;
     write_prototype_for(out, func);
   }
 
@@ -74,9 +74,9 @@ write_prototypes(ostream &out, ostream *out_h) {
 ////////////////////////////////////////////////////////////////////
 void InterfaceMakerPythonObj::
 write_functions(ostream &out) {
-  Functions::iterator fi;
+  FunctionsByIndex::iterator fi;
   for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
-    Function *func = (*fi);
+    Function *func = (*fi).second;
     write_function_for(out, func);
   }
 
@@ -360,21 +360,21 @@ write_function_instance(ostream &out, int indent_level,
     CPPType *orig_type = remap->_parameters[pn]._remap->get_orig_type();
     CPPType *type = remap->_parameters[pn]._remap->get_new_type();
     string param_name = remap->get_parameter_name(pn);
-    
+
     // This is the string to convert our local variable to the
     // appropriate C++ type.  Normally this is just a cast.
     string pexpr_string =
       "(" + type->get_local_name(&parser) + ")" + param_name;
-    
+
     if (remap->_parameters[pn]._remap->new_type_is_atomic_string()) {
       if (TypeManager::is_char_pointer(orig_type)) {
         out << "char *" << param_name;
         format_specifiers += "s";
         parameter_list += ", &" + param_name;
-        
+
       } else {
         out << "char *" << param_name
-            << "_str; int " << param_name << "_len";
+            << "_str; Py_ssize_t " << param_name << "_len";
         format_specifiers += "s#";
         parameter_list += ", &" + param_name
           + "_str, &" + param_name + "_len";
@@ -383,7 +383,7 @@ write_function_instance(ostream &out, int indent_level,
           param_name + "_len)";
       }
       expected_params += "string";
-      
+
     } else if (TypeManager::is_bool(type)) {
       out << "PyObject *" << param_name;
       format_specifiers += "O";

+ 12 - 12
dtool/src/interrogate/interfaceMakerPythonSimple.cxx

@@ -53,9 +53,9 @@ InterfaceMakerPythonSimple::
 ////////////////////////////////////////////////////////////////////
 void InterfaceMakerPythonSimple::
 write_prototypes(ostream &out,ostream *out_h) {
-  Functions::iterator fi;
+  FunctionsByIndex::iterator fi;
   for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
-    Function *func = (*fi);
+    Function *func = (*fi).second;
     write_prototype_for(out, func);
   }
 
@@ -72,9 +72,9 @@ write_prototypes(ostream &out,ostream *out_h) {
 ////////////////////////////////////////////////////////////////////
 void InterfaceMakerPythonSimple::
 write_functions(ostream &out) {
-  Functions::iterator fi;
+  FunctionsByIndex::iterator fi;
   for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
-    Function *func = (*fi);
+    Function *func = (*fi).second;
     write_function_for(out, func);
   }
 
@@ -93,9 +93,9 @@ write_module(ostream &out,ostream *out_h, InterrogateModuleDef *def) {
 
   out << "static PyMethodDef python_simple_funcs[] = {\n";
 
-  Functions::iterator fi;
+  FunctionsByIndex::iterator fi;
   for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
-    Function *func = (*fi);
+    Function *func = (*fi).second;
     Function::Remaps::const_iterator ri;
     for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) {
       FunctionRemap *remap = (*ri);
@@ -270,21 +270,21 @@ void InterfaceMakerPythonSimple::write_function_instance(ostream &out, Interface
     CPPType *orig_type = remap->_parameters[pn]._remap->get_orig_type();
     CPPType *type = remap->_parameters[pn]._remap->get_new_type();
     string param_name = remap->get_parameter_name(pn);
-    
+
     // This is the string to convert our local variable to the
     // appropriate C++ type.  Normally this is just a cast.
     string pexpr_string =
       "(" + type->get_local_name(&parser) + ")" + param_name;
-    
+
     if (remap->_parameters[pn]._remap->new_type_is_atomic_string()) {
       if (TypeManager::is_char_pointer(orig_type)) {
         out << "char *" << param_name;
         format_specifiers += "s";
         parameter_list += ", &" + param_name;
-        
+
       } else if (TypeManager::is_wstring(orig_type)) {
         out << "Py_UNICODE *" << param_name
-            << "_str; int " << param_name << "_len";
+            << "_str; Py_ssize_t " << param_name << "_len";
         format_specifiers += "u#";
         parameter_list += ", &" + param_name
           + "_str, &" + param_name + "_len";
@@ -294,7 +294,7 @@ void InterfaceMakerPythonSimple::write_function_instance(ostream &out, Interface
 
       } else {
         out << "char *" << param_name
-            << "_str; int " << param_name << "_len";
+            << "_str; Py_ssize_t " << param_name << "_len";
         format_specifiers += "s#";
         parameter_list += ", &" + param_name
           + "_str, &" + param_name + "_len";
@@ -302,7 +302,7 @@ void InterfaceMakerPythonSimple::write_function_instance(ostream &out, Interface
           param_name + "_str, " +
           param_name + "_len)";
       }
-      
+
     } else if (TypeManager::is_bool(type)) {
       out << "PyObject *" << param_name;
       format_specifiers += "O";

+ 99 - 0
dtool/src/interrogate/interrogateBuilder.cxx

@@ -44,6 +44,7 @@
 #include "cppTypeDeclaration.h"
 #include "cppEnumType.h"
 #include "cppCommentBlock.h"
+#include "cppMakeProperty.h"
 #include "cppMakeSeq.h"
 #include "pnotify.h"
 
@@ -1357,6 +1358,11 @@ scan_element(CPPInstance *element, CPPStructType *struct_type,
   ielement._name = element->get_local_name(scope);
   ielement._scoped_name = descope(element->get_local_name(&parser));
 
+  // See if there happens to be a comment before the element.
+  if (element->_leading_comment != (CPPCommentBlock *)NULL) {
+    ielement._comment = trim_blanks(element->_leading_comment->_comment);
+  }
+
   ielement._type = get_type(TypeManager::unwrap_reference(element_type), false);
   if (ielement._type == 0) {
     // If we can't understand what type it is, forget it.
@@ -1641,6 +1647,7 @@ get_function(CPPInstance *function, string description,
              CPPStructType *struct_type,
              CPPScope *scope, int flags,
              const string &expression) {
+
   // Get a unique function signature.  Make sure we tell the function
   // where its native scope is, so we get a fully-scoped signature.
 
@@ -1768,6 +1775,90 @@ get_function(CPPInstance *function, string description,
   return index;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: InterrogateBuilder::get_make_property
+//       Access: Private
+//  Description: Adds the indicated make_property to the database,
+//               if it is not already present.  In either case,
+//               returns the MakeSeqIndex of the make_seq within the
+//               database.
+////////////////////////////////////////////////////////////////////
+ElementIndex InterrogateBuilder::
+get_make_property(CPPMakeProperty *make_property, CPPStructType *struct_type) {
+  string property_name = make_property->get_local_name(&parser);
+
+  // First, check to see if it's already there.
+  PropertiesByName::const_iterator tni =
+    _properties_by_name.find(property_name);
+  if (tni != _properties_by_name.end()) {
+    ElementIndex index = (*tni).second;
+    return index;
+  }
+
+  // Find the getter so we can get its return type.
+  CPPInstance *getter = NULL;
+  CPPType *return_type = NULL;
+
+  CPPFunctionGroup *fgroup = make_property->_getter;
+  CPPFunctionGroup::Instances::const_iterator fi;
+  for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) {
+    CPPInstance *function = (*fi);
+    CPPFunctionType *ftype =
+      function->_type->as_function_type();
+    if (ftype != NULL && ftype->_parameters->_parameters.size() == 0) {
+      getter = function;
+      return_type = ftype->_return_type;
+
+      // The return type of the non-const method probably better represents
+      // the type of the property we are creating.
+      if ((ftype->_flags & CPPFunctionType::F_const_method) == 0) {
+        break;
+      }
+    }
+  }
+
+  if (getter == NULL || return_type == NULL) {
+    cerr << "No instance of getter '"
+         << make_property->_getter->_name << "' is suitable!\n";
+    return 0;
+  }
+
+  InterrogateDatabase *idb = InterrogateDatabase::get_ptr();
+  // It isn't here, so we'll have to define it.
+  ElementIndex index = idb->get_next_index();
+  _properties_by_name[property_name] = index;
+
+  InterrogateElement iproperty;
+  iproperty._name = make_property->get_simple_name();
+  iproperty._scoped_name = descope(make_property->get_local_name(&parser));
+
+  iproperty._type = get_type(return_type, false);
+
+  iproperty._flags |= InterrogateElement::F_has_getter;
+  iproperty._getter = get_function(getter, "", struct_type,
+                                   struct_type->get_scope(), 0);
+
+  // See if there happens to be a comment before the MAKE_PROPERTY macro.
+  if (make_property->_leading_comment != (CPPCommentBlock *)NULL) {
+    iproperty._comment = trim_blanks(make_property->_leading_comment->_comment);
+  }
+
+  // Now look for setters.
+  fgroup = make_property->_setter;
+  if (fgroup != NULL) {
+    for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) {
+      CPPInstance *function = (*fi);
+      iproperty._flags |= InterrogateElement::F_has_setter;
+      iproperty._setter = get_function(function, "", struct_type,
+                                       struct_type->get_scope(), 0);
+    }
+  }
+
+  idb->add_element(index, iproperty);
+
+  return index;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: InterrogateBuilder::get_make_seq
 //       Access: Private
@@ -2279,6 +2370,10 @@ define_struct_type(InterrogateType &itype, CPPStructType *cpptype,
         TypeIndex nested_index = get_type(type, false);
         itype._nested_types.push_back(nested_index);
       }
+
+    } else if ((*di)->get_subtype() == CPPDeclaration::ST_make_property) {
+      ElementIndex element_index = get_make_property((*di)->as_make_property(), cpptype);
+      itype._elements.push_back(element_index);
     }
   }
 
@@ -2566,6 +2661,10 @@ define_enum_type(InterrogateType &itype, CPPEnumType *cpptype) {
     evalue._name = element->get_simple_name();
     evalue._scoped_name = descope(element->get_local_name(&parser));
 
+    if (element->_leading_comment != (CPPCommentBlock *)NULL) {
+      evalue._comment = trim_blanks(element->_leading_comment->_comment);
+    }
+
     if (element->_initializer != (CPPExpression *)NULL) {
       CPPExpression::Result result = element->_initializer->evaluate();
       next_value = result.as_integer();

+ 6 - 0
dtool/src/interrogate/interrogateBuilder.h

@@ -38,6 +38,7 @@ class CPPScope;
 class CPPIdentifier;
 class CPPNameComponent;
 class CPPManifest;
+class CPPMakeProperty;
 class CPPMakeSeq;
 class InterrogateType;
 class InterrogateFunction;
@@ -108,6 +109,9 @@ public:
                CPPStructType *struct_type, CPPScope *scope,
                int flags, const string &expression = string());
 
+  ElementIndex
+  get_make_property(CPPMakeProperty *make_property, CPPStructType *struct_type);
+
   MakeSeqIndex
   get_make_seq(CPPMakeSeq *make_seq, CPPStructType *struct_type);
 
@@ -132,10 +136,12 @@ public:
   typedef map<string, TypeIndex> TypesByName;
   typedef map<string, FunctionIndex> FunctionsByName;
   typedef map<string, MakeSeqIndex> MakeSeqsByName;
+  typedef map<string, ElementIndex> PropertiesByName;
 
   TypesByName _types_by_name;
   FunctionsByName _functions_by_name;
   MakeSeqsByName _make_seqs_by_name;
+  PropertiesByName _properties_by_name;
 
   typedef map<string, char> IncludeFiles;
   IncludeFiles _include_files;

+ 1 - 1
dtool/src/interrogatedb/interrogateDatabase.cxx

@@ -21,7 +21,7 @@ InterrogateDatabase *InterrogateDatabase::_global_ptr = NULL;
 int InterrogateDatabase::_file_major_version = 0;
 int InterrogateDatabase::_file_minor_version = 0;
 int InterrogateDatabase::_current_major_version = 2;
-int InterrogateDatabase::_current_minor_version = 2;
+int InterrogateDatabase::_current_minor_version = 3;
 
 ////////////////////////////////////////////////////////////////////
 //     Function: InterrogateDatabase::Constructor

+ 21 - 0
dtool/src/interrogatedb/interrogateElement.I

@@ -48,6 +48,7 @@ operator = (const InterrogateElement &copy) {
   InterrogateComponent::operator = (copy);
   _flags = copy._flags;
   _scoped_name = copy._scoped_name;
+  _comment = copy._comment;
   _type = copy._type;
   _getter = copy._getter;
   _setter = copy._setter;
@@ -85,6 +86,26 @@ get_scoped_name() const {
   return _scoped_name;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: InterrogateElement::has_comment
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool InterrogateElement::
+has_comment() const {
+  return !_comment.empty();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterrogateElement::get_comment
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE const string &InterrogateElement::
+get_comment() const {
+  return _comment;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Element: InterrogateElement::get_type
 //       Access: Public

+ 5 - 0
dtool/src/interrogatedb/interrogateElement.cxx

@@ -30,6 +30,7 @@ output(ostream &out) const {
       << _getter << " "
       << _setter << " ";
   idf_output_string(out, _scoped_name);
+  idf_output_string(out, _comment, '\n');
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -43,6 +44,10 @@ input(istream &in) {
   InterrogateComponent::input(in);
   in >> _flags >> _type >> _getter >> _setter;
   idf_input_string(in, _scoped_name);
+
+  if (InterrogateDatabase::get_file_minor_version() >= 3) {
+    idf_input_string(in, _comment);
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

+ 4 - 0
dtool/src/interrogatedb/interrogateElement.h

@@ -37,6 +37,9 @@ public:
   INLINE bool has_scoped_name() const;
   INLINE const string &get_scoped_name() const;
 
+  INLINE bool has_comment() const;
+  INLINE const string &get_comment() const;
+
   INLINE TypeIndex get_type() const;
   INLINE bool has_getter() const;
   INLINE FunctionIndex get_getter() const;
@@ -57,6 +60,7 @@ private:
 
   int _flags;
   string _scoped_name;
+  string _comment;
   TypeIndex _type;
   FunctionIndex _getter;
   FunctionIndex _setter;

+ 13 - 0
dtool/src/interrogatedb/interrogateType.I

@@ -263,6 +263,19 @@ get_enum_value_scoped_name(int n) const {
   return _empty_string;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: InterrogateType::get_enum_value_comment
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE const string &InterrogateType::
+get_enum_value_comment(int n) const {
+  if (n >= 0 && n < (int)_enum_values.size()) {
+    return _enum_values[n]._comment;
+  }
+  return _empty_string;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: InterrogateType::get_enum_value
 //       Access: Public

+ 5 - 0
dtool/src/interrogatedb/interrogateType.cxx

@@ -15,6 +15,7 @@
 #include "interrogateType.h"
 #include "indexRemapper.h"
 #include "interrogate_datafile.h"
+#include "interrogateDatabase.h"
 
 #include <algorithm>
 
@@ -76,6 +77,7 @@ void InterrogateType::EnumValue::
 output(ostream &out) const {
   idf_output_string(out, _name);
   idf_output_string(out, _scoped_name);
+  idf_output_string(out, _comment, '\n');
   out << _value;
 }
 
@@ -88,6 +90,9 @@ void InterrogateType::EnumValue::
 input(istream &in) {
   idf_input_string(in, _name);
   idf_input_string(in, _scoped_name);
+  if (InterrogateDatabase::get_file_minor_version() >= 3) {
+    idf_input_string(in, _comment);
+  }
   in >> _value;
 }
 

+ 2 - 0
dtool/src/interrogatedb/interrogateType.h

@@ -66,6 +66,7 @@ public:
   INLINE int number_of_enum_values() const;
   INLINE const string &get_enum_value_name(int n) const;
   INLINE const string &get_enum_value_scoped_name(int n) const;
+  INLINE const string &get_enum_value_comment(int n) const;
   INLINE int get_enum_value(int n) const;
 
   INLINE bool is_struct() const;
@@ -189,6 +190,7 @@ public:
 
     string _name;
     string _scoped_name;
+    string _comment;
     int _value;
   };
 

+ 18 - 0
dtool/src/interrogatedb/interrogate_interface.cxx

@@ -120,6 +120,18 @@ interrogate_element_scoped_name(ElementIndex element) {
   return InterrogateDatabase::get_ptr()->get_element(element).get_scoped_name().c_str();
 }
 
+bool
+interrogate_element_has_comment(ElementIndex element) {
+  //cerr << "interrogate_element_has_comment(" << element << ")\n";
+  return InterrogateDatabase::get_ptr()->get_element(element).has_comment();
+}
+
+const char *
+interrogate_element_comment(ElementIndex element) {
+  //cerr << "interrogate_element_comment(" << element << ")\n";
+  return InterrogateDatabase::get_ptr()->get_element(element).get_comment().c_str();
+}
+
 ElementIndex
 interrogate_get_element_by_name(const char *element_name) {
   //cerr << "interrogate_get_element_by_name(" << element_name << ")\n";
@@ -631,6 +643,12 @@ interrogate_type_enum_value_scoped_name(TypeIndex type, int n) {
   return InterrogateDatabase::get_ptr()->get_type(type).get_enum_value_scoped_name(n).c_str();
 }
 
+const char *
+interrogate_type_enum_value_comment(TypeIndex type, int n) {
+  //cerr << "interrogate_type_enum_value_comment(" << type << ", " << n << ")\n";
+  return InterrogateDatabase::get_ptr()->get_type(type).get_enum_value_comment(n).c_str();
+}
+
 int
 interrogate_type_enum_value(TypeIndex type, int n) {
   //cerr << "interrogate_type_enum_value(" << type << ", " << n << ")\n";

+ 3 - 0
dtool/src/interrogatedb/interrogate_interface.h

@@ -138,6 +138,8 @@ EXPCL_DTOOLCONFIG int interrogate_manifest_get_int_value(ManifestIndex manifest)
 
 EXPCL_DTOOLCONFIG const char *interrogate_element_name(ElementIndex element);
 EXPCL_DTOOLCONFIG const char *interrogate_element_scoped_name(ElementIndex element);
+EXPCL_DTOOLCONFIG bool interrogate_element_has_comment(ElementIndex element);
+EXPCL_DTOOLCONFIG const char *interrogate_element_comment(ElementIndex element);
 EXPCL_DTOOLCONFIG ElementIndex interrogate_get_element_by_name(const char *element_name);
 EXPCL_DTOOLCONFIG ElementIndex interrogate_get_element_by_scoped_name(const char *element_name);
 
@@ -454,6 +456,7 @@ EXPCL_DTOOLCONFIG bool interrogate_type_is_enum(TypeIndex type);
 EXPCL_DTOOLCONFIG int interrogate_type_number_of_enum_values(TypeIndex type);
 EXPCL_DTOOLCONFIG const char *interrogate_type_enum_value_name(TypeIndex type, int n);
 EXPCL_DTOOLCONFIG const char *interrogate_type_enum_value_scoped_name(TypeIndex type, int n);
+EXPCL_DTOOLCONFIG const char *interrogate_type_enum_value_comment(TypeIndex type, int n);
 EXPCL_DTOOLCONFIG int interrogate_type_enum_value(TypeIndex type, int n);
 
 // If none of the above is true, the type is some extension type.  It

+ 2 - 0
dtool/src/pystub/pystub.cxx

@@ -40,6 +40,7 @@ extern "C" {
   EXPCL_PYSTUB int PyErr_ExceptionMatches(...);
   EXPCL_PYSTUB int PyErr_Fetch(...);
   EXPCL_PYSTUB int PyErr_Format(...);
+  EXPCL_PYSTUB int PyErr_NoMemory(...);
   EXPCL_PYSTUB int PyErr_Occurred(...);
   EXPCL_PYSTUB int PyErr_Print(...);
   EXPCL_PYSTUB int PyErr_Restore(...);
@@ -214,6 +215,7 @@ int PyErr_Clear(...) { return 0; };
 int PyErr_ExceptionMatches(...) { return 0; };
 int PyErr_Fetch(...) { return 0; }
 int PyErr_Format(...) { return 0; };
+int PyErr_NoMemory(...) { return 0; }
 int PyErr_Occurred(...) { return 0; }
 int PyErr_Print(...) { return 0; }
 int PyErr_Restore(...) { return 0; }

+ 7 - 6
makepanda/makepanda.py

@@ -2877,14 +2877,8 @@ TargetAdd('p3interrogatedb_composite2.obj', opts=OPTS, input='p3interrogatedb_co
 #
 
 OPTS=['DIR:dtool/metalibs/dtoolconfig', 'BUILDING:DTOOLCONFIG']
-if (PkgSkip("PYTHON")):
-  TargetAdd('p3dtoolconfig_pydtool.obj', opts=OPTS, input="null.cxx")
-else:
-  TargetAdd('p3dtoolconfig_pydtool.obj', opts=OPTS, input="pydtool.cxx")
 TargetAdd('p3dtoolconfig_dtoolconfig.obj', opts=OPTS, input='dtoolconfig.cxx')
-TargetAdd('p3dtoolconfig_pydtool.obj', dep='dtool_have_python.dat')
 TargetAdd('libp3dtoolconfig.dll', input='p3dtoolconfig_dtoolconfig.obj')
-TargetAdd('libp3dtoolconfig.dll', input='p3dtoolconfig_pydtool.obj')
 TargetAdd('libp3dtoolconfig.dll', input='p3interrogatedb_composite1.obj')
 TargetAdd('libp3dtoolconfig.dll', input='p3interrogatedb_composite2.obj')
 TargetAdd('libp3dtoolconfig.dll', input='p3dconfig_composite1.obj')
@@ -2893,6 +2887,13 @@ TargetAdd('libp3dtoolconfig.dll', input='p3prc_composite2.obj')
 TargetAdd('libp3dtoolconfig.dll', input='libp3dtool.dll')
 TargetAdd('libp3dtoolconfig.dll', opts=['ADVAPI', 'OPENSSL', 'WINGDI', 'WINUSER'])
 
+if not PkgSkip("PYTHON"):
+  TargetAdd('dtoolconfig_pydtool.obj', opts=OPTS, input="pydtool.cxx")
+  TargetAdd('dtoolconfig.pyd', input='dtoolconfig_pydtool.obj')
+  TargetAdd('dtoolconfig.pyd', input='libp3dtoolconfig.dll')
+  TargetAdd('dtoolconfig.pyd', input='libp3dtool.dll')
+  TargetAdd('dtoolconfig.pyd', opts=['PYTHON'])
+
 #
 # DIRECTORY: dtool/src/pystub/
 #

+ 12 - 3
makepanda/makepandacore.py

@@ -430,6 +430,8 @@ def GetBison():
         # We don't strictly need it, so don't give an error
         return None
 
+    return BISON
+
 FLEX = None
 def GetFlex():
     global FLEX
@@ -445,6 +447,8 @@ def GetFlex():
         # We don't strictly need it, so don't give an error
         return None
 
+    return FLEX
+
 ########################################################################
 ##
 ## LocateBinary
@@ -1842,13 +1846,18 @@ def SdkLocatePython(force_use_sys_executable = False):
                 exit("Could not find %s!" % SDK["PYTHONEXEC"])
 
             # Determine which version it is by checking which dll is in the directory.
-            py_dlls = glob.glob(SDK["PYTHON"] + "/python[0-9][0-9].dll")
+            if (GetOptimize() <= 2):
+                py_dlls = glob.glob(SDK["PYTHON"] + "/python[0-9][0-9]_d.dll")
+            else:
+                py_dlls = glob.glob(SDK["PYTHON"] + "/python[0-9][0-9].dll")
+
             if len(py_dlls) == 0:
                 exit("Could not find the Python dll in %s." % (SDK["PYTHON"]))
             elif len(py_dlls) > 1:
                 exit("Found multiple Python dlls in %s." % (SDK["PYTHON"]))
 
-            SDK["PYTHONVERSION"] = "python" + py_dlls[0][-6] + "." + py_dlls[0][-5]
+            py_dll = os.path.basename(py_dlls[0])
+            SDK["PYTHONVERSION"] = "python" + py_dll[6] + "." + py_dll[7]
 
         elif (GetTarget() == 'windows'):
             SDK["PYTHON"] = os.path.dirname(sysconfig.get_python_inc())
@@ -2581,7 +2590,7 @@ def CalcLocation(fn, ipath):
         if (fn.endswith(".res")):   return OUTPUTDIR+"/tmp/"+fn
         if (fn.endswith(".tlb")):   return OUTPUTDIR+"/tmp/"+fn
         if (fn.endswith(".dll")):   return OUTPUTDIR+"/bin/"+fn[:-4]+dllext+".dll"
-        if (fn.endswith(".pyd")):   return OUTPUTDIR+"/panda3d/"+fn[:-4]+dllext+".pyd"
+        if (fn.endswith(".pyd")):   return OUTPUTDIR+"/panda3d/"+fn[:-4]+".pyd"
         if (fn.endswith(".ocx")):   return OUTPUTDIR+"/plugins/"+fn[:-4]+dllext+".ocx"
         if (fn.endswith(".mll")):   return OUTPUTDIR+"/plugins/"+fn[:-4]+dllext+".mll"
         if (fn.endswith(".dlo")):   return OUTPUTDIR+"/plugins/"+fn[:-4]+dllext+".dlo"

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

@@ -668,3 +668,35 @@ set_transform_dirty() {
   transform_changed();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BulletBodyNode::get_shape_bounds
+//       Access: Published
+//  Description: Returns the current bounds of all collision shapes
+//               owned by this body.
+////////////////////////////////////////////////////////////////////
+BoundingSphere BulletBodyNode::
+get_shape_bounds() const {
+
+/*
+  btTransform tr;
+  tr.setIdentity();
+  btVector3 aabbMin,aabbMax;
+  ptr()->getAabb(tr,aabbMin,aabbMax);
+  btVector3 o = tr.getOrigin();
+cout << "aabbMin " << aabbMin.x() << " " << aabbMin.y() << " " << aabbMin.z() << endl;
+cout << "aabbMax " << aabbMax.x() << " " << aabbMax.y() << " " << aabbMax.z() << endl;
+cout << "origin " << aabbMin.x() << " " << aabbMin.y() << " " << aabbMin.z() << endl;
+*/
+
+  btVector3 center;
+  btScalar radius;
+
+  if (_shape) {
+    _shape->getBoundingSphere(center, radius);
+  }
+
+  BoundingSphere bounds(btVector3_to_LPoint3(center), (PN_stdfloat)radius);
+
+  return bounds;
+}
+

+ 2 - 0
panda/src/bullet/bulletBodyNode.h

@@ -24,6 +24,7 @@
 #include "collideMask.h"
 #include "collisionNode.h"
 #include "transformState.h"
+#include "boundingSphere.h"
 
 class BulletShape;
 
@@ -47,6 +48,7 @@ PUBLISHED:
 
   LPoint3 get_shape_pos(int idx) const;
   LMatrix4 get_shape_mat(int idx) const;
+  BoundingSphere get_shape_bounds() const;
 
   void add_shapes_from_collision_solids(CollisionNode *cnode);
 

+ 28 - 0
panda/src/bullet/bulletShape.cxx

@@ -73,3 +73,31 @@ set_local_scale(const LVecBase3 &scale) {
   ptr()->setLocalScaling(LVecBase3_to_btVector3(scale));
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BulletShape::get_shape_bounds
+//       Access: Published
+//  Description: Returns the current bounds of this collision shape.
+////////////////////////////////////////////////////////////////////
+BoundingSphere BulletShape::
+get_shape_bounds() const {
+
+/*
+  btTransform tr;
+  tr.setIdentity();
+  btVector3 aabbMin,aabbMax;
+  ptr()->getAabb(tr,aabbMin,aabbMax);
+  btVector3 o = tr.getOrigin();
+cout << "aabbMin " << aabbMin.x() << " " << aabbMin.y() << " " << aabbMin.z() << endl;
+cout << "aabbMax " << aabbMax.x() << " " << aabbMax.y() << " " << aabbMax.z() << endl;
+cout << "origin " << aabbMin.x() << " " << aabbMin.y() << " " << aabbMin.z() << endl;
+*/
+
+  btVector3 center;
+  btScalar radius;
+
+  ptr()->getBoundingSphere(center, radius);
+  BoundingSphere bounds(btVector3_to_LPoint3(center), (PN_stdfloat)radius);
+
+  return bounds;
+}
+

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

@@ -20,6 +20,7 @@
 #include "bullet_includes.h"
 
 #include "typedReferenceCount.h"
+#include "boundingSphere.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : BulletShape
@@ -43,6 +44,8 @@ PUBLISHED:
 
   PN_stdfloat get_margin() const;
 
+  BoundingSphere get_shape_bounds() const;
+
 public:
   virtual btCollisionShape *ptr() const = 0;
 

+ 4 - 3
panda/src/collide/collisionHandlerPusher.cxx

@@ -18,6 +18,7 @@
 #include "collisionPolygon.h"
 #include "config_collide.h"
 #include "dcast.h"
+#include "epvector.h"
 
 TypeHandle CollisionHandlerPusher::_type_handle;
 
@@ -95,7 +96,7 @@ handle_entries() {
         // shove.  We hack around this by testing if two shove vectors
         // share nearly the same direction, and if so, we keep only the
         // longer of the two.
-        
+
         typedef epvector<ShoveData> Shoves;
         Shoves shoves;
 
@@ -110,13 +111,13 @@ handle_entries() {
           LPoint3 interior_point;
 
           if (!entry->get_all(def._target, surface_point, normal, interior_point)) {
-            #ifndef NDEBUG          
+#ifndef NDEBUG
             if (collide_cat.is_debug()) {
               collide_cat.debug()
                 << "Cannot shove on " << from_node_path << " for collision into "
                 << entry->get_into_node_path() << "; no normal/depth information.\n";
             }
-            #endif            
+#endif
           } else {
             // Shove it just enough to clear the volume.
             if (!surface_point.almost_equal(interior_point)) {

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

@@ -38,6 +38,7 @@
 #include "geomLinestrips.h"
 #include "geomVertexWriter.h"
 #include "renderState.h"
+#include "epvector.h"
 
 #include <algorithm>
 
@@ -1491,14 +1492,14 @@ fillin(DatagramIterator &scan, BamReader *manager) {
     if (_points.size() >= 3) {
       LMatrix4 to_3d_mat;
       rederive_to_3d_mat(to_3d_mat);
-      
+
       epvector<LPoint3> verts;
       verts.reserve(_points.size());
       Points::const_iterator pi;
       for (pi = _points.begin(); pi != _points.end(); ++pi) {
         verts.push_back(to_3d((*pi)._p, to_3d_mat));
       }
-      
+
       const LPoint3 *verts_begin = &verts[0];
       const LPoint3 *verts_end = verts_begin + verts.size();
       setup_points(verts_begin, verts_end);

+ 38 - 0
panda/src/display/displayRegion.I

@@ -331,6 +331,32 @@ get_target_tex_page() const {
   return cdata->_target_tex_page;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: DisplayRegion::set_scissor_enabled
+//       Access: Published
+//  Description: Sets whether or not scissor testing is enabled
+//               for this region.  The default is true, except for
+//               the overlay display region.
+////////////////////////////////////////////////////////////////////
+INLINE void DisplayRegion::
+set_scissor_enabled(bool scissor_enabled) {
+  CDWriter cdata(_cycler);
+  cdata->_scissor_enabled = scissor_enabled;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DisplayRegion::get_scissor_enabled
+//       Access: Published
+//  Description: Returns whether or not scissor testing is enabled
+//               for this region.  The default is true, except for
+//               the overlay display region.
+////////////////////////////////////////////////////////////////////
+INLINE bool DisplayRegion::
+get_scissor_enabled() const {
+  CDReader cdata(_cycler);
+  return cdata->_scissor_enabled;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegion::set_cull_callback
 //       Access: Published
@@ -941,6 +967,18 @@ get_target_tex_page() const {
   return _cdata->_target_tex_page;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: DisplayRegionPipelineReader::get_scissor_enabled
+//       Access: Published
+//  Description: Returns whether or not scissor testing is enabled
+//               for this region.  The default is true, except for
+//               the overlay display region.
+////////////////////////////////////////////////////////////////////
+INLINE bool DisplayRegionPipelineReader::
+get_scissor_enabled() const {
+  return _cdata->_scissor_enabled;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegionPipelineReader::get_draw_callback
 //       Access: Published

+ 5 - 3
panda/src/display/displayRegion.cxx

@@ -392,7 +392,7 @@ get_cull_traverser() {
 //       Access: Published, Virtual
 //  Description: This is a special parameter that is only used when
 //               rendering the faces of a cube map or multipage and/or
-//               multiview texture.  
+//               multiview texture.
 //
 //               This sets up the DisplayRegion to render to the ith
 //               page and jth view of its associated texture(s); the
@@ -832,7 +832,8 @@ CData() :
   _sort(0),
   _stereo_channel(Lens::SC_mono),
   _tex_view_offset(0),
-  _target_tex_page(-1)
+  _target_tex_page(-1),
+  _scissor_enabled(true)
 {
   _regions.push_back(Region());
 }
@@ -852,7 +853,8 @@ CData(const DisplayRegion::CData &copy) :
   _sort(copy._sort),
   _stereo_channel(copy._stereo_channel),
   _tex_view_offset(copy._tex_view_offset),
-  _target_tex_page(copy._target_tex_page)
+  _target_tex_page(copy._target_tex_page),
+  _scissor_enabled(copy._scissor_enabled)
 {
 }
 

+ 9 - 3
panda/src/display/displayRegion.h

@@ -38,6 +38,7 @@
 #include "cullTraverser.h"
 #include "callbackObject.h"
 #include "luse.h"
+#include "epvector.h"
 
 class GraphicsOutput;
 class GraphicsPipe;
@@ -120,6 +121,9 @@ PUBLISHED:
   virtual void set_target_tex_page(int page);
   INLINE int get_target_tex_page() const;
 
+  INLINE void set_scissor_enabled(bool scissor_enabled);
+  INLINE bool get_scissor_enabled() const;
+
   INLINE void set_cull_callback(CallbackObject *object);
   INLINE void clear_cull_callback();
   INLINE CallbackObject *get_cull_callback() const;
@@ -172,7 +176,7 @@ public:
     LVecBase4i _pixels;
     LVecBase4i _pixels_i;
   };
-  typedef pvector<Region> Regions;
+  typedef epvector<Region> Regions;
 
 private:
   class CData;
@@ -214,15 +218,16 @@ private:
     Regions _regions;
 
     int _lens_index; // index into which lens of a camera is associated with this display region.  0 is default
-    
+
     NodePath _camera;
     Camera *_camera_node;
-    
+
     bool _active;
     int _sort;
     Lens::StereoChannel _stereo_channel;
     int _tex_view_offset;
     int _target_tex_page;
+    bool _scissor_enabled;
 
     PT(CallbackObject) _cull_callback;
     PT(CallbackObject) _draw_callback;
@@ -323,6 +328,7 @@ public:
   INLINE int get_tex_view_offset();
   INLINE bool get_clear_depth_between_eyes() const;
   INLINE int get_target_tex_page() const;
+  INLINE bool get_scissor_enabled() const;
   INLINE CallbackObject *get_draw_callback() const;
 
   INLINE void get_pixels(int &pl, int &pr, int &pb, int &pt) const;

+ 3 - 3
panda/src/display/graphicsBuffer.cxx

@@ -41,19 +41,19 @@ GraphicsBuffer(GraphicsEngine *engine, GraphicsPipe *pipe,
       << "Creating new offscreen buffer " << get_name() << "\n";
   }
 
-  _overlay_display_region->compute_pixels(_x_size, _y_size);
+  _overlay_display_region->compute_pixels(_size.get_x(), _size.get_y());
   _open_request = OR_none;
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsBuffer::Destructor
 //       Access: Published, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 GraphicsBuffer::
 ~GraphicsBuffer() {
 }
- 
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsBuffer::set_size
 //       Access: Public, Virtual

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

@@ -40,7 +40,7 @@ protected:
 
 PUBLISHED:
   virtual ~GraphicsBuffer();
-  void set_size(int x, int y);
+  virtual void set_size(int x, int y);
 
 public:
   virtual void request_open();

+ 27 - 8
panda/src/display/graphicsOutput.I

@@ -150,6 +150,25 @@ get_rtm_mode(int i) const {
   return cdata->_textures[i]._rtm_mode;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::get_size
+//       Access: Published
+//  Description: Returns the visible size of the window or buffer, if
+//               it is known.  In certain cases (e.g. fullscreen
+//               windows), the size may not be known until after the
+//               object has been fully created.  Check has_size()
+//               first.
+//
+//               Certain objects (like windows) may change size
+//               spontaneously; this method is not thread-safe.  To
+//               get the size of a window in a thread-safe manner,
+//               query get_properties().
+////////////////////////////////////////////////////////////////////
+INLINE const LVecBase2i &GraphicsOutput::
+get_size() const {
+  return _size;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsOutput::get_x_size
 //       Access: Published
@@ -166,7 +185,7 @@ get_rtm_mode(int i) const {
 ////////////////////////////////////////////////////////////////////
 INLINE int GraphicsOutput::
 get_x_size() const {
-  return _x_size;
+  return _size.get_x();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -185,7 +204,7 @@ get_x_size() const {
 ////////////////////////////////////////////////////////////////////
 INLINE int GraphicsOutput::
 get_y_size() const {
-  return _y_size;
+  return _size.get_y();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -198,7 +217,7 @@ get_y_size() const {
 ////////////////////////////////////////////////////////////////////
 INLINE int GraphicsOutput::
 get_fb_x_size() const {
-  return max(int(_x_size * get_pixel_factor()), 1);
+  return max(int(_size.get_x() * get_pixel_factor()), 1);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -211,7 +230,7 @@ get_fb_x_size() const {
 ////////////////////////////////////////////////////////////////////
 INLINE int GraphicsOutput::
 get_fb_y_size() const {
-  return max(int(_y_size * get_pixel_factor()), 1);
+  return max(int(_size.get_y() * get_pixel_factor()), 1);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -226,7 +245,7 @@ get_fb_y_size() const {
 INLINE int GraphicsOutput::
 get_sbs_left_x_size() const {
   PN_stdfloat left_w = _sbs_left_dimensions[1] - _sbs_left_dimensions[0];
-  return max(int(_x_size * left_w), 1);
+  return max(int(_size.get_x() * left_w), 1);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -241,7 +260,7 @@ get_sbs_left_x_size() const {
 INLINE int GraphicsOutput::
 get_sbs_left_y_size() const {
   PN_stdfloat left_h = _sbs_left_dimensions[3] - _sbs_left_dimensions[2];
-  return max(int(_y_size * left_h), 1);
+  return max(int(_size.get_y() * left_h), 1);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -256,7 +275,7 @@ get_sbs_left_y_size() const {
 INLINE int GraphicsOutput::
 get_sbs_right_x_size() const {
   PN_stdfloat right_w = _sbs_right_dimensions[1] - _sbs_right_dimensions[0];
-  return max(int(_x_size * right_w), 1);
+  return max(int(_size.get_x() * right_w), 1);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -271,7 +290,7 @@ get_sbs_right_x_size() const {
 INLINE int GraphicsOutput::
 get_sbs_right_y_size() const {
   PN_stdfloat right_h = _sbs_right_dimensions[3] - _sbs_right_dimensions[2];
-  return max(int(_y_size * right_h), 1);
+  return max(int(_size.get_y() * right_h), 1);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 11 - 12
panda/src/display/graphicsOutput.cxx

@@ -78,7 +78,8 @@ GraphicsOutput(GraphicsEngine *engine, GraphicsPipe *pipe,
                bool default_stereo_flags) :
   _lock("GraphicsOutput"),
   _cull_window_pcollector(_cull_pcollector, name),
-  _draw_window_pcollector(_draw_pcollector, name)
+  _draw_window_pcollector(_draw_pcollector, name),
+  _size(0, 0)
 {
 #ifdef DO_MEMORY_USAGE
   MemoryUsage::update_type(this, this);
@@ -90,13 +91,11 @@ GraphicsOutput(GraphicsEngine *engine, GraphicsPipe *pipe,
   _fb_properties = fb_prop;
   _name = name;
   _creation_flags = flags;
-  _x_size = _y_size = 0;
   _has_size = win_prop.has_size();
   _is_nonzero_size = false;
   if (_has_size) {
-    _x_size = win_prop.get_x_size();
-    _y_size = win_prop.get_y_size();
-    _is_nonzero_size = (_x_size > 0 && _y_size > 0);
+    _size = win_prop.get_size();
+    _is_nonzero_size = (_size[0] > 0 && _size[1] > 0);
   }
   if (_creation_flags & GraphicsPipe::BF_size_track_host) {
     // If we're tracking the host size, we assume we'll be nonzero
@@ -152,6 +151,7 @@ GraphicsOutput(GraphicsEngine *engine, GraphicsPipe *pipe,
   // clear() and get_screenshot().
   _overlay_display_region = make_mono_display_region(0.0f, 1.0f, 0.0f, 1.0f);
   _overlay_display_region->set_active(false);
+  _overlay_display_region->set_scissor_enabled(false);
 
   // Make sure the "active" flag is set true for pipeline stage 0.
   {
@@ -546,14 +546,14 @@ set_inverted(bool inverted) {
   if (_inverted != inverted) {
     _inverted = inverted;
 
-    if (_y_size != 0) {
+    if (get_y_size() != 0) {
       // All of our DisplayRegions need to recompute their pixel
       // positions now.
       TotalDisplayRegions::iterator dri;
       for (dri = _total_display_regions.begin();
            dri != _total_display_regions.end();
            ++dri) {
-        (*dri)->compute_pixels(_x_size, _y_size);
+        (*dri)->compute_pixels(get_x_size(), get_y_size());
       }
     }
   }
@@ -1102,7 +1102,7 @@ make_cube_map(const string &name, int size, NodePath &camera_rig,
 NodePath GraphicsOutput::
 get_texture_card() {
   if (_texture_card == 0) {
-    PT(GeomVertexData) vdata = create_texture_card_vdata(_x_size, _y_size);
+    PT(GeomVertexData) vdata = create_texture_card_vdata(get_x_size(), get_y_size());
     PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_static);
     strip->set_shade_model(Geom::SM_uniform);
     strip->add_next_vertices(4);
@@ -1262,11 +1262,10 @@ clear_pipe() {
 ////////////////////////////////////////////////////////////////////
 void GraphicsOutput::
 set_size_and_recalc(int x, int y) {
-  _x_size = x;
-  _y_size = y;
+  _size.set(x, y);
   _has_size = true;
 
-  _is_nonzero_size = (_x_size > 0 && _y_size > 0);
+  _is_nonzero_size = (x > 0 && y > 0);
 
   int fb_x_size = get_fb_x_size();
   int fb_y_size = get_fb_y_size();
@@ -1498,7 +1497,7 @@ process_events() {
 void GraphicsOutput::
 pixel_factor_changed() {
   if (_has_size) {
-    set_size_and_recalc(_x_size, _y_size);
+    set_size_and_recalc(get_x_size(), get_y_size());
   }
 }
 

+ 8 - 8
panda/src/display/graphicsOutput.h

@@ -128,10 +128,11 @@ PUBLISHED:
   INLINE RenderTexturePlane get_texture_plane(int i=0) const;
   INLINE RenderTextureMode get_rtm_mode(int i=0) const;
   void clear_render_textures();
-  void add_render_texture(Texture *tex, RenderTextureMode mode, 
+  void add_render_texture(Texture *tex, RenderTextureMode mode,
                           RenderTexturePlane bitplane=RTP_COUNT);
   void setup_render_texture(Texture *tex, bool allow_bind, bool to_ram);
 
+  INLINE const LVecBase2i &get_size() const;
   INLINE int get_x_size() const;
   INLINE int get_y_size() const;
   INLINE int get_fb_x_size() const;
@@ -290,7 +291,7 @@ protected:
 
 private:
   PT(GeomVertexData) create_texture_card_vdata(int x, int y);
-  
+
   DisplayRegion *add_display_region(DisplayRegion *display_region);
   bool do_remove_display_region(DisplayRegion *display_region);
 
@@ -323,7 +324,7 @@ protected:
     RenderTextureMode _rtm_mode;
   };
   typedef pvector<RenderTexture> RenderTextures;
-  
+
 private:
   int _sort;
   int _child_sort;
@@ -346,9 +347,9 @@ protected:
   // have, we don't auto-close the buffer (since that would deallocate
   // the memory associated with the texture).
   pvector<WPT(Texture)> _hold_textures;
-  
+
 protected:
-  LightMutex _lock; 
+  LightMutex _lock;
   // protects _display_regions.
   PT(DisplayRegion) _overlay_display_region;
   typedef pvector< PT(DisplayRegion) > TotalDisplayRegions;
@@ -382,8 +383,7 @@ protected:
 
 protected:
   int _creation_flags;
-  int _x_size;
-  int _y_size;
+  LVecBase2i _size;
   bool _has_size;
   bool _is_valid;
   bool _is_nonzero_size;
@@ -394,7 +394,7 @@ protected:
   static PStatCollector _draw_pcollector;
   PStatCollector _cull_window_pcollector;
   PStatCollector _draw_window_pcollector;
-  
+
 public:
   static TypeHandle get_class_type() {
     return _type_handle;

+ 1 - 2
panda/src/display/graphicsWindow.cxx

@@ -170,8 +170,7 @@ request_properties(const WindowProperties &requested_properties) {
     // stick.  This is helpful for the MultitexReducer, which needs to
     // know the size of the textures that it will be working with,
     // even if the texture hasn't been fully generated yet.
-    _x_size = _requested_properties.get_x_size();
-    _y_size = _requested_properties.get_y_size();
+    _size = _requested_properties.get_size();
 
     // Don't set _has_size yet, because we don't really know yet.
   }

+ 17 - 19
panda/src/display/parasiteBuffer.cxx

@@ -27,15 +27,15 @@ TypeHandle ParasiteBuffer::_type_handle;
 ParasiteBuffer::
 ParasiteBuffer(GraphicsOutput *host, const string &name,
                int x_size, int y_size, int flags) :
-  GraphicsOutput(host->get_engine(), host->get_pipe(), 
+  GraphicsOutput(host->get_engine(), host->get_pipe(),
                  name, host->get_fb_properties(),
-                 WindowProperties::size(x_size, y_size), flags, 
+                 WindowProperties::size(x_size, y_size), flags,
                  host->get_gsg(), host, false)
 {
 #ifdef DO_MEMORY_USAGE
   MemoryUsage::update_type(this, this);
 #endif
-  
+
   if (display_cat.is_debug()) {
     display_cat.debug()
       << "Creating new parasite buffer " << get_name()
@@ -43,25 +43,24 @@ ParasiteBuffer(GraphicsOutput *host, const string &name,
   }
 
   _creation_flags = flags;
-  
+
   if (flags & GraphicsPipe::BF_size_track_host) {
-    x_size = host->get_x_size();
-    y_size = host->get_y_size();
+    _size = host->get_size();
+  } else {
+    _size.set(x_size, y_size);
   }
-  
-  _x_size = x_size;
-  _y_size = y_size;
+
   _has_size = true;
-  _overlay_display_region->compute_pixels(_x_size, _y_size);
+  _overlay_display_region->compute_pixels(_size.get_x(), _size.get_y());
   _is_valid = true;
-  
+
   set_inverted(host->get_gsg()->get_copy_texture_inverted());
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ParasiteBuffer::Destructor
 //       Access: Published, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ParasiteBuffer::
 ~ParasiteBuffer() {
@@ -201,19 +200,18 @@ begin_frame(FrameMode mode, Thread *current_thread) {
   }
 
   if (_creation_flags & GraphicsPipe::BF_size_track_host) {
-    if ((_host->get_x_size() != _x_size)||
-        (_host->get_y_size() != _y_size)) {
+    if (_host->get_size() != _size) {
       set_size_and_recalc(_host->get_x_size(),
                           _host->get_y_size());
     }
   } else {
-    if (_host->get_x_size() < _x_size ||
-        _host->get_y_size() < _y_size) {
-      set_size_and_recalc(min(_x_size, _host->get_x_size()),
-                          min(_y_size, _host->get_y_size()));
+    if (_host->get_x_size() < get_x_size() ||
+        _host->get_y_size() < get_y_size()) {
+      set_size_and_recalc(min(get_x_size(), _host->get_x_size()),
+                          min(get_y_size(), _host->get_y_size()));
     }
   }
-  
+
   clear_cube_map_selection();
   return true;
 }

+ 4 - 5
panda/src/dxgsg8/wdxGraphicsBuffer8.cxx

@@ -229,14 +229,13 @@ rebuild_bitplanes() {
   // Decide how big the bitplanes should be.
 
   if ((_host != 0)&&(_creation_flags & GraphicsPipe::BF_size_track_host)) {
-    if ((_host->get_x_size() != _x_size)||
-        (_host->get_y_size() != _y_size)) {
+    if (_host->get_size() != _size) {
       set_size_and_recalc(_host->get_x_size(),
                           _host->get_y_size());
     }
   }
-  int bitplane_x = _x_size;
-  int bitplane_y = _y_size;
+  int bitplane_x = get_x_size();
+  int bitplane_y = get_y_size();
   if (Texture::get_textures_power_2() != ATS_none) {
     bitplane_x = Texture::up_to_power_2(bitplane_x);
     bitplane_y = Texture::up_to_power_2(bitplane_y);
@@ -350,7 +349,7 @@ rebuild_bitplanes() {
           << "Unable to re-create texture " << *depth_ctx->get_texture() << endl;
         return false;
       }
-      
+
       if (depth_tex->get_texture_type() == Texture::TT_2d_texture) {
         depth_d3d_tex = depth_ctx->_d3d_2d_texture;
         nassertr(depth_d3d_tex != 0, false);

+ 12 - 13
panda/src/dxgsg9/wdxGraphicsBuffer9.cxx

@@ -276,25 +276,24 @@ rebuild_bitplanes() {
   IDirect3DSurface9 *color_surf = 0;
   IDirect3DSurface9 *depth_surf = 0;
   DWORD render_target_index;
-  
+
   render_target_index = 0;
-  
+
   // Decide how big the bitplanes should be.
 
   if ((_host != 0)&&(_creation_flags & GraphicsPipe::BF_size_track_host)) {
-    if ((_host->get_x_size() != _x_size)||
-        (_host->get_y_size() != _y_size)) {
+    if (_host->get_size() != _size) {
       set_size_and_recalc(_host->get_x_size(),
                           _host->get_y_size());
     }
   }
-  int bitplane_x = _x_size;
-  int bitplane_y = _y_size;
+  int bitplane_x = get_x_size();
+  int bitplane_y = get_y_size();
   if (Texture::get_textures_power_2() != ATS_none) {
     bitplane_x = Texture::up_to_power_2(bitplane_x);
     bitplane_y = Texture::up_to_power_2(bitplane_y);
   }
-  
+
   // Find the color and depth textures.  Either may be present,
   // or neither.
   //
@@ -342,7 +341,7 @@ rebuild_bitplanes() {
           }
           break;
         }
-      }                
+      }
     }
   }
 
@@ -373,7 +372,7 @@ rebuild_bitplanes() {
       _color_backing_store = NULL;
     }
     color_tex = get_texture(color_tex_index);
-    color_tex->set_size_padded(_x_size, _y_size);
+    color_tex->set_size_padded(get_x_size(), get_y_size());
 //    color_tex->set_format(Texture::F_rgba);
     color_ctx =
       DCAST(DXTextureContext9,
@@ -445,14 +444,14 @@ rebuild_bitplanes() {
       _depth_backing_store = NULL;
     }
 
-    if (_shared_depth_buffer) {      
+    if (_shared_depth_buffer) {
       depth_tex = _shared_depth_buffer -> get_texture(depth_tex_index);
     }
-    if (depth_tex == 0) {        
+    if (depth_tex == 0) {
       depth_tex = get_texture(depth_tex_index);
     }
 
-    depth_tex->set_size_padded(_x_size, _y_size);
+    depth_tex->set_size_padded(get_x_size(), get_y_size());
     depth_tex->set_format(Texture::F_depth_stencil);
     depth_ctx =
       DCAST(DXTextureContext9,
@@ -855,7 +854,7 @@ share_depth_buffer(GraphicsOutput *graphics_output) {
     if (_debug) {
       printf ("share_depth_buffer\n");
     }
-    
+
     // check buffer sizes
     if (this -> get_x_size() != input_graphics_output -> get_x_size()) {    
       if (_debug) {

+ 1 - 0
panda/src/egg/eggGroupNode.cxx

@@ -27,6 +27,7 @@
 #include "eggVertex.h"
 #include "eggTextureCollection.h"
 #include "eggMaterialCollection.h"
+#include "epvector.h"
 #include "pt_EggTexture.h"
 #include "pt_EggMaterial.h"
 #include "config_egg.h"

+ 1 - 1
panda/src/egg/eggMorphList.h

@@ -21,7 +21,7 @@
 
 #include "indent.h"
 
-#include "pvector.h"
+#include "epvector.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : EggMorphList

+ 1 - 1
panda/src/egg/eggSwitchCondition.h

@@ -73,11 +73,11 @@ PUBLISHED:
 
   virtual void transform(const LMatrix4d &mat);
 
+public:
   double _switch_in, _switch_out, _fade;
   LPoint3d _center;
 
 public:
-
   static TypeHandle get_class_type() {
     return _type_handle;
   }

+ 2 - 0
panda/src/express/config_express.N

@@ -1,3 +1,5 @@
+defconstruct TypeHandle new TypeHandle(TypeHandle::none())
+
 forcetype PandaSystem
 forcetype DSearchPath
 forcetype DSearchPath::Results

+ 12 - 9
panda/src/glstuff/glGraphicsBuffer_src.cxx

@@ -155,8 +155,7 @@ begin_frame(FrameMode mode, Thread *current_thread) {
       }
     }
     if (_creation_flags & GraphicsPipe::BF_size_track_host) {
-      if ((_host->get_x_size() != _x_size)||
-          (_host->get_y_size() != _y_size)) {
+      if (_host->get_size() != _size) {
         // We also need to rebuild if we need to change size.
         _needs_rebuild = true;
       }
@@ -277,14 +276,14 @@ rebuild_bitplanes() {
 
   // Calculate bitplane size.  This can be larger than the buffer.
   if (_creation_flags & GraphicsPipe::BF_size_track_host) {
-    if ((_host->get_x_size() != _x_size)||
-        (_host->get_y_size() != _y_size)) {
+    if (_host->get_size() != _size) {
       set_size_and_recalc(_host->get_x_size(),
                           _host->get_y_size());
     }
   }
-  int bitplane_x = _x_size;
-  int bitplane_y = _y_size;
+
+  int bitplane_x = get_x_size();
+  int bitplane_y = get_y_size();
   if (Texture::get_textures_power_2() != ATS_none) {
     bitplane_x = Texture::up_to_power_2(bitplane_x);
     bitplane_y = Texture::up_to_power_2(bitplane_y);
@@ -602,7 +601,7 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
     if (tex->get_texture_type() != Texture::TT_cube_map && _rb_size_z > 1) {
       tex->set_z_size(_rb_size_z);
     }
-    tex->set_pad_size(_rb_size_x - _x_size, _rb_size_y - _y_size);
+    tex->set_pad_size(_rb_size_x - get_x_size(), _rb_size_y - get_y_size());
 
     // Adjust the texture format based on the requested framebuffer settings.
     switch (slot) {
@@ -1072,6 +1071,10 @@ attach_tex(int layer, int view, Texture *attach, GLenum attachpoint) {
   gtc->set_active(true);
   _texture_contexts.push_back(gtc);
 
+  // It seems that binding the texture is necessary before binding
+  // to a framebuffer attachment.
+  glgsg->apply_texture(gtc);
+
 #ifndef OPENGLES
   GLclampf priority = 1.0f;
   glPrioritizeTextures(1, &gtc->_index, &priority);
@@ -1191,7 +1194,7 @@ end_frame(FrameMode mode, Thread *current_thread) {
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsBuffer)::
 set_size(int x, int y) {
-  if (_x_size != x || _y_size != y) {
+  if (_size.get_x() != x || _size.get_y() != y) {
     _needs_rebuild = true;
   }
 
@@ -1280,7 +1283,7 @@ open_buffer() {
   // A lot of code seems to depend on being able to get a
   // color buffer by just setting the rgb_color bit.
   if (_fb_properties.get_color_bits() == 0 &&
-      _fb_properties.get_rgb_color() > 0) {
+      _fb_properties.get_rgb_color()) {
     _fb_properties.set_color_bits(1);
   }
 

+ 155 - 78
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -310,6 +310,8 @@ CLP(GraphicsStateGuardian)(GraphicsEngine *engine, GraphicsPipe *pipe) :
   _check_errors = gl_check_errors;
   _force_flush = gl_force_flush;
 
+  _scissor_enabled = false;
+
 #ifdef DO_PSTATS
   if (gl_finish) {
     GLCAT.warning()
@@ -1423,6 +1425,7 @@ reset() {
   }
 
   _glDrawBuffers = NULL;
+  _glClearBufferfv = NULL;
 #ifndef OPENGLES
   if (is_at_least_gl_version(2, 0)) {
     _glDrawBuffers = (PFNGLDRAWBUFFERSPROC)
@@ -1438,6 +1441,11 @@ reset() {
     glGetIntegerv(GL_MAX_DRAW_BUFFERS, &max_draw_buffers);
     _max_color_targets = max_draw_buffers;
   }
+
+  if (is_at_least_gl_version(3, 0)) {
+    _glClearBufferfv = (PFNGLCLEARBUFFERFVPROC)
+      get_extension_func("glClearBufferfv");
+  }
 #endif  // OPENGLES
 
 #ifndef OPENGLES
@@ -2178,9 +2186,7 @@ clear(DrawableRegion *clearable) {
   PStatTimer timer(_clear_pcollector);
   report_my_gl_errors();
 
-  if ((!clearable->get_clear_color_active())&&
-      (!clearable->get_clear_depth_active())&&
-      (!clearable->get_clear_stencil_active())) {
+  if (!clearable->is_any_clear_active()) {
     return;
   }
 
@@ -2188,59 +2194,113 @@ clear(DrawableRegion *clearable) {
 
   int mask = 0;
 
-  for (int i=0; i<_current_properties->get_aux_rgba(); i++) {
-    int layerid = GraphicsOutput::RTP_aux_rgba_0 + i;
-    int layerbit = RenderBuffer::T_aux_rgba_0 << i;
-    if (clearable->get_clear_active(layerid)) {
-      LColor v = clearable->get_clear_value(layerid);
-      glClearColor(v[0],v[1],v[2],v[3]);
-      set_draw_buffer(layerbit);
-      glClear(GL_COLOR_BUFFER_BIT);
-    }
-  }
-  for (int i=0; i<_current_properties->get_aux_hrgba(); i++) {
-    int layerid = GraphicsOutput::RTP_aux_hrgba_0 + i;
-    int layerbit = RenderBuffer::T_aux_hrgba_0 << i;
-    if (clearable->get_clear_active(layerid)) {
-      LColor v = clearable->get_clear_value(layerid);
-      glClearColor(v[0],v[1],v[2],v[3]);
-      set_draw_buffer(layerbit);
-      glClear(GL_COLOR_BUFFER_BIT);
-    }
-  }
-  for (int i=0; i<_current_properties->get_aux_float(); i++) {
-    int layerid = GraphicsOutput::RTP_aux_float_0 + i;
-    int layerbit = RenderBuffer::T_aux_float_0 << i;
-    if (clearable->get_clear_active(layerid)) {
-      LColor v = clearable->get_clear_value(layerid);
-      glClearColor(v[0],v[1],v[2],v[3]);
-      set_draw_buffer(layerbit);
-      glClear(GL_COLOR_BUFFER_BIT);
-    }
-  }
-
-  // In the past, it was possible to set the draw buffer
-  // once in prepare_display_region and then forget about it.
-  // Now, with aux layers, it is necessary to occasionally
-  // change the draw buffer.  In time, I think there will need
-  // to be a draw buffer attrib.  Until then, this little hack
-  // to put things back the way they were after
-  // prepare_display_region will do.
-  
-  set_draw_buffer(_draw_buffer_type);
+#ifndef OPENGLES
+  if (_current_fbo != 0 && _glClearBufferfv != NULL) {
+    // We can use glClearBuffer to clear all the color attachments,
+    // which protects us from the overhead of having to call set_draw_buffer
+    // for every single attachment.
+    int index = 0;
 
-  if (_current_properties->get_color_bits() > 0) {
-    if (clearable->get_clear_color_active()) {
-      LColor v = clearable->get_clear_color();
-      glClearColor(v[0],v[1],v[2],v[3]);
-      if (gl_color_mask) {
-        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+    if (_current_properties->get_color_bits() > 0) {
+      if (_current_properties->is_stereo()) {
+        // Clear both left and right attachments.
+        if (clearable->get_clear_active(GraphicsOutput::RTP_color)) {
+          LColorf v = LCAST(float, clearable->get_clear_value(GraphicsOutput::RTP_color));
+          _glClearBufferfv(GL_COLOR, index, v.get_data());
+          _glClearBufferfv(GL_COLOR, index + 1, v.get_data());
+        }
+        index += 2;
+      } else {
+        if (clearable->get_clear_active(GraphicsOutput::RTP_color)) {
+          LColorf v = LCAST(float, clearable->get_clear_value(GraphicsOutput::RTP_color));
+          _glClearBufferfv(GL_COLOR, index, v.get_data());
+        }
+        ++index;
+      }
+    }
+    for (int i = 0; i < _current_properties->get_aux_rgba(); ++i) {
+      int layerid = GraphicsOutput::RTP_aux_rgba_0 + i;
+      if (clearable->get_clear_active(layerid)) {
+        LColorf v = LCAST(float, clearable->get_clear_value(layerid));
+        _glClearBufferfv(GL_COLOR, index, v.get_data());
+      }
+      ++index;
+    }
+    for (int i = 0; i < _current_properties->get_aux_hrgba(); ++i) {
+      int layerid = GraphicsOutput::RTP_aux_hrgba_0 + i;
+      if (clearable->get_clear_active(layerid)) {
+        LColorf v = LCAST(float, clearable->get_clear_value(layerid));
+        _glClearBufferfv(GL_COLOR, index, v.get_data());
+      }
+      ++index;
+    }
+    for (int i = 0; i < _current_properties->get_aux_float(); ++i) {
+      int layerid = GraphicsOutput::RTP_aux_float_0 + i;
+      if (clearable->get_clear_active(layerid)) {
+        LColorf v = LCAST(float, clearable->get_clear_value(layerid));
+        _glClearBufferfv(GL_COLOR, index, v.get_data());
+      }
+      ++index;
+    }
+  } else
+#endif
+  {
+    if (_current_properties->get_aux_mask() != 0) {
+      for (int i = 0; i < _current_properties->get_aux_rgba(); ++i) {
+        int layerid = GraphicsOutput::RTP_aux_rgba_0 + i;
+        int layerbit = RenderBuffer::T_aux_rgba_0 << i;
+        if (clearable->get_clear_active(layerid)) {
+          LColor v = clearable->get_clear_value(layerid);
+          glClearColor(v[0], v[1], v[2], v[3]);
+          set_draw_buffer(layerbit);
+          glClear(GL_COLOR_BUFFER_BIT);
+        }
+      }
+      for (int i = 0; i < _current_properties->get_aux_hrgba(); ++i) {
+        int layerid = GraphicsOutput::RTP_aux_hrgba_0 + i;
+        int layerbit = RenderBuffer::T_aux_hrgba_0 << i;
+        if (clearable->get_clear_active(layerid)) {
+          LColor v = clearable->get_clear_value(layerid);
+          glClearColor(v[0], v[1], v[2], v[3]);
+          set_draw_buffer(layerbit);
+          glClear(GL_COLOR_BUFFER_BIT);
+        }
+      }
+      for (int i = 0; i < _current_properties->get_aux_float(); ++i) {
+        int layerid = GraphicsOutput::RTP_aux_float_0 + i;
+        int layerbit = RenderBuffer::T_aux_float_0 << i;
+        if (clearable->get_clear_active(layerid)) {
+          LColor v = clearable->get_clear_value(layerid);
+          glClearColor(v[0], v[1], v[2], v[3]);
+          set_draw_buffer(layerbit);
+          glClear(GL_COLOR_BUFFER_BIT);
+        }
+      }
+
+      // In the past, it was possible to set the draw buffer
+      // once in prepare_display_region and then forget about it.
+      // Now, with aux layers, it is necessary to occasionally
+      // change the draw buffer.  In time, I think there will need
+      // to be a draw buffer attrib.  Until then, this little hack
+      // to put things back the way they were after
+      // prepare_display_region will do.
+
+      set_draw_buffer(_draw_buffer_type);
+    }
+
+    if (_current_properties->get_color_bits() > 0) {
+      if (clearable->get_clear_color_active()) {
+        LColor v = clearable->get_clear_color();
+        glClearColor(v[0], v[1], v[2], v[3]);
+        if (gl_color_mask) {
+          glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+        }
+        _state_mask.clear_bit(ColorWriteAttrib::get_class_slot());
+        mask |= GL_COLOR_BUFFER_BIT;
       }
-      _state_mask.clear_bit(ColorWriteAttrib::get_class_slot());
-      mask |= GL_COLOR_BUFFER_BIT;
     }
   }
-  
+
   if (clearable->get_clear_depth_active()) {
 #ifdef OPENGLES
     glClearDepthf(clearable->get_clear_depth());
@@ -2311,12 +2371,18 @@ prepare_display_region(DisplayRegionPipelineReader *dr) {
   _draw_buffer_type |= _current_properties->get_aux_mask();
   set_draw_buffer(_draw_buffer_type);
 
-  glEnable(GL_SCISSOR_TEST);
+  if (dr->get_scissor_enabled()) {
+    glEnable(GL_SCISSOR_TEST);
+    _scissor_enabled = true;
+  } else {
+    glDisable(GL_SCISSOR_TEST);
+    _scissor_enabled = false;
+  }
 
   if (_supports_viewport_arrays) {
     int count = dr->get_num_regions();
-    GLfloat *viewports = new GLfloat[4 * count];
-    GLint *scissors = new GLint[4 * count];
+    GLfloat *viewports = (GLfloat *)alloca(sizeof(GLfloat) * 4 * count);
+    GLint *scissors = (GLint *)alloca(sizeof(GLint) * 4 * count);
 
     for (int i = 0; i < count; ++i) {
       GLint *sr = scissors + i * 4;
@@ -2328,13 +2394,15 @@ prepare_display_region(DisplayRegionPipelineReader *dr) {
       vr[3] = (GLfloat) sr[3];
     }
     _glViewportArrayv(0, count, viewports);
-    _glScissorArrayv(0, count, scissors);
-    delete[] viewports;
-    delete[] scissors;
+    if (dr->get_scissor_enabled()) {
+      _glScissorArrayv(0, count, scissors);
+    }
 
   } else {
-    glScissor(x, y, width, height);
     glViewport(x, y, width, height);
+    if (dr->get_scissor_enabled()) {
+      glScissor(x, y, width, height);
+    }
   }
 
   report_my_gl_errors();
@@ -6322,19 +6390,19 @@ set_draw_buffer(int rbtype) {
         ++index;
       }
     }
-    for (int i=0; i<_current_properties->get_aux_rgba(); i++) {
+    for (int i = 0; i < _current_properties->get_aux_rgba(); ++i) {
       if (rbtype & (RenderBuffer::T_aux_rgba_0 << i)) {
         buffers[nbuffers++] = GL_COLOR_ATTACHMENT0_EXT + index;
       }
       ++index;
     }
-    for (int i=0; i<_current_properties->get_aux_hrgba(); i++) {
+    for (int i = 0; i < _current_properties->get_aux_hrgba(); ++i) {
       if (rbtype & (RenderBuffer::T_aux_hrgba_0 << i)) {
         buffers[nbuffers++] = GL_COLOR_ATTACHMENT0_EXT + index;
       }
       ++index;
     }
-    for (int i=0; i<_current_properties->get_aux_float(); i++) {
+    for (int i = 0; i < _current_properties->get_aux_float(); ++i) {
       if (rbtype & (RenderBuffer::T_aux_float_0 << i)) {
         buffers[nbuffers++] = GL_COLOR_ATTACHMENT0_EXT + index;
       }
@@ -6423,19 +6491,19 @@ set_read_buffer(int rbtype) {
       }
       ++index;
     }
-    for (int i=0; i<_current_properties->get_aux_rgba(); i++) {
+    for (int i = 0; i < _current_properties->get_aux_rgba(); ++i) {
       if (rbtype & (RenderBuffer::T_aux_rgba_0 << i)) {
         buffer = GL_COLOR_ATTACHMENT0_EXT + index;
       }
       ++index;
     }
-    for (int i=0; i<_current_properties->get_aux_hrgba(); i++) {
+    for (int i = 0; i < _current_properties->get_aux_hrgba(); ++i) {
       if (rbtype & (RenderBuffer::T_aux_hrgba_0 << i)) {
         buffer = GL_COLOR_ATTACHMENT0_EXT + index;
       }
       ++index;
     }
-    for (int i=0; i<_current_properties->get_aux_float(); i++) {
+    for (int i = 0; i < _current_properties->get_aux_float(); ++i) {
       if (rbtype & (RenderBuffer::T_aux_float_0 << i)) {
         buffer = GL_COLOR_ATTACHMENT0_EXT + index;
       }
@@ -6487,8 +6555,6 @@ set_read_buffer(int rbtype) {
 #endif  // OPENGLES
 }
 
-
-
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::get_numeric_type
 //       Access: Protected, Static
@@ -11056,7 +11122,6 @@ bind_fbo(GLuint fbo) {
   _current_fbo = fbo;
 }
 
-
 ////////////////////////////////////////////////////////////////////
 //  GL stencil code section
 ////////////////////////////////////////////////////////////////////
@@ -11292,9 +11357,9 @@ do_issue_stencil() {
       }
     }
 
-    if (stencil -> get_render_state (StencilAttrib::SRS_clear)) {    
+    if (stencil -> get_render_state (StencilAttrib::SRS_clear)) {
       GLbitfield mask = 0;
-      
+
       // clear stencil buffer
       glClearStencil(stencil -> get_render_state (StencilAttrib::SRS_clear_value));
       mask |= GL_STENCIL_BUFFER_BIT;
@@ -11310,18 +11375,30 @@ do_issue_stencil() {
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::do_issue_scissor
 //       Access: Protected
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 do_issue_scissor() {
   const ScissorAttrib *target_scissor = DCAST(ScissorAttrib, _target_rs->get_attrib_def(ScissorAttrib::get_class_slot()));
-  const LVecBase4 &frame = target_scissor->get_frame();
 
-  int x = (int)(_viewport_x + _viewport_width * frame[0] + 0.5f);
-  int y = (int)(_viewport_y + _viewport_height * frame[2] + 0.5f);
-  int width = (int)(_viewport_width * (frame[1] - frame[0]) + 0.5f);
-  int height = (int)(_viewport_height * (frame[3] - frame[2]) + 0.5f);
+  if (target_scissor->is_off()) {
+    if (_scissor_enabled) {
+      glDisable(GL_SCISSOR_TEST);
+      _scissor_enabled = false;
+    }
+  } else {
+    if (!_scissor_enabled) {
+      glEnable(GL_SCISSOR_TEST);
+      _scissor_enabled = true;
+    }
+
+    const LVecBase4 &frame = target_scissor->get_frame();
 
-  glEnable(GL_SCISSOR_TEST);
-  glScissor(x, y, width, height);
+    int x = (int)(_viewport_x + _viewport_width * frame[0] + 0.5f);
+    int y = (int)(_viewport_y + _viewport_height * frame[2] + 0.5f);
+    int width = (int)(_viewport_width * (frame[1] - frame[0]) + 0.5f);
+    int height = (int)(_viewport_height * (frame[3] - frame[2]) + 0.5f);
+
+    glScissor(x, y, width, height);
+  }
 }

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

@@ -88,6 +88,7 @@ typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
 typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
 typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data);
 typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs);
+typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value);
 typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
 typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
 typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data);
@@ -528,6 +529,7 @@ protected:
   PN_stdfloat _point_size;
   bool _point_perspective;
   bool _vertex_blending_enabled;
+  bool _scissor_enabled;
 
 #ifndef OPENGLES_1
   PT(Shader) _current_shader;
@@ -689,6 +691,7 @@ public:
   INLINE bool get_supports_framebuffer_blit();
   PFNGLBLITFRAMEBUFFEREXTPROC _glBlitFramebuffer;
   PFNGLDRAWBUFFERSPROC _glDrawBuffers;
+  PFNGLCLEARBUFFERFVPROC _glClearBufferfv;
   int _max_fb_samples;
   bool _supports_viewport_arrays;
   bool _supports_bindless_texture;

+ 85 - 47
panda/src/glstuff/glShaderContext_src.cxx

@@ -267,6 +267,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
           if (size > 6 && matrix_name.compare(size - 6, 6, "Matrix") == 0) {
             Shader::ShaderMatSpec bind;
             bind._id = arg_id;
+            bind._func = Shader::SMF_compose;
             if (transpose) {
               bind._piece = Shader::SMP_transpose;
             } else {
@@ -274,9 +275,10 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
             }
             bind._arg[0] = NULL;
             bind._arg[1] = NULL;
+            bind._dep[0] = Shader::SSD_general | Shader::SSD_transform;
+            bind._dep[1] = Shader::SSD_general | Shader::SSD_transform;
 
             if (matrix_name == "ModelViewProjectionMatrix") {
-              bind._func = Shader::SMF_compose;
               if (inverse) {
                 bind._part[0] = Shader::SMO_apiclip_to_view;
                 bind._part[1] = Shader::SMO_view_to_model;
@@ -284,11 +286,8 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
                 bind._part[0] = Shader::SMO_model_to_view;
                 bind._part[1] = Shader::SMO_view_to_apiclip;
               }
-              bind._dep[0] = Shader::SSD_general | Shader::SSD_transform;
-              bind._dep[1] = Shader::SSD_general | Shader::SSD_transform;
 
             } else if (matrix_name == "ModelViewMatrix") {
-              bind._func = Shader::SMF_compose;
               if (inverse) {
                 bind._part[0] = Shader::SMO_apiview_to_view;
                 bind._part[1] = Shader::SMO_view_to_model;
@@ -296,11 +295,8 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
                 bind._part[0] = Shader::SMO_model_to_view;
                 bind._part[1] = Shader::SMO_view_to_apiview;
               }
-              bind._dep[0] = Shader::SSD_general | Shader::SSD_transform;
-              bind._dep[1] = Shader::SSD_general | Shader::SSD_transform;
 
             } else if (matrix_name == "ProjectionMatrix") {
-              bind._func = Shader::SMF_compose;
               if (inverse) {
                 bind._part[0] = Shader::SMO_apiclip_to_view;
                 bind._part[1] = Shader::SMO_view_to_apiview;
@@ -308,12 +304,9 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
                 bind._part[0] = Shader::SMO_apiview_to_view;
                 bind._part[1] = Shader::SMO_view_to_apiclip;
               }
-              bind._dep[0] = Shader::SSD_general | Shader::SSD_transform;
-              bind._dep[1] = Shader::SSD_general | Shader::SSD_transform;
 
             } else if (matrix_name == "NormalMatrix") {
               // This is really the upper 3x3 of the ModelViewMatrixInverseTranspose.
-              bind._func = Shader::SMF_compose;
               if (inverse) {
                 bind._part[0] = Shader::SMO_model_to_view;
                 bind._part[1] = Shader::SMO_view_to_apiview;
@@ -321,8 +314,6 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
                 bind._part[0] = Shader::SMO_apiview_to_view;
                 bind._part[1] = Shader::SMO_view_to_model;
               }
-              bind._dep[0] = Shader::SSD_general | Shader::SSD_transform;
-              bind._dep[1] = Shader::SSD_general | Shader::SSD_transform;
 
               if (transpose) {
                 bind._piece = Shader::SMP_upper3x3;
@@ -330,6 +321,33 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
                 bind._piece = Shader::SMP_transpose3x3;
               }
 
+            } else if (matrix_name == "ModelMatrix") {
+              if (inverse) {
+                bind._part[0] = Shader::SMO_world_to_view;
+                bind._part[1] = Shader::SMO_view_to_model;
+              } else {
+                bind._part[0] = Shader::SMO_model_to_view;
+                bind._part[1] = Shader::SMO_view_to_world;
+              }
+
+            } else if (matrix_name == "ViewMatrix") {
+              if (inverse) {
+                bind._part[0] = Shader::SMO_apiview_to_view;
+                bind._part[1] = Shader::SMO_view_to_world;
+              } else {
+                bind._part[0] = Shader::SMO_world_to_view;
+                bind._part[1] = Shader::SMO_view_to_apiview;
+              }
+
+            } else if (matrix_name == "ViewProjectionMatrix") {
+              if (inverse) {
+                bind._part[0] = Shader::SMO_apiclip_to_view;
+                bind._part[1] = Shader::SMO_view_to_world;
+              } else {
+                bind._part[0] = Shader::SMO_world_to_view;
+                bind._part[1] = Shader::SMO_view_to_apiclip;
+              }
+
             } else {
               GLCAT.error() << "Unrecognized uniform matrix name '" << matrix_name << "'!\n";
               continue;
@@ -410,21 +428,21 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
 
           if (param_name == "osg_ViewMatrix") {
             bind._piece = Shader::SMP_whole;
-            bind._func = Shader::SMF_first;
+            bind._func = Shader::SMF_compose;
             bind._part[0] = Shader::SMO_world_to_view;
-            bind._part[1] = Shader::SMO_identity;
+            bind._part[1] = Shader::SMO_view_to_apiview;
             bind._dep[0] = Shader::SSD_general | Shader::SSD_transform;
-            bind._dep[1] = Shader::SSD_NONE;
+            bind._dep[1] = Shader::SSD_general | Shader::SSD_transform;
             s->_mat_spec.push_back(bind);
             continue;
 
           } else if (param_name == "osg_InverseViewMatrix") {
             bind._piece = Shader::SMP_whole;
-            bind._func = Shader::SMF_first;
-            bind._part[0] = Shader::SMO_view_to_world;
-            bind._part[1] = Shader::SMO_identity;
+            bind._func = Shader::SMF_compose;
+            bind._part[0] = Shader::SMO_apiview_to_view;
+            bind._part[1] = Shader::SMO_view_to_world;
             bind._dep[0] = Shader::SSD_general | Shader::SSD_transform;
-            bind._dep[1] = Shader::SSD_NONE;
+            bind._dep[1] = Shader::SSD_general | Shader::SSD_transform;
             s->_mat_spec.push_back(bind);
             continue;
 
@@ -1135,9 +1153,14 @@ disable_shader_texture_bindings() {
 
     if (gl_enable_memory_barriers) {
       for (int i = 0; i < num_image_units; ++i) {
-        // We don't distinguish between read-only and read-write/write-only
-        // image access, so we have to assume that the shader wrote to it.
-        _glsl_img_textures[i]->mark_incoherent();
+        const InternalName *name = _glsl_img_inputs[i];
+        const ShaderInput *input = _glgsg->_target_shader->get_shader_input(name);
+
+        if ((input->_access & ShaderInput::A_write) != 0) {
+          _glsl_img_textures[i]->mark_incoherent(true);
+        } else {
+          _glsl_img_textures[i]->mark_incoherent(false);
+        }
         _glsl_img_textures[i] = NULL;
       }
     }
@@ -1175,21 +1198,18 @@ update_shader_texture_bindings(ShaderContext *prev) {
   int num_image_units = min(_glsl_img_inputs.size(), (size_t)_glgsg->_max_image_units);
 
   if (num_image_units > 0) {
-    GLuint *multi_img = NULL;
-    // If we support multi-bind, prepare an array.
-    if (_glgsg->_supports_multi_bind) {
-      multi_img = new GLuint[num_image_units];
-    }
-
     for (int i = 0; i < num_image_units; ++i) {
       const InternalName *name = _glsl_img_inputs[i];
-      Texture *tex = _glgsg->_target_shader->get_shader_input_texture(name);
+      const ShaderInput *input = _glgsg->_target_shader->get_shader_input(name);
+      Texture *tex = input->get_texture();
 
       GLuint gl_tex = 0;
+      CLP(TextureContext) *gtc;
+
       if (tex != NULL) {
         int view = _glgsg->get_current_tex_view_offset();
 
-        CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tex->prepare_now(view, _glgsg->_prepared_objects, _glgsg));
+        gtc = DCAST(CLP(TextureContext), tex->prepare_now(view, _glgsg->_prepared_objects, _glgsg));
         if (gtc != (TextureContext*)NULL) {
           _glsl_img_textures[i] = gtc;
 
@@ -1202,27 +1222,45 @@ update_shader_texture_bindings(ShaderContext *prev) {
         }
       }
 
-      if (multi_img != NULL) {
-        // Put in array so we can multi-bind later.
-        multi_img[i] = gl_tex;
-
+      if (gl_tex == 0) {
+        _glgsg->_glBindImageTexture(i, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R8);
       } else {
-        // We don't support multi-bind, so bind now in the same way that multi-bind would have done it.
-        if (gl_tex == 0) {
-          _glgsg->_glBindImageTexture(i, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R8);
+        //TODO: automatically convert to sized type instead of plain GL_RGBA
+        // If a base type is used, it will crash.
+        if (gtc->_internal_format == GL_RGBA || gtc->_internal_format == GL_RGB) {
+          GLCAT.error()
+            << "Texture " << tex->get_name() << " has an unsized format.  Textures bound "
+            << "to a shader as an image need a sized format.\n";
+
+          // This may not actually be right, but may still prevent a crash.
+          if (gtc->_internal_format == GL_RGBA) {
+            gtc->_internal_format = GL_RGBA8;
+          } else {
+            gtc->_internal_format = GL_RGB8;
+          }
+        }
+
+        GLenum access = GL_READ_ONLY;
+        GLboolean layered = (input->_access & ShaderInput::A_layered) != 0;
+
+        if ((input->_access & ShaderInput::A_read) != 0 &&
+            (input->_access & ShaderInput::A_write) != 0) {
+          access = GL_READ_WRITE;
+
+        } else if ((input->_access & ShaderInput::A_read) != 0) {
+          access = GL_READ_ONLY;
+
+        } else if ((input->_access & ShaderInput::A_write) != 0) {
+          access = GL_WRITE_ONLY;
+
         } else {
-          //TODO: automatically convert to sized type instead of plain GL_RGBA
-          // If a base type is used, it will crash.
-          GLint internal_format = _glgsg->get_internal_image_format(tex);
-          _glgsg->_glBindImageTexture(i, gl_tex, 0, GL_TRUE, 0, GL_READ_WRITE, internal_format);
+          access = GL_READ_ONLY;
+          gl_tex = 0;
         }
+        _glgsg->_glBindImageTexture(i, gl_tex, input->_bind_level, layered,
+                                    input->_bind_layer, access, gtc->_internal_format);
       }
     }
-
-    if (multi_img != NULL) {
-      _glgsg->_glBindImageTextures(0, num_image_units, multi_img);
-      delete[] multi_img;
-    }
   }
 #endif
 
@@ -1314,7 +1352,7 @@ update_shader_texture_bindings(ShaderContext *prev) {
 
 #ifndef OPENGLES
   if (barriers != 0) {
-    // Issue a memory barrier.
+    // Issue a memory barrier prior to this shader's execution.
     _glgsg->issue_memory_barrier(barriers);
   }
 #endif

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

@@ -28,7 +28,6 @@ CLP(TextureContext)(CLP(GraphicsStateGuardian) *glgsg,
   glGenTextures(1, &_index);
 
   _handle = 0;
-  _needs_barrier = false;
   _has_storage = false;
   _immutable = false;
   _uses_mipmaps = false;

+ 13 - 4
panda/src/glstuff/glTextureContext_src.cxx

@@ -87,7 +87,6 @@ reset_data() {
 
   _handle = 0;
   _handle_resident = false;
-  _needs_barrier = false;
   _has_storage = false;
   _immutable = false;
 
@@ -169,15 +168,25 @@ needs_barrier(GLbitfield barrier) {
 //     Function: GLTextureContext::mark_incoherent
 //       Access: Public
 //  Description: Mark a texture as needing a memory barrier, since
-//               a non-coherent write just happened to it.
+//               a non-coherent read or write just happened to it.
+//               If 'wrote' is true, it was written to.
 ////////////////////////////////////////////////////////////////////
 void CLP(TextureContext)::
-mark_incoherent() {
+mark_incoherent(bool wrote) {
   if (!gl_enable_memory_barriers) {
     return;
   }
 
-  _glgsg->_textures_needing_fetch_barrier.insert(this);
+  // If we only read from it, the next read operation won't need
+  // another barrier, since it'll be reading the same data.
+  if (wrote) {
+    _glgsg->_textures_needing_fetch_barrier.insert(this);
+  }
+
+  // We could still write to it before we read from it, so we have
+  // to always insert these barriers.  This could be slightly
+  // optimized so that we don't issue a barrier between consecutive
+  // image reads, but that may not be worth the trouble.
   _glgsg->_textures_needing_image_access_barrier.insert(this);
   _glgsg->_textures_needing_update_barrier.insert(this);
   _glgsg->_textures_needing_framebuffer_barrier.insert(this);

+ 1 - 6
panda/src/glstuff/glTextureContext_src.h

@@ -40,7 +40,7 @@ public:
   CONSTEXPR bool needs_barrier(GLbitfield barrier) { return false; };
 #else
   bool needs_barrier(GLbitfield barrier);
-  void mark_incoherent();
+  void mark_incoherent(bool wrote);
 #endif
 
   // This is the GL "name" of the texture object.
@@ -50,11 +50,6 @@ public:
   GLuint64 _handle;
   bool _handle_resident;
 
-  // This is true if the texture was recently written to in a
-  // non-coherent way, and Panda may have to call glMemoryBarrier
-  // for the results of this write to become visible.
-  bool _needs_barrier;
-
   // These are the parameters that we specified with the last
   // glTexImage2D() or glTexStorage2D() call.  If none of these have
   // changed, we can reload the texture image with a glTexSubImage2D().

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