Browse Source

Merge branch 'release/1.10.x'

rdb 4 years ago
parent
commit
78fb565f2b

+ 1 - 1
makepanda/makepandacore.py

@@ -2769,7 +2769,7 @@ def SetupVisualStudioEnviron():
         elif not win_kit.endswith('\\'):
         elif not win_kit.endswith('\\'):
             win_kit += '\\'
             win_kit += '\\'
 
 
-        for vnum in 10150, 10240, 10586, 14393, 15063, 16299, 17134, 17763, 18362:
+        for vnum in 10150, 10240, 10586, 14393, 15063, 16299, 17134, 17763, 18362, 19041:
             version = "10.0.{0}.0".format(vnum)
             version = "10.0.{0}.0".format(vnum)
             if os.path.isfile(win_kit + "Include\\" + version + "\\ucrt\\assert.h"):
             if os.path.isfile(win_kit + "Include\\" + version + "\\ucrt\\assert.h"):
                 print("Using Universal CRT %s" % (version))
                 print("Using Universal CRT %s" % (version))

+ 82 - 67
panda/src/doc/eggSyntax.txt

@@ -3,7 +3,7 @@ THE PHILOSOPHY OF EGG FILES (vs. bam files)
 Egg files are used by Panda3D to describe many properties of a scene:
 Egg files are used by Panda3D to describe many properties of a scene:
 simple geometry, including special effects and collision surfaces,
 simple geometry, including special effects and collision surfaces,
 characters including skeletons, morphs, and multiple-joint
 characters including skeletons, morphs, and multiple-joint
-assignments, and character animation tables.  
+assignments, and character animation tables.
 
 
 Egg files are designed to be the lingua franca of model manipulation
 Egg files are designed to be the lingua franca of model manipulation
 for Panda tools.  A number of utilities are provided that read and
 for Panda tools.  A number of utilities are provided that read and
@@ -168,8 +168,9 @@ appear before they are referenced.
     The remaining formats are generic and specify only the semantic
     The remaining formats are generic and specify only the semantic
     meaning of the channels.  The size of the texels is determined by
     meaning of the channels.  The size of the texels is determined by
     the width of the components in the image file.  RGBA is the most
     the width of the components in the image file.  RGBA is the most
-    general; RGB is the same, but without any alpha channel.  RGBM is
-    like RGBA, except that it requests only one bit of alpha, if the
+    general; RGB is the same, but without any alpha channel.
+
+    RGBM is like RGBA, except that it requests only one bit of alpha, if the
     graphics card can provide that, to leave more room for the RGB
     graphics card can provide that, to leave more room for the RGB
     components, which is especially important for older 16-bit
     components, which is especially important for older 16-bit
     graphics cards (the "M" stands for "mask", as in a cutout).
     graphics cards (the "M" stands for "mask", as in a cutout).
@@ -211,7 +212,7 @@ appear before they are referenced.
     Although less often used, for 3-d textures wrapw may also be
     Although less often used, for 3-d textures wrapw may also be
     specified, and it behaves similarly to wrapu and wrapv.
     specified, and it behaves similarly to wrapu and wrapv.
 
 
-    There are other legal values in addtional to REPEAT and CLAMP.
+    There are other legal values in additional to REPEAT and CLAMP.
     The full list is:
     The full list is:
 
 
       CLAMP
       CLAMP
@@ -278,7 +279,7 @@ appear before they are referenced.
     / (number of views).
     / (number of views).
 
 
   <Scalar> read-mipmaps { flag }
   <Scalar> read-mipmaps { flag }
- 
+
    If this flag is nonzero, then pre-generated mipmap levels will be
    If this flag is nonzero, then pre-generated mipmap levels will be
     loaded along with the texture.  In this case, the filename should
     loaded along with the texture.  In this case, the filename should
     contain a sequence of one or more hash mark ("#") characters,
     contain a sequence of one or more hash mark ("#") characters,
@@ -413,7 +414,7 @@ appear before they are referenced.
       <Scalar> combine-alpha-operand2 { src-alpha }
       <Scalar> combine-alpha-operand2 { src-alpha }
 
 
   <Scalar> saved-result { flag }
   <Scalar> saved-result { flag }
- 
+
     If flag is nonzero, then it indicates that this particular texture
     If flag is nonzero, then it indicates that this particular texture
     stage will be supplied as the "last_saved_result" source for any
     stage will be supplied as the "last_saved_result" source for any
     future texture stages.
     future texture stages.
@@ -704,7 +705,7 @@ appear before they are referenced.
     <UV> [name] { u v [w] [tangent] [binormal] [morph-list] }
     <UV> [name] { u v [w] [tangent] [binormal] [morph-list] }
 
 
     This gives the texture coordinates of the vertex.  This must be
     This gives the texture coordinates of the vertex.  This must be
-    specified if a texture is to be mapped onto this geometry.  
+    specified if a texture is to be mapped onto this geometry.
 
 
     The texture coordinates are usually two-dimensional, with two
     The texture coordinates are usually two-dimensional, with two
     component values (u v), but they may also be three-dimensional,
     component values (u v), but they may also be three-dimensional,
@@ -739,7 +740,7 @@ appear before they are referenced.
     meaning to custom code or a custom shader.  Like named UV's, there
     meaning to custom code or a custom shader.  Like named UV's, there
     may be multiple Aux entries for a given vertex, each with a
     may be multiple Aux entries for a given vertex, each with a
     different name.
     different name.
-    
+
 
 
 
 
 <DynamicVertexPool> name { vertices }
 <DynamicVertexPool> name { vertices }
@@ -758,18 +759,18 @@ appear before they are referenced.
 
 
   At the present time, the DynamicVertexPool is not implemented in
   At the present time, the DynamicVertexPool is not implemented in
   Panda3D.
   Panda3D.
-  
+
 
 
 
 
 
 
 GEOMETRY ENTRIES
 GEOMETRY ENTRIES
 
 
-<Polygon> name { 
-    [attributes] 
-    <VertexRef> { 
-        indices 
-        <Ref> { pool-name } 
-    } 
+<Polygon> name {
+    [attributes]
+    <VertexRef> {
+        indices
+        <Ref> { pool-name }
+    }
 }
 }
 
 
   A polygon consists of a sequence of vertices from a single vertex
   A polygon consists of a sequence of vertices from a single vertex
@@ -822,7 +823,7 @@ GEOMETRY ENTRIES
     used unless all vertices also have a normal.  If no normal is
     used unless all vertices also have a normal.  If no normal is
     defined, none will be supplied.  The polygon normal, like the
     defined, none will be supplied.  The polygon normal, like the
     vertex normal, may be morphed by specifying a series of <DNormal>
     vertex normal, may be morphed by specifying a series of <DNormal>
-    entries.  
+    entries.
 
 
     The polygon normal is used only for lighting and environment
     The polygon normal is used only for lighting and environment
     mapping calculations, and is not related to the implicit normal
     mapping calculations, and is not related to the implicit normal
@@ -844,7 +845,7 @@ GEOMETRY ENTRIES
     disabled, and polygons are one-sided; specifying a nonzero value
     disabled, and polygons are one-sided; specifying a nonzero value
     disables backface culling for this particular polygon and allows
     disables backface culling for this particular polygon and allows
     it to be viewed from either side.
     it to be viewed from either side.
-    
+
 
 
   <Scalar> bin { bin-name }
   <Scalar> bin { bin-name }
 
 
@@ -916,12 +917,12 @@ GEOMETRY ENTRIES
     or even within a texture.
     or even within a texture.
 
 
 
 
-<Patch> name { 
-    [attributes] 
-    <VertexRef> { 
-        indices 
-        <Ref> { pool-name } 
-    } 
+<Patch> name {
+    [attributes]
+    <VertexRef> {
+        indices
+        <Ref> { pool-name }
+    }
 }
 }
 
 
   A patch is similar to a polygon, but it is a special primitive that
   A patch is similar to a polygon, but it is a special primitive that
@@ -936,12 +937,12 @@ GEOMETRY ENTRIES
   specified for Patch.
   specified for Patch.
 
 
 
 
-<PointLight> name { 
-    [attributes] 
-    <VertexRef> { 
-        indices 
-        <Ref> { pool-name } 
-    } 
+<PointLight> name {
+    [attributes]
+    <VertexRef> {
+        indices
+        <Ref> { pool-name }
+    }
 }
 }
 
 
   A PointLight is a set of single points.  One point is drawn for each
   A PointLight is a set of single points.  One point is drawn for each
@@ -964,12 +965,12 @@ GEOMETRY ENTRIES
     viewer normally.
     viewer normally.
 
 
 
 
-<Line> name { 
-    [attributes] 
-    <VertexRef> { 
-        indices 
-        <Ref> { pool-name } 
-    } 
+<Line> name {
+    [attributes]
+    <VertexRef> {
+        indices
+        <Ref> { pool-name }
+    }
     [component attributes]
     [component attributes]
 }
 }
 
 
@@ -985,11 +986,11 @@ GEOMETRY ENTRIES
   line segment, as in TriangleStrip, below.
   line segment, as in TriangleStrip, below.
 
 
 
 
-<TriangleStrip> name { 
-    [attributes] 
-    <VertexRef> { 
-        indices 
-        <Ref> { pool-name } 
+<TriangleStrip> name {
+    [attributes]
+    <VertexRef> {
+        indices
+        <Ref> { pool-name }
     }
     }
     [component attributes]
     [component attributes]
 }
 }
@@ -1013,7 +1014,7 @@ GEOMETRY ENTRIES
   It is possible for the individual triangles of a triangle strip to
   It is possible for the individual triangles of a triangle strip to
   have a separate normal and/or color.  If so, a <Component> entry
   have a separate normal and/or color.  If so, a <Component> entry
   should be given for each so-modified triangle:
   should be given for each so-modified triangle:
-  
+
   <Component> index {
   <Component> index {
     <RGBA> { r g b a [morph-list] }
     <RGBA> { r g b a [morph-list] }
     <Normal> { x y z [morph-list] }
     <Normal> { x y z [morph-list] }
@@ -1024,11 +1025,11 @@ GEOMETRY ENTRIES
   must always follow the vertex list.
   must always follow the vertex list.
 
 
 
 
-<TriangleFan> name { 
-    [attributes] 
-    <VertexRef> { 
-        indices 
-        <Ref> { pool-name } 
+<TriangleFan> name {
+    [attributes]
+    <VertexRef> {
+        indices
+        <Ref> { pool-name }
     }
     }
     [component attributes]
     [component attributes]
 }
 }
@@ -1057,7 +1058,7 @@ itself doesn't support them and will always create static curves and
 surfaces.  External tools like egg-qtess, however, may respect them.
 surfaces.  External tools like egg-qtess, however, may respect them.
 
 
 <NURBSCurve> {
 <NURBSCurve> {
-    [attributes] 
+    [attributes]
 
 
     <Order> { order }
     <Order> { order }
     <Knots> { knot-list }
     <Knots> { knot-list }
@@ -1083,7 +1084,7 @@ surfaces.  External tools like egg-qtess, however, may respect them.
 
 
   <Scalar> type { curve-type }
   <Scalar> type { curve-type }
 
 
-    This defines the semanting meaning of this curve, either XYZ, HPR,
+    This defines the semantic meaning of this curve, either XYZ, HPR,
     or T.  If the type is XYZ, the curve will automatically be
     or T.  If the type is XYZ, the curve will automatically be
     transformed between Y-up and Z-up if necessary; otherwise, it will
     transformed between Y-up and Z-up if necessary; otherwise, it will
     be left alone.
     be left alone.
@@ -1107,16 +1108,16 @@ surfaces.  External tools like egg-qtess, however, may respect them.
 
 
 
 
 <NURBSSurface> name {
 <NURBSSurface> name {
-    [attributes] 
+    [attributes]
 
 
     <Order> { u-order v-order }
     <Order> { u-order v-order }
     <U-knots> { u-knot-list }
     <U-knots> { u-knot-list }
     <V-knots> { v-knot-list }
     <V-knots> { v-knot-list }
 
 
-    <VertexRef> { 
-        indices 
-        <Ref> { pool-name } 
-    } 
+    <VertexRef> {
+        indices
+        <Ref> { pool-name }
+    }
 }
 }
 
 
   A NURBS surface is an extension of a NURBS curve into two parametric
   A NURBS surface is an extension of a NURBS curve into two parametric
@@ -1137,7 +1138,7 @@ surfaces.  External tools like egg-qtess, however, may respect them.
     These define the number of subdivisions to make in the U and V
     These define the number of subdivisions to make in the U and V
     directions to represent the surface.  A uniform subdivision is
     directions to represent the surface.  A uniform subdivision is
     always made, and trim curves are not respected (though they will
     always made, and trim curves are not respected (though they will
-    be drawn in if the trim curves themselves also have a subiv
+    be drawn in if the trim curves themselves also have a subdiv
     parameter).  This is only intended as a cheesy visualization.
     parameter).  This is only intended as a cheesy visualization.
 
 
 
 
@@ -1194,7 +1195,7 @@ surfaces.  External tools like egg-qtess, however, may respect them.
 
 
   Although the egg syntax supports trim curves, there are at present
   Although the egg syntax supports trim curves, there are at present
   no egg processing tools that respect them.  For instance, egg-qtess
   no egg processing tools that respect them.  For instance, egg-qtess
-  ignores trim curves and always tesselates the entire NURBS surface.
+  ignores trim curves and always tessellates the entire NURBS surface.
 
 
 
 
 MORPH DESCRIPTION ENTRIES
 MORPH DESCRIPTION ENTRIES
@@ -1267,7 +1268,7 @@ GROUPING ENTRIES
   attributes of the group:
   attributes of the group:
 
 
   GROUP BINARY ATTRIBUTES
   GROUP BINARY ATTRIBUTES
-  
+
   These attributes may be either on or off; they are off by default.
   These attributes may be either on or off; they are off by default.
   They are turned on by specifying a non-zero "boolean-value".
   They are turned on by specifying a non-zero "boolean-value".
 
 
@@ -1310,6 +1311,15 @@ GROUPING ENTRIES
     vertices; joints and morphs appearing outside of a hierarchy
     vertices; joints and morphs appearing outside of a hierarchy
     identified with a <Dart> flag are undefined.
     identified with a <Dart> flag are undefined.
 
 
+  <Dart> { structured }
+
+    This is an optional alternative for the <Dart> flag.
+    By default, Panda will collapse all of the geometry in a group (with the <Dart> { 1 } flag)
+    a single node. While this is optimal for conditions such as characters moving around
+    a scene, it may be suboptimal for larger or more complex characters.
+    This entry is typically generated by the egg-optchar program with the "-dart structured" flag.
+    <Dart> { structured } implies <Dart> { 1 }.
+
   <Switch> { boolean-value }
   <Switch> { boolean-value }
 
 
     This attribute indicates that the child nodes of this group
     This attribute indicates that the child nodes of this group
@@ -1446,7 +1456,7 @@ GROUPING ENTRIES
     of the billboard, not at the origin of the scene.
     of the billboard, not at the origin of the scene.
 
 
   <SwitchCondition> {
   <SwitchCondition> {
-     <Distance> { 
+     <Distance> {
         in out [fade] <Vertex> { x y z }
         in out [fade] <Vertex> { x y z }
      }
      }
   }
   }
@@ -1483,7 +1493,7 @@ GROUPING ENTRIES
     Valid types so far are:
     Valid types so far are:
 
 
     Plane
     Plane
-    
+
       The geometry represents an infinite plane.  The first polygon
       The geometry represents an infinite plane.  The first polygon
       found in the group will define the plane.
       found in the group will define the plane.
 
 
@@ -1550,7 +1560,7 @@ GROUPING ENTRIES
       most compatibility.
       most compatibility.
 
 
     keep
     keep
- 
+
       Don't discard the visible geometry after using it to define a
       Don't discard the visible geometry after using it to define a
       collision surface; create both an invisible collision surface
       collision surface; create both an invisible collision surface
       and the visible geometry.
       and the visible geometry.
@@ -1619,7 +1629,8 @@ GROUPING ENTRIES
 
 
     There may also be additional predefined egg object types not
     There may also be additional predefined egg object types not
     listed here; see the *.pp files that are installed into the etc
     listed here; see the *.pp files that are installed into the etc
-    directory for a complete list.
+    directory for a complete list. Additionally, you can reference
+    the file located in $PANDA/src/doc/howto.MultiGenModelFlags
 
 
   <Transform> { transform-definition }
   <Transform> { transform-definition }
 
 
@@ -1683,9 +1694,9 @@ GROUPING ENTRIES
     current group, regardless of the group in which the geometry is
     current group, regardless of the group in which the geometry is
     actually defined.  See the <Joint> description, below.
     actually defined.  See the <Joint> description, below.
 
 
-  <AnimPreload> { 
+  <AnimPreload> {
     <Scalar> fps { float-value }
     <Scalar> fps { float-value }
-    <Scalar> num-frames { integer-value } 
+    <Scalar> num-frames { integer-value }
   }
   }
 
 
     One or more AnimPreload entries may appear within the <Group> that
     One or more AnimPreload entries may appear within the <Group> that
@@ -1720,7 +1731,7 @@ GROUPING ENTRIES
   geometry in the scene graph.  The syntax is:
   geometry in the scene graph.  The syntax is:
 
 
 <Instance> name {
 <Instance> name {
-  <Ref> { group-name } 
+  <Ref> { group-name }
   [ <Ref> { group-name } ... ]
   [ <Ref> { group-name } ... ]
 }
 }
 
 
@@ -1746,8 +1757,8 @@ GROUPING ENTRIES
   and it may contain other joints.
   and it may contain other joints.
 
 
   A tree of <Joint> nodes only makes sense within a character
   A tree of <Joint> nodes only makes sense within a character
-  definition, which is created by applying the <DART> flag to a group.
-  See <DART>, above.
+  definition, which is created by applying the <Dart> flag to a group.
+  See <Dart>, above.
 
 
   The vertex assignment is crucial.  This is how the geometry of a
   The vertex assignment is crucial.  This is how the geometry of a
   character is made to move with the joints.  The character's geometry
   character is made to move with the joints.  The character's geometry
@@ -1790,7 +1801,7 @@ GROUPING ENTRIES
   bundles, or any one of the following (<Scalar> entries are optional,
   bundles, or any one of the following (<Scalar> entries are optional,
   and default as shown):
   and default as shown):
 
 
-  <S$Anim> name { 
+  <S$Anim> name {
       <Scalar> fps { 24 }
       <Scalar> fps { 24 }
       <V> { values }
       <V> { values }
   }
   }
@@ -1844,7 +1855,7 @@ GROUPING ENTRIES
     an animation sequence.
     an animation sequence.
 
 
 
 
-  <VertexAnim> name { 
+  <VertexAnim> name {
       <Scalar> width { table-width }
       <Scalar> width { table-width }
       <Scalar> fps { 24 }
       <Scalar> fps { 24 }
       <V> { values }
       <V> { values }
@@ -1913,6 +1924,10 @@ ANIMATION STRUCTURE
   animated model description.  Without the <Dart> flag, joints will be
   animated model description.  Without the <Dart> flag, joints will be
   treated as ordinary groups, and morphs will be ignored.
   treated as ordinary groups, and morphs will be ignored.
 
 
+  It is important to note that utilizing <Dart> { 1 } will collapse all of the
+  model's geometry into a single node. To omit this, use <Dart> { structured } instead.
+  (See <Dart> above.)
+
   In the above, UPPERCASE NAMES represent an arbitrary name that you
   In the above, UPPERCASE NAMES represent an arbitrary name that you
   may choose.  The name of the enclosing group, CHARACTER_NAME, is
   may choose.  The name of the enclosing group, CHARACTER_NAME, is
   taken as the name of the animated model.  It should generally match
   taken as the name of the animated model.  It should generally match

+ 10 - 10
panda/src/doc/howto.MultiGenModelFlags

@@ -3,7 +3,7 @@
 
 
 This document describes the different kinds of model flags one can place in
 This document describes the different kinds of model flags one can place in
 the comment field of MultiGen group beads.  The general format for a model
 the comment field of MultiGen group beads.  The general format for a model
-flag is: 
+flag is:
                        <egg> { <FLAGNAME> {value} }
                        <egg> { <FLAGNAME> {value} }
 
 
 The most up-to-date version of this document can be found in:
 The most up-to-date version of this document can be found in:
@@ -30,7 +30,7 @@ The most up-to-date version of this document can be found in:
 <egg> { <ObjectType> {camera-barrier} }      Invisible collision surface for camera and colliders
 <egg> { <ObjectType> {camera-barrier} }      Invisible collision surface for camera and colliders
 <egg> { <ObjectType> {camera-barrier-sphere} }     Invisible sphere collision surface for camera and colliders
 <egg> { <ObjectType> {camera-barrier-sphere} }     Invisible sphere collision surface for camera and colliders
 <egg> { <ObjectType> {backstage} }  Modeling reference object
 <egg> { <ObjectType> {backstage} }  Modeling reference object
-<egg> { <Decal>      {1} }          Decal the node below to me 
+<egg> { <Decal>      {1} }          Decal the node below to me
                                     (like a window on a wall)
                                     (like a window on a wall)
 <egg> { <Scalar> fps { # } }        Set rate of animation for a pfSequence
 <egg> { <Scalar> fps { # } }        Set rate of animation for a pfSequence
 
 
@@ -52,12 +52,12 @@ common flag/value pairs and describes what they are used for.
    which one places the flag (so names like red-hut are more useful than
    which one places the flag (so names like red-hut are more useful than
    names like o34).
    names like o34).
 
 
-<egg> { <Model> {1} }   
+<egg> { <Model> {1} }
 
 
-   Used to show/hide, change the color, or change the collision properties 
+   Used to show/hide, change the color, or change the collision properties
    of a chunk.
    of a chunk.
 
 
-<egg> { <DCS> {1} }     
+<egg> { <DCS> {1} }
 
 
    Used to move, rotate, or scale a chunk of the model.  Also can be used
    Used to move, rotate, or scale a chunk of the model.  Also can be used
    (like the <Model> flag) to show/hide, change the color, and change the
    (like the <Model> flag) to show/hide, change the color, and change the
@@ -91,7 +91,7 @@ common flag/value pairs and describes what they are used for.
          a door, for example, so the player can tell when the avatar has
          a door, for example, so the player can tell when the avatar has
          moved through the door.
          moved through the door.
       -  BACKSTAGE objects are not translated over to the player.  Modelers
       -  BACKSTAGE objects are not translated over to the player.  Modelers
-         should use this flag on reference objects that they include to help 
+         should use this flag on reference objects that they include to help
          in the modeling task (such as scale references)
          in the modeling task (such as scale references)
 
 
    IMPORTANT NOTE:
    IMPORTANT NOTE:
@@ -108,7 +108,7 @@ common flag/value pairs and describes what they are used for.
 
 
                      ********** PROPERTIES **********
                      ********** PROPERTIES **********
 
 
-These are used to control properties of selected chunks. 
+These are used to control properties of selected chunks.
 
 
 <egg> { <Scalar> fps { frame-rate } }
 <egg> { <Scalar> fps { frame-rate } }
 
 
@@ -124,7 +124,7 @@ These are used to control properties of selected chunks.
    Multiple Flag/value pairs can be combined within an single <egg> field.
    Multiple Flag/value pairs can be combined within an single <egg> field.
    For example:
    For example:
 
 
-   <egg> { <Model> {1}  
+   <egg> { <Model> {1}
            <ObjectType> {barrier} }
            <ObjectType> {barrier} }
 
 
    Generally, the <Model> flag can be combined with most other flags
    Generally, the <Model> flag can be combined with most other flags
@@ -134,7 +134,7 @@ These are used to control properties of selected chunks.
    could also be written as:
    could also be written as:
 
 
    <egg>{<model>{1}<objecttype>{barrier}}
    <egg>{<model>{1}<objecttype>{barrier}}
-         
+
 3) Where to place the flags
 3) Where to place the flags
 
 
    All model flags except <Normal> flags are generally placed in the
    All model flags except <Normal> flags are generally placed in the
@@ -154,6 +154,6 @@ These are used to control properties of selected chunks.
 4) Flags at different levels in the model
 4) Flags at different levels in the model
 
 
    Flags in lower level beads generally override flags in upper level
    Flags in lower level beads generally override flags in upper level
-   beads. 
+   beads.
 
 
 5) For more detailed information see $PANDA/src/doc/eggSyntax.txt.
 5) For more detailed information see $PANDA/src/doc/eggSyntax.txt.

+ 9 - 14
panda/src/egg2pg/characterMaker.cxx

@@ -36,10 +36,6 @@
 
 
 using std::string;
 using std::string;
 
 
-
-
-
-
 /**
 /**
  *
  *
  */
  */
@@ -589,16 +585,15 @@ determine_bin_home(EggBin *egg_bin) {
     // ahead and make an implicit node for the joint.
     // ahead and make an implicit node for the joint.
 
 
     if (egg_group->get_dcs_type() == EggGroup::DC_none) {
     if (egg_group->get_dcs_type() == EggGroup::DC_none) {
-/*
- * Unless the user specifically forbade exposing the joint by putting an
- * explicit "<DCS> { none }" entry in the joint.  In this case, we return NULL
- * to treat the geometry as dynamic (and animate it by animating its
- * vertices), but display lists and vertex buffers will perform better if more
- * geometry is rigid.  There's a tradeoff, though, since the cull traverser
- * will have to do more work with additional transforms in the scene graph,
- * and this may also break up the geometry into more individual pieces, which
- * is the biggest limiting factor on modern PC graphics cards.
- */
+      // Unless the user specifically forbade exposing the joint by putting an
+      // explicit "<DCS> { none }" entry in the joint.  In this case, we return
+      // nullptr to treat the geometry as dynamic (and animate it by animating
+      // its vertices), but display lists and vertex buffers will perform better
+      // if more geometry is rigid.  There's a tradeoff, though, since the cull
+      // traverser will have to do more work with additional transforms in the
+      // scene graph, and this may also break up the geometry into more
+      // individual pieces, which is the biggest limiting factor on modern PC
+      // graphics cards.
       return nullptr;
       return nullptr;
     }
     }
 
 

+ 32 - 0
panda/src/event/buttonEvent.I

@@ -149,3 +149,35 @@ update_mods(ModifierButtons &mods) const {
     return false;
     return false;
   }
   }
 }
 }
+
+/**
+ *
+ */
+INLINE ButtonHandle ButtonEvent::
+get_button() const {
+  return _button;
+}
+
+/**
+ *
+ */
+INLINE int ButtonEvent::
+get_keycode() const {
+  return _keycode;
+}
+
+/**
+ *
+ */
+INLINE ButtonEvent::Type ButtonEvent::
+get_type() const {
+  return _type;
+}
+
+/**
+ *
+ */
+INLINE double ButtonEvent::
+get_time() const {
+  return _time;
+}

+ 25 - 10
panda/src/event/buttonEvent.h

@@ -44,19 +44,20 @@ class DatagramIterator;
  * character set.
  * character set.
  */
  */
 class EXPCL_PANDA_EVENT ButtonEvent {
 class EXPCL_PANDA_EVENT ButtonEvent {
-public:
+PUBLISHED:
   enum Type {
   enum Type {
-/*
- * T_down and T_up represent a button changing state correspondingly.
- * T_resume_down is a special event that is only thrown when focus is returned
- * to a window and a button is detected as being held down at that point; it
- * indicates that the button should be considered down now (if it wasn't
- * already), but it didn't just get pressed down at this moment, it was
- * depressed some time ago.  It's mainly used for correct tracking of modifier
- * keys like shift and control, and can be ignored for other keys.
- */
+    // T_down is sent when a button was just pressed.
     T_down,
     T_down,
+
+    // T_resume_down is a special event that is only thrown when focus is
+    // returned to a window and a button is detected as being held down at that
+    // point; it indicates that the button should be considered down now (if it
+    // wasn't already), but it didn't just get pressed down at this moment, it
+    // was depressed some time ago.  It's mainly used for correct tracking of
+    // modifier keys like shift and control, and can be ignored for other keys.
     T_resume_down,
     T_resume_down,
+
+    // T_down is sent when a button is released.
     T_up,
     T_up,
 
 
     // T_repeat is sent for each a keyrepeat event generated by the system,
     // T_repeat is sent for each a keyrepeat event generated by the system,
@@ -84,6 +85,7 @@ public:
     T_raw_up,
     T_raw_up,
   };
   };
 
 
+public:
   INLINE ButtonEvent();
   INLINE ButtonEvent();
   INLINE ButtonEvent(ButtonHandle button, Type type, double time = ClockObject::get_global_clock()->get_frame_time());
   INLINE ButtonEvent(ButtonHandle button, Type type, double time = ClockObject::get_global_clock()->get_frame_time());
   INLINE ButtonEvent(int keycode, double time = ClockObject::get_global_clock()->get_frame_time());
   INLINE ButtonEvent(int keycode, double time = ClockObject::get_global_clock()->get_frame_time());
@@ -92,17 +94,30 @@ public:
   INLINE ButtonEvent(const ButtonEvent &copy);
   INLINE ButtonEvent(const ButtonEvent &copy);
   INLINE void operator = (const ButtonEvent &copy);
   INLINE void operator = (const ButtonEvent &copy);
 
 
+PUBLISHED:
   INLINE bool operator == (const ButtonEvent &other) const;
   INLINE bool operator == (const ButtonEvent &other) const;
   INLINE bool operator != (const ButtonEvent &other) const;
   INLINE bool operator != (const ButtonEvent &other) const;
   INLINE bool operator < (const ButtonEvent &other) const;
   INLINE bool operator < (const ButtonEvent &other) const;
 
 
+public:
   INLINE bool update_mods(ModifierButtons &mods) const;
   INLINE bool update_mods(ModifierButtons &mods) const;
 
 
+  INLINE ButtonHandle get_button() const;
+  INLINE int get_keycode() const;
+  INLINE Type get_type() const;
+  INLINE double get_time() const;
+
   void output(std::ostream &out) const;
   void output(std::ostream &out) const;
 
 
   void write_datagram(Datagram &dg) const;
   void write_datagram(Datagram &dg) const;
   void read_datagram(DatagramIterator &scan);
   void read_datagram(DatagramIterator &scan);
 
 
+PUBLISHED:
+  MAKE_PROPERTY(button, get_button);
+  MAKE_PROPERTY(keycode, get_keycode);
+  MAKE_PROPERTY(type, get_type);
+  MAKE_PROPERTY(time, get_time);
+
 public:
 public:
   // _button will be filled in if type is T_down, T_resume_down, or T_up.
   // _button will be filled in if type is T_down, T_resume_down, or T_up.
   ButtonHandle _button;
   ButtonHandle _button;

+ 2 - 0
panda/src/event/buttonEventList.h

@@ -47,6 +47,8 @@ PUBLISHED:
   virtual void output(std::ostream &out) const;
   virtual void output(std::ostream &out) const;
   void write(std::ostream &out, int indent_level = 0) const;
   void write(std::ostream &out, int indent_level = 0) const;
 
 
+  MAKE_SEQ_PROPERTY(events, get_num_events, get_event);
+
 private:
 private:
   typedef pvector<ButtonEvent> Events;
   typedef pvector<ButtonEvent> Events;
   Events _events;
   Events _events;

+ 2 - 1
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -14190,7 +14190,8 @@ upload_simple_texture(CLP(TextureContext) *gtc) {
 #endif
 #endif
   GLenum external_format = GL_BGRA;
   GLenum external_format = GL_BGRA;
 
 
-  const unsigned char *image_ptr = tex->get_simple_ram_image();
+  CPTA_uchar image = tex->get_simple_ram_image();
+  const unsigned char *image_ptr = image.p();
   if (image_ptr == nullptr) {
   if (image_ptr == nullptr) {
     return false;
     return false;
   }
   }

+ 5 - 2
panda/src/glstuff/glShaderContext_src.cxx

@@ -2911,10 +2911,13 @@ update_shader_texture_bindings(ShaderContext *prev) {
 
 
     // Bindless texturing wasn't supported or didn't work, so let's just bind
     // Bindless texturing wasn't supported or didn't work, so let's just bind
     // the texture normally.
     // the texture normally.
+    // Note that simple RAM images are always 2-D for now, so to avoid errors,
+    // we must load the real texture if this is not for a sampler2D.
+    bool force = (spec._desired_type != Texture::TT_2d_texture);
 #ifndef OPENGLES
 #ifndef OPENGLES
     if (multi_bind) {
     if (multi_bind) {
       // Multi-bind case.
       // Multi-bind case.
-      if (!_glgsg->update_texture(gtc, false)) {
+      if (!_glgsg->update_texture(gtc, force)) {
         textures[i] = 0;
         textures[i] = 0;
       } else {
       } else {
         gtc->set_active(true);
         gtc->set_active(true);
@@ -2934,7 +2937,7 @@ update_shader_texture_bindings(ShaderContext *prev) {
     {
     {
       // Non-multibind case.
       // Non-multibind case.
       _glgsg->set_active_texture_stage(i);
       _glgsg->set_active_texture_stage(i);
-      if (!_glgsg->update_texture(gtc, false)) {
+      if (!_glgsg->update_texture(gtc, force)) {
         continue;
         continue;
       }
       }
       _glgsg->apply_texture(gtc);
       _glgsg->apply_texture(gtc);

+ 57 - 0
panda/src/gobj/texture.cxx

@@ -10351,10 +10351,12 @@ make_this_from_bam(const FactoryParams &params) {
     // object to read all of the attributes from the bam stream.
     // object to read all of the attributes from the bam stream.
     Texture *dummy = this;
     Texture *dummy = this;
     AutoTextureScale auto_texture_scale = ATS_unspecified;
     AutoTextureScale auto_texture_scale = ATS_unspecified;
+    bool has_simple_ram_image = false;
     {
     {
       CDWriter cdata_dummy(dummy->_cycler, true);
       CDWriter cdata_dummy(dummy->_cycler, true);
       dummy->do_fillin_body(cdata_dummy, scan, manager);
       dummy->do_fillin_body(cdata_dummy, scan, manager);
       auto_texture_scale = cdata_dummy->_auto_texture_scale;
       auto_texture_scale = cdata_dummy->_auto_texture_scale;
+      has_simple_ram_image = !cdata_dummy->_simple_ram_image._image.empty();
     }
     }
 
 
     if (filename.empty()) {
     if (filename.empty()) {
@@ -10387,6 +10389,61 @@ make_this_from_bam(const FactoryParams &params) {
       case TT_1d_texture:
       case TT_1d_texture:
       case TT_2d_texture:
       case TT_2d_texture:
       case TT_1d_texture_array:
       case TT_1d_texture_array:
+        // If we don't want to preload textures, and we already have a simple
+        // RAM image (or don't need one), we don't need to load it from disk.
+        // We do check for it in the texture pool first, though, in case it has
+        // already been loaded.
+        if ((options.get_texture_flags() & LoaderOptions::TF_preload) == 0 &&
+            (has_simple_ram_image || (options.get_texture_flags() & LoaderOptions::TF_preload_simple) == 0)) {
+          if (alpha_filename.empty()) {
+            me = TexturePool::get_texture(filename, primary_file_num_channels,
+                                          has_read_mipmaps);
+          } else {
+            me = TexturePool::get_texture(filename, alpha_filename,
+                                          primary_file_num_channels,
+                                          alpha_file_channel,
+                                          has_read_mipmaps);
+          }
+          if (me != nullptr && me->get_texture_type() == texture_type) {
+            // We can use this.
+            break;
+          }
+
+          // We don't have a texture, but we didn't need to preload it, so we
+          // can just use this one.  We just need to know where we can find it
+          // when we do need to reload it.
+          Filename fullpath = filename;
+          Filename alpha_fullpath = alpha_filename;
+          const DSearchPath &model_path = get_model_path();
+          if (vfs->resolve_filename(fullpath, model_path) &&
+              (alpha_fullpath.empty() || vfs->resolve_filename(alpha_fullpath, model_path))) {
+            me = dummy;
+            me->set_name(name);
+
+            {
+              CDWriter cdata_me(me->_cycler, true);
+              cdata_me->_filename = filename;
+              cdata_me->_alpha_filename = alpha_filename;
+              cdata_me->_fullpath = fullpath;
+              cdata_me->_alpha_fullpath = alpha_fullpath;
+              cdata_me->_primary_file_num_channels = primary_file_num_channels;
+              cdata_me->_alpha_file_channel = alpha_file_channel;
+              cdata_me->_texture_type = texture_type;
+              cdata_me->_loaded_from_image = true;
+              cdata_me->_has_read_mipmaps = has_read_mipmaps;
+            }
+
+            // To manage the reference count, explicitly ref it now, then unref
+            // it in the finalize callback.
+            me->ref();
+            manager->register_finalize(me);
+
+            // Do add it to the cache now, so that future uses of this same
+            // texture are unified.
+            TexturePool::add_texture(me);
+            return me;
+          }
+        }
         if (alpha_filename.empty()) {
         if (alpha_filename.empty()) {
           me = TexturePool::load_texture(filename, primary_file_num_channels,
           me = TexturePool::load_texture(filename, primary_file_num_channels,
                                          has_read_mipmaps, options);
                                          has_read_mipmaps, options);

+ 23 - 0
panda/src/gobj/texturePool.I

@@ -33,6 +33,29 @@ verify_texture(const Filename &filename) {
   return load_texture(filename) != nullptr;
   return load_texture(filename) != nullptr;
 }
 }
 
 
+/**
+ * Returns the texture that has already been previously loaded, or NULL
+ * otherwise.
+ */
+INLINE Texture *TexturePool::
+get_texture(const Filename &filename, int primary_file_num_channels,
+            bool read_mipmaps) {
+  return get_global_ptr()->ns_get_texture(filename, primary_file_num_channels,
+                                          read_mipmaps);
+}
+
+/**
+ * Returns the texture that has already been previously loaded, or NULL
+ * otherwise.
+ */
+INLINE Texture *TexturePool::
+get_texture(const Filename &filename, const Filename &alpha_filename,
+            int primary_file_num_channels, int alpha_file_channel,
+            bool read_mipmaps) {
+  return get_global_ptr()->ns_get_texture(filename, primary_file_num_channels,
+                                          read_mipmaps);
+}
+
 /**
 /**
  * Loads the given filename up into a texture, if it has not already been
  * Loads the given filename up into a texture, if it has not already been
  * loaded, and returns the new texture.  If a texture with the same filename
  * loaded, and returns the new texture.  If a texture with the same filename

+ 56 - 0
panda/src/gobj/texturePool.cxx

@@ -273,6 +273,62 @@ ns_has_texture(const Filename &orig_filename) {
   return false;
   return false;
 }
 }
 
 
+/**
+ * The nonstatic implementation of get_texture().
+ */
+Texture *TexturePool::
+ns_get_texture(const Filename &orig_filename, int primary_file_num_channels,
+               bool read_mipmaps) {
+  LookupKey key;
+  key._primary_file_num_channels = primary_file_num_channels;
+  {
+    MutexHolder holder(_lock);
+    resolve_filename(key._fullpath, orig_filename, read_mipmaps, LoaderOptions());
+
+    Textures::const_iterator ti;
+    ti = _textures.find(key);
+    if (ti != _textures.end()) {
+      // This texture was previously loaded.
+      Texture *tex = (*ti).second;
+      nassertr(!tex->get_fullpath().empty(), tex);
+      return tex;
+    }
+  }
+
+  return nullptr;
+}
+
+/**
+ * The nonstatic implementation of get_texture().
+ */
+Texture *TexturePool::
+ns_get_texture(const Filename &orig_filename,
+               const Filename &orig_alpha_filename,
+               int primary_file_num_channels,
+               int alpha_file_channel,
+               bool read_mipmaps) {
+  LookupKey key;
+  key._primary_file_num_channels = primary_file_num_channels;
+  key._alpha_file_channel = alpha_file_channel;
+  {
+    MutexHolder holder(_lock);
+    LoaderOptions options;
+    resolve_filename(key._fullpath, orig_filename, read_mipmaps, options);
+    resolve_filename(key._alpha_fullpath, orig_alpha_filename, read_mipmaps, options);
+
+    Textures::const_iterator ti;
+    ti = _textures.find(key);
+    if (ti != _textures.end()) {
+      // This texture was previously loaded.
+      Texture *tex = (*ti).second;
+      nassertr(!tex->get_fullpath().empty(), tex);
+      return tex;
+    }
+  }
+
+  return nullptr;
+}
+
 /**
 /**
  * The nonstatic implementation of load_texture().
  * The nonstatic implementation of load_texture().
  */
  */

+ 16 - 0
panda/src/gobj/texturePool.h

@@ -38,6 +38,14 @@ class EXPCL_PANDA_GOBJ TexturePool {
 PUBLISHED:
 PUBLISHED:
   INLINE static bool has_texture(const Filename &filename);
   INLINE static bool has_texture(const Filename &filename);
   INLINE static bool verify_texture(const Filename &filename);
   INLINE static bool verify_texture(const Filename &filename);
+  INLINE static Texture *get_texture(const Filename &filename,
+                                     int primary_file_num_channels = 0,
+                                     bool read_mipmaps = false);
+  INLINE static Texture *get_texture(const Filename &filename,
+                                     const Filename &alpha_filename,
+                                     int primary_file_num_channels = 0,
+                                     int alpha_file_channel = 0,
+                                     bool read_mipmaps = false);
   BLOCKING INLINE static Texture *load_texture(const Filename &filename,
   BLOCKING INLINE static Texture *load_texture(const Filename &filename,
                                                int primary_file_num_channels = 0,
                                                int primary_file_num_channels = 0,
                                                bool read_mipmaps = false,
                                                bool read_mipmaps = false,
@@ -109,6 +117,14 @@ private:
   TexturePool();
   TexturePool();
 
 
   bool ns_has_texture(const Filename &orig_filename);
   bool ns_has_texture(const Filename &orig_filename);
+  Texture *ns_get_texture(const Filename &filename,
+                          int primary_file_num_channels = 0,
+                          bool read_mipmaps = false);
+  Texture *ns_get_texture(const Filename &filename,
+                          const Filename &alpha_filename,
+                          int primary_file_num_channels = 0,
+                          int alpha_file_channel = 0,
+                          bool read_mipmaps = false);
   Texture *ns_load_texture(const Filename &orig_filename,
   Texture *ns_load_texture(const Filename &orig_filename,
                            int primary_file_num_channels,
                            int primary_file_num_channels,
                            bool read_mipmaps,
                            bool read_mipmaps,

+ 24 - 18
panda/src/gobj/textureReloadRequest.cxx

@@ -22,28 +22,34 @@ TypeHandle TextureReloadRequest::_type_handle;
 AsyncTask::DoneStatus TextureReloadRequest::
 AsyncTask::DoneStatus TextureReloadRequest::
 do_task() {
 do_task() {
   // Don't reload the texture if it doesn't need it.
   // Don't reload the texture if it doesn't need it.
-  if (_texture->was_image_modified(_pgo)) {
-    double delay = async_load_delay;
-    if (delay != 0.0) {
-      Thread::sleep(delay);
-    }
+  if (!_texture->was_image_modified(_pgo) &&
+      (_allow_compressed ? _texture->has_ram_image() : _texture->has_uncompressed_ram_image())) {
+    return DS_done;
+  }
+
+  double delay = async_load_delay;
+  if (delay != 0.0) {
+    Thread::sleep(delay);
 
 
-    if (_texture->was_image_modified(_pgo)) {
-      if (_allow_compressed) {
-        _texture->get_ram_image();
-      } else {
-        _texture->get_uncompressed_ram_image();
-      }
-
-      // Now that we've loaded the texture, we should ensure it actually gets
-      // prepared--even if it's no longer visible in the frame--or it may
-      // become a kind of a leak (if the texture is never rendered again on
-      // this GSG, we'll just end up carrying the texture memory in RAM
-      // forever, instead of dumping it as soon as it gets prepared).
-      _pgo->enqueue_texture(_texture);
+    if (!_texture->was_image_modified(_pgo) &&
+        (_allow_compressed ? _texture->has_ram_image() : _texture->has_uncompressed_ram_image())) {
+      return DS_done;
     }
     }
   }
   }
 
 
+  if (_allow_compressed) {
+    _texture->get_ram_image();
+  } else {
+    _texture->get_uncompressed_ram_image();
+  }
+
+  // Now that we've loaded the texture, we should ensure it actually gets
+  // prepared--even if it's no longer visible in the frame--or it may become a
+  // kind of a leak (if the texture is never rendered again on this GSG, we'll
+  // just end up carrying the texture memory in RAM forever, instead of dumping
+  // it as soon as it gets prepared).
+  _pgo->enqueue_texture(_texture);
+
   // Don't continue the task; we're done.
   // Don't continue the task; we're done.
   return DS_done;
   return DS_done;
 }
 }

+ 0 - 1
panda/src/linmath/lquaternion_src.cxx

@@ -106,7 +106,6 @@ set_hpr(const FLOATNAME(LVecBase3) &hpr, CoordinateSystem cs) {
   v = FLOATNAME(LVector3)::right(cs);
   v = FLOATNAME(LVector3)::right(cs);
   a = deg_2_rad(hpr[1] * 0.5f);
   a = deg_2_rad(hpr[1] * 0.5f);
   csincos(a, &s, &c);
   csincos(a, &s, &c);
-  s = csin(a);
   quat_p.set(c, v[0] * s, v[1] * s, v[2] * s);
   quat_p.set(c, v[0] * s, v[1] * s, v[2] * s);
   v = FLOATNAME(LVector3)::forward(cs);
   v = FLOATNAME(LVector3)::forward(cs);
   a = deg_2_rad(hpr[2] * 0.5f);
   a = deg_2_rad(hpr[2] * 0.5f);