Browse Source

extend ModelNode::preserve_transform and Texture::alpha_file_channel

David Rose 23 years ago
parent
commit
df2a60cfb0

+ 20 - 16
panda/src/doc/eggSyntax.txt

@@ -761,26 +761,30 @@ GROUPING ENTRIES
 
 
   <DCS> { boolean-value }
   <DCS> { boolean-value }
 
 
-    This indicates that this group contains geometry that might need
-    to be repositioned interactively relative to the rest of the
-    scene.  The egg loader interprets this by creating a pfDCS node
-    instead of a pfGroup node.  This also implies <Model>, below.
-
-  <TexList> { boolean-value }
-
-    This indicates that this group contains geometry whose textures
-    might need to be separately managed.  A special xpfTexListNode is
-    created for this group.  This also implies <Model>.
+    DCS stands for Dynamic Coordinate System.  This indicates that
+    show code will expect to be able to read the transform set on this
+    node at run time, and may need to modify the transform further.
+    This is a special case of <Model>, below.
+
+  <DCS> { dcs-type }
+
+    This is another syntax for the <DCS> flag.  The dcs-type string
+    should be one of either "local" or "net", which specifies the kind
+    of preserve_transform flag that will be set on the corresponding
+    ModelNode.  If the string is "local", it indicates that the local
+    transform on this node (as well as the net transform) will not be
+    affected by any flattening operation and will be preserved through
+    the entire model loading process.  If the string is "net", then
+    only the net transform will be preserved; the local transform may
+    be adjusted in the event of a flatten operation.
 
 
   <Model> { boolean-value }
   <Model> { boolean-value }
 
 
     This indicates that the show code might need a pointer to this
     This indicates that the show code might need a pointer to this
-    particular group.  If any nodes in the egg file have the <Model>
-    flag set, the egg loader creates an xpfModelRoot node as the root
-    node of the file, which keeps a short list of all the nodes with
-    the <Model> flag set.  This allows quick access to these nodes by
-    the show code at run time.  In the old player this also implied
-    <DCS>, but it doesn't any more.
+    particular group.  This creates a ModelNode at the corresponding
+    level, which is guaranteed not to be removed by any flatten
+    operation.  However, its transform might still be changed, but see
+    also the <DCS> flag, above.
 
 
 
 
   <Dart> { boolean-value }
   <Dart> { boolean-value }

+ 10 - 1
panda/src/egg/eggData.cxx

@@ -165,7 +165,16 @@ read(istream &in) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void EggData::
 void EggData::
 merge(EggData &other) {
 merge(EggData &other) {
-  other.set_coordinate_system(get_coordinate_system());
+  if (get_coordinate_system() == CS_default) {
+    // If we haven't specified a coordinate system yet, we inherit the
+    // other one's.
+    set_coordinate_system(other.get_coordinate_system());
+
+  } else {
+    // Otherwise, the other one is forced into our coordinate system
+    // before we merge.
+    other.set_coordinate_system(get_coordinate_system());
+  }
   steal_children(other);
   steal_children(other);
 }
 }
 
 

+ 10 - 12
panda/src/egg/eggGroup.I

@@ -217,27 +217,25 @@ get_collide_flags() const {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: EggGroup::set_dcs_flag
+//     Function: EggGroup::set_dcs_type
 //       Access: Public
 //       Access: Public
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void EggGroup::
 INLINE void EggGroup::
-set_dcs_flag(bool flag) {
-  if (flag) {
-    _flags |= F_dcs_flag;
-  } else {
-    _flags &= ~F_dcs_flag;
-  }
+set_dcs_type(EggGroup::DCSType type) {
+  // Make sure the user didn't give us any stray bits.
+  nassertv((type & ~F2_dcs_type)==0);
+  _flags2 = (_flags2 & ~F2_dcs_type) | type;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: EggGroup::get_dcs_flag
+//     Function: EggGroup::get_dcs_type
 //       Access: Public
 //       Access: Public
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE bool EggGroup::
-get_dcs_flag() const {
-  return ((_flags & F_dcs_flag) != 0);
+INLINE EggGroup::DCSType EggGroup::
+get_dcs_type() const {
+  return (DCSType)(_flags2 & F2_dcs_type);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -246,7 +244,7 @@ get_dcs_flag() const {
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void EggGroup::
 INLINE void EggGroup::
-set_dart_type(DartType type) {
+set_dart_type(EggGroup::DartType type) {
   // Make sure the user didn't give us any stray bits.
   // Make sure the user didn't give us any stray bits.
   nassertv((type & ~F_dart_type)==0);
   nassertv((type & ~F_dart_type)==0);
   _flags = (_flags & ~F_dart_type) | type;
   _flags = (_flags & ~F_dart_type) | type;

+ 43 - 2
panda/src/egg/eggGroup.cxx

@@ -236,8 +236,9 @@ write(ostream &out, int indent_level) const {
     out << " }\n";
     out << " }\n";
   }
   }
 
 
-  if (get_dcs_flag()) {
-    indent(out, indent_level + 2) << "<DCS> { 1 }\n";
+  if (get_dcs_type() != DC_none) {
+    indent(out, indent_level + 2) 
+      << "<DCS> { " << get_dcs_type() << " }\n";
   }
   }
 
 
   if (get_dart_type() != DT_none) {
   if (get_dart_type() != DT_none) {
@@ -542,6 +543,26 @@ string_dart_type(const string &string) {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggGroup::string_dcs_type
+//       Access: Public, Static
+//  Description: Returns the DCSType value associated with the given
+//               string representation, or DC_none if the string
+//               does not match any known DCSType value.
+////////////////////////////////////////////////////////////////////
+EggGroup::DCSType EggGroup::
+string_dcs_type(const string &string) {
+  if (cmp_nocase_uh(string, "local") == 0) {
+    return DC_local;
+  } else if (cmp_nocase_uh(string, "net") == 0) {
+    return DC_net;
+  } else if (cmp_nocase_uh(string, "default") == 0) {
+    return DC_default;
+  } else {
+    return DC_none;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EggGroup::string_billboard_type
 //     Function: EggGroup::string_billboard_type
 //       Access: Public, Static
 //       Access: Public, Static
@@ -897,6 +918,26 @@ ostream &operator << (ostream &out, EggGroup::DartType t) {
   return out << "(**invalid**)";
   return out << "(**invalid**)";
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: DCSType output operator
+//  Description:
+////////////////////////////////////////////////////////////////////
+ostream &operator << (ostream &out, EggGroup::DCSType t) {
+  switch (t) {
+  case EggGroup::DC_none:
+    return out << "none";
+  case EggGroup::DC_local:
+    return out << "local";
+  case EggGroup::DC_net:
+    return out << "net";
+  case EggGroup::DC_default:
+    return out << "1";
+  }
+
+  nassertr(false, out);
+  return out << "(**invalid**)";
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: BillboardType output operator
 //     Function: BillboardType output operator
 //  Description:
 //  Description:

+ 14 - 3
panda/src/egg/eggGroup.h

@@ -56,6 +56,13 @@ public:
     DT_nosync                = 0x00000008,
     DT_nosync                = 0x00000008,
     DT_default               = 0x0000000c,
     DT_default               = 0x0000000c,
   };
   };
+  enum DCSType {
+    // The bits here must correspond to those in Flags2, below.
+    DC_none                  = 0x00000000,
+    DC_local                 = 0x00000010,
+    DC_net                   = 0x00000020,
+    DC_default               = 0x00000030,
+  };
   enum BillboardType {
   enum BillboardType {
     // The bits here must correspond to those in Flags, below.
     // The bits here must correspond to those in Flags, below.
     BT_none                  = 0x00000000,
     BT_none                  = 0x00000000,
@@ -121,8 +128,8 @@ public:
   INLINE bool has_collision_name() const;
   INLINE bool has_collision_name() const;
   INLINE const string &get_collision_name() const;
   INLINE const string &get_collision_name() const;
 
 
-  INLINE void set_dcs_flag(bool flag);
-  INLINE bool get_dcs_flag() const;
+  INLINE void set_dcs_type(DCSType type);
+  INLINE DCSType get_dcs_type() const;
 
 
   INLINE void set_dart_type(DartType type);
   INLINE void set_dart_type(DartType type);
   INLINE DartType get_dart_type() const;
   INLINE DartType get_dart_type() const;
@@ -192,6 +199,7 @@ public:
 
 
   static GroupType string_group_type(const string &string);
   static GroupType string_group_type(const string &string);
   static DartType string_dart_type(const string &string);
   static DartType string_dart_type(const string &string);
+  static DCSType string_dcs_type(const string &string);
   static BillboardType string_billboard_type(const string &string);
   static BillboardType string_billboard_type(const string &string);
   static CollisionSolidType string_cs_type(const string &string);
   static CollisionSolidType string_cs_type(const string &string);
   static CollideFlags string_collide_flags(const string &string);
   static CollideFlags string_collide_flags(const string &string);
@@ -211,7 +219,7 @@ private:
   enum Flags {
   enum Flags {
     F_group_type             = 0x00000003,
     F_group_type             = 0x00000003,
     F_dart_type              = 0x0000000c,
     F_dart_type              = 0x0000000c,
-    F_dcs_flag               = 0x00000010,
+
     F_billboard_type         = 0x000000e0,
     F_billboard_type         = 0x000000e0,
     F_switch_flag            = 0x00000100,
     F_switch_flag            = 0x00000100,
     F_model_flag             = 0x00000400,
     F_model_flag             = 0x00000400,
@@ -227,6 +235,8 @@ private:
     F2_from_collide_mask     = 0x00000002,
     F2_from_collide_mask     = 0x00000002,
     F2_into_collide_mask     = 0x00000004,
     F2_into_collide_mask     = 0x00000004,
     F2_billboard_center      = 0x00000008,
     F2_billboard_center      = 0x00000008,
+
+    F2_dcs_type              = 0x00000030,
   };
   };
 
 
   int _flags;
   int _flags;
@@ -263,6 +273,7 @@ private:
 
 
 ostream &operator << (ostream &out, EggGroup::GroupType t);
 ostream &operator << (ostream &out, EggGroup::GroupType t);
 ostream &operator << (ostream &out, EggGroup::DartType t);
 ostream &operator << (ostream &out, EggGroup::DartType t);
+ostream &operator << (ostream &out, EggGroup::DCSType t);
 ostream &operator << (ostream &out, EggGroup::BillboardType t);
 ostream &operator << (ostream &out, EggGroup::BillboardType t);
 ostream &operator << (ostream &out, EggGroup::CollisionSolidType t);
 ostream &operator << (ostream &out, EggGroup::CollisionSolidType t);
 ostream &operator << (ostream &out, EggGroup::CollideFlags t);
 ostream &operator << (ostream &out, EggGroup::CollideFlags t);

+ 58 - 6
panda/src/egg/eggTexture.I

@@ -206,15 +206,13 @@ has_anisotropic_degree() const {
 //     Function: EggTexture::get_anisotropic_degree
 //     Function: EggTexture::get_anisotropic_degree
 //       Access: Public
 //       Access: Public
 //  Description: Returns the anisotropic filtering degree that has
 //  Description: Returns the anisotropic filtering degree that has
-//               been specified for this texture.  It is an error to
-//               call this unless has_anisotropic_degree() returns
-//               true.
+//               been specified for this texture, or 0 if nothing has
+//               been specified.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE int EggTexture::
 INLINE int EggTexture::
 get_anisotropic_degree() const {
 get_anisotropic_degree() const {
-  //  nassertr(has_anisotropic_degree(), 1);
-
-  // note: _anisotropic_degree's of 0 and 1 are equivalent (no anisotropic filtering to be done by gsg)
+  // note: _anisotropic_degree of 0 and 1 are equivalent (no
+  // anisotropic filtering to be done by gsg)
   return _anisotropic_degree;
   return _anisotropic_degree;
 }
 }
 
 
@@ -382,6 +380,60 @@ set_alpha_fullpath(const Filename &alpha_fullpath) {
   _alpha_fullpath = alpha_fullpath;
   _alpha_fullpath = alpha_fullpath;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggTexture::set_alpha_file_channel
+//       Access: Public
+//  Description: If a separate alpha-file is specified, this indicates
+//               which channel number should be extracted from this
+//               file to derive the alpha channel for the final image.
+//               The default is 0, which means the grayscale
+//               combination of r, g, b.  Otherwise, this should be
+//               the 1-based channel number, for instance 1, 2, or 3
+//               for r, g, or b, respectively, or 4 for the alpha
+//               channel of a four-component image.
+////////////////////////////////////////////////////////////////////
+INLINE void EggTexture::
+set_alpha_file_channel(int alpha_file_channel) {
+  _alpha_file_channel = alpha_file_channel;
+  _flags |= F_has_alpha_file_channel;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTexture::clear_alpha_file_channel
+//       Access: Public
+//  Description: Removes the specification of a particular channel to
+//               use from the alpha-file image.
+////////////////////////////////////////////////////////////////////
+INLINE void EggTexture::
+clear_alpha_file_channel() {
+  _alpha_file_channel = 0;
+  _flags &= ~F_has_alpha_file_channel;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTexture::has_alpha_file_channel
+//       Access: Public
+//  Description: Returns true if a particular channel has been
+//               specified for the alpha-file image, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool EggTexture::
+has_alpha_file_channel() const {
+  return (_flags & F_has_alpha_file_channel) != 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTexture::get_alpha_file_channel
+//       Access: Public
+//  Description: Returns the particular channel that has been
+//               specified for the alpha-file image, or 0 if no
+//               channel has been specified.  See
+//               set_alpha_file_channel().
+////////////////////////////////////////////////////////////////////
+INLINE int EggTexture::
+get_alpha_file_channel() const {
+  return _alpha_file_channel;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: UniqueEggTextures::Constructor
 //     Function: UniqueEggTextures::Constructor
 //       Access: Public
 //       Access: Public

+ 8 - 0
panda/src/egg/eggTexture.cxx

@@ -45,6 +45,7 @@ EggTexture(const string &tref_name, const string &filename)
   _env_type = ET_unspecified;
   _env_type = ET_unspecified;
   _flags = 0;
   _flags = 0;
   _transform = LMatrix3d::ident_mat();
   _transform = LMatrix3d::ident_mat();
+  _alpha_file_channel = 0;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -79,6 +80,7 @@ operator = (const EggTexture &copy) {
   _transform = copy._transform;
   _transform = copy._transform;
   _alpha_filename = copy._alpha_filename;
   _alpha_filename = copy._alpha_filename;
   _alpha_fullpath = copy._alpha_fullpath;
   _alpha_fullpath = copy._alpha_fullpath;
+  _alpha_file_channel = copy._alpha_file_channel;
 
 
   return *this;
   return *this;
 }
 }
@@ -101,6 +103,12 @@ write(ostream &out, int indent_level) const {
     out << " }\n";
     out << " }\n";
   }
   }
 
 
+  if (has_alpha_file_channel()) {
+    indent(out, indent_level + 2)
+      << "<Scalar> alpha-file-channel { " 
+      << get_alpha_file_channel() << " }\n";
+  }
+
   if (get_format() != F_unspecified) {
   if (get_format() != F_unspecified) {
     indent(out, indent_level + 2)
     indent(out, indent_level + 2)
       << "<Scalar> format { " << get_format() << " }\n";
       << "<Scalar> format { " << get_format() << " }\n";

+ 7 - 0
panda/src/egg/eggTexture.h

@@ -128,6 +128,11 @@ public:
   INLINE void set_alpha_fullpath(const Filename &fullpath);
   INLINE void set_alpha_fullpath(const Filename &fullpath);
   INLINE const Filename &get_alpha_fullpath() const;
   INLINE const Filename &get_alpha_fullpath() const;
 
 
+  INLINE void set_alpha_file_channel(int alpha_file_channel);
+  INLINE void clear_alpha_file_channel();
+  INLINE bool has_alpha_file_channel() const;
+  INLINE int get_alpha_file_channel() const;
+
   static Format string_format(const string &string);
   static Format string_format(const string &string);
   static WrapMode string_wrap_mode(const string &string);
   static WrapMode string_wrap_mode(const string &string);
   static FilterType string_filter_type(const string &string);
   static FilterType string_filter_type(const string &string);
@@ -141,6 +146,7 @@ private:
     F_has_transform          = 0x0001,
     F_has_transform          = 0x0001,
     F_has_alpha_filename     = 0x0002,
     F_has_alpha_filename     = 0x0002,
     F_has_anisotropic_degree = 0x0004,
     F_has_anisotropic_degree = 0x0004,
+    F_has_alpha_file_channel = 0x0008,
   };
   };
 
 
   Format _format;
   Format _format;
@@ -152,6 +158,7 @@ private:
   LMatrix3d _transform;
   LMatrix3d _transform;
   Filename _alpha_filename;
   Filename _alpha_filename;
   Filename _alpha_fullpath;
   Filename _alpha_fullpath;
+  int _alpha_file_channel;
 
 
 
 
 public:
 public:

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

@@ -397,6 +397,9 @@ texture_body:
   } else if (cmp_nocase_uh(name, "alpha_file") == 0) {
   } else if (cmp_nocase_uh(name, "alpha_file") == 0) {
     texture->set_alpha_filename(strval);
     texture->set_alpha_filename(strval);
 
 
+  } else if (cmp_nocase_uh(name, "alpha_file_channel") == 0) {
+    texture->set_alpha_file_channel((int)value);
+
   } else {
   } else {
     eggyywarning("Unsupported texture scalar: " + name);
     eggyywarning("Unsupported texture scalar: " + name);
   }
   }
@@ -940,7 +943,20 @@ group_body:
 {
 {
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   int value = (int)$4;
   int value = (int)$4;
-  group->set_dcs_flag(value!=0);
+  group->set_dcs_type(value!=0 ? EggGroup::DC_default : EggGroup::DC_none);
+}
+        | group_body DCS '{' STRING '}'
+{
+  // The special flavor of DCS, with { sync } or { nosync }.
+  EggGroup *group = DCAST(EggGroup, egg_stack.back());
+  string strval = $4;
+
+  EggGroup::DCSType f = EggGroup::string_dcs_type(strval);
+  if (f == EggGroup::DC_none) {
+    eggyywarning("Unknown DCS type " + strval);
+  } else {
+    group->set_dcs_type(f);
+  }
 }
 }
         | group_body DART '{' integer '}'
         | group_body DART '{' integer '}'
 {
 {

+ 2 - 2
panda/src/egg2pg/characterMaker.cxx

@@ -185,7 +185,7 @@ build_joint_hierarchy(EggNode *egg_node, PartGroup *part) {
       index = _parts.size();
       index = _parts.size();
       _parts.push_back(joint);
       _parts.push_back(joint);
 
 
-      if (egg_group->get_dcs_flag()) {
+      if (egg_group->get_dcs_type() != EggGroup::DC_none) {
         // If the joint requested an explicit DCS, create a node for
         // If the joint requested an explicit DCS, create a node for
         // it.
         // it.
         joint->_geom_node = new PandaNode(egg_group->get_name());
         joint->_geom_node = new PandaNode(egg_group->get_name());
@@ -375,7 +375,7 @@ determine_primitive_home(EggPrimitive *egg_primitive) {
 
 
   if (egg_group != (EggGroup *)NULL &&
   if (egg_group != (EggGroup *)NULL &&
       egg_group->get_group_type() == EggGroup::GT_joint &&
       egg_group->get_group_type() == EggGroup::GT_joint &&
-      !egg_group->get_dcs_flag()) {
+      egg_group->get_dcs_type() == EggGroup::DC_none) {
     // If the home is a joint without a <DCS> flag--this is the normal
     // If the home is a joint without a <DCS> flag--this is the normal
     // case--we'll move the polygon under the character node and
     // case--we'll move the polygon under the character node and
     // animate it from there explicitly.
     // animate it from there explicitly.

+ 31 - 12
panda/src/egg2pg/eggLoader.cxx

@@ -476,21 +476,24 @@ load_textures() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool EggLoader::
 bool EggLoader::
 load_texture(TextureDef &def, const EggTexture *egg_tex) {
 load_texture(TextureDef &def, const EggTexture *egg_tex) {
-  // Check to see if we should reduce the number of components in
+  // Check to see if we should reduce the number of channels in
   // the texture.
   // the texture.
-  int wanted_components = 0;
+  int wanted_channels = 0;
+  bool wanted_alpha = false;
   switch (egg_tex->get_format()) {
   switch (egg_tex->get_format()) {
   case EggTexture::F_red:
   case EggTexture::F_red:
   case EggTexture::F_green:
   case EggTexture::F_green:
   case EggTexture::F_blue:
   case EggTexture::F_blue:
   case EggTexture::F_alpha:
   case EggTexture::F_alpha:
   case EggTexture::F_luminance:
   case EggTexture::F_luminance:
-    wanted_components = 1;
+    wanted_channels = 1;
+    wanted_alpha = false;
     break;
     break;
 
 
   case EggTexture::F_luminance_alpha:
   case EggTexture::F_luminance_alpha:
   case EggTexture::F_luminance_alphamask:
   case EggTexture::F_luminance_alphamask:
-    wanted_components = 2;
+    wanted_channels = 2;
+    wanted_alpha = true;
     break;
     break;
 
 
   case EggTexture::F_rgb:
   case EggTexture::F_rgb:
@@ -498,7 +501,8 @@ load_texture(TextureDef &def, const EggTexture *egg_tex) {
   case EggTexture::F_rgb8:
   case EggTexture::F_rgb8:
   case EggTexture::F_rgb5:
   case EggTexture::F_rgb5:
   case EggTexture::F_rgb332:
   case EggTexture::F_rgb332:
-    wanted_components = 3;
+    wanted_channels = 3;
+    wanted_alpha = false;
     break;
     break;
 
 
   case EggTexture::F_rgba:
   case EggTexture::F_rgba:
@@ -507,7 +511,8 @@ load_texture(TextureDef &def, const EggTexture *egg_tex) {
   case EggTexture::F_rgba8:
   case EggTexture::F_rgba8:
   case EggTexture::F_rgba4:
   case EggTexture::F_rgba4:
   case EggTexture::F_rgba5:
   case EggTexture::F_rgba5:
-    wanted_components = 4;
+    wanted_channels = 4;
+    wanted_alpha = true;
     break;
     break;
 
 
   case EggTexture::F_unspecified:
   case EggTexture::F_unspecified:
@@ -515,13 +520,14 @@ load_texture(TextureDef &def, const EggTexture *egg_tex) {
   }
   }
 
 
   Texture *tex;
   Texture *tex;
-  if (egg_tex->has_alpha_filename()) {
+  if (egg_tex->has_alpha_filename() && wanted_alpha) {
     tex = TexturePool::load_texture(egg_tex->get_fullpath(),
     tex = TexturePool::load_texture(egg_tex->get_fullpath(),
                                     egg_tex->get_alpha_fullpath(),
                                     egg_tex->get_alpha_fullpath(),
-                                    wanted_components);
+                                    wanted_channels,
+                                    egg_tex->get_alpha_file_channel());
   } else {
   } else {
     tex = TexturePool::load_texture(egg_tex->get_fullpath(),
     tex = TexturePool::load_texture(egg_tex->get_fullpath(),
-                                    wanted_components);
+                                    wanted_channels);
   }
   }
   if (tex == (Texture *)NULL) {
   if (tex == (Texture *)NULL) {
     return false;
     return false;
@@ -531,7 +537,7 @@ load_texture(TextureDef &def, const EggTexture *egg_tex) {
   // egg file).  These filenames will be written back to the bam file
   // egg file).  These filenames will be written back to the bam file
   // if the bam file is written out.
   // if the bam file is written out.
   tex->set_filename(egg_tex->get_filename());
   tex->set_filename(egg_tex->get_filename());
-  if (egg_tex->has_alpha_filename()) {
+  if (egg_tex->has_alpha_filename() && wanted_alpha) {
     tex->set_alpha_filename(egg_tex->get_alpha_filename());
     tex->set_alpha_filename(egg_tex->get_alpha_filename());
   }
   }
 
 
@@ -1373,10 +1379,23 @@ make_node(EggGroup *egg_group, PandaNode *parent) {
       make_node(*ci, node);
       make_node(*ci, node);
     }
     }
 
 
-  } else if (egg_group->get_model_flag() || egg_group->get_dcs_flag()) {
+  } else if (egg_group->get_model_flag() || 
+             egg_group->get_dcs_type() != EggGroup::DC_none) {
     // A model or DCS flag; create a model node.
     // A model or DCS flag; create a model node.
     node = new ModelNode(egg_group->get_name());
     node = new ModelNode(egg_group->get_name());
-    DCAST(ModelNode, node)->set_preserve_transform(egg_group->get_dcs_flag());
+    switch (egg_group->get_dcs_type()) {
+    case EggGroup::DC_net:
+      DCAST(ModelNode, node)->set_preserve_transform(ModelNode::PT_net);
+      break;
+
+    case EggGroup::DC_local:
+    case EggGroup::DC_default:
+      DCAST(ModelNode, node)->set_preserve_transform(ModelNode::PT_local);
+      break;
+
+    case EggGroup::DC_none:
+      break;
+    }
 
 
     EggGroup::const_iterator ci;
     EggGroup::const_iterator ci;
     for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
     for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {

+ 33 - 9
panda/src/gobj/imageBuffer.cxx

@@ -16,23 +16,37 @@
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
-////////////////////////////////////////////////////////////////////
-// Includes
-////////////////////////////////////////////////////////////////////
-#include <pandabase.h>
+#include "pandabase.h"
 
 
 #include "imageBuffer.h"
 #include "imageBuffer.h"
 #include "config_gobj.h"
 #include "config_gobj.h"
 #include "config_util.h"
 #include "config_util.h"
 
 
-#include <datagram.h>
-#include <datagramIterator.h>
-#include <bamReader.h>
+#include "datagram.h"
+#include "datagramIterator.h"
+#include "bamReader.h"
+
+TypeHandle ImageBuffer::_type_handle;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-// Static variables
+//     Function: ImageBuffer::Constructor
+//       Access: Public
+//  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-TypeHandle ImageBuffer::_type_handle;
+ImageBuffer::
+ImageBuffer() {
+  _primary_file_num_channels = 0;
+  _alpha_file_channel = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ImageBuffer::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+ImageBuffer::
+~ImageBuffer() {
+}
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: ImageBuffer::write_datagram
 //     Function: ImageBuffer::write_datagram
@@ -85,6 +99,8 @@ write_datagram(BamWriter *, Datagram &me)
   me.add_string(get_name());
   me.add_string(get_name());
   me.add_string(filename);
   me.add_string(filename);
   me.add_string(alpha_filename);
   me.add_string(alpha_filename);
+  me.add_uint8(_primary_file_num_channels);
+  me.add_uint8(_alpha_file_channel);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -100,4 +116,12 @@ fillin(DatagramIterator &scan, BamReader *manager) {
   set_name(scan.get_string());
   set_name(scan.get_string());
   set_filename(scan.get_string());
   set_filename(scan.get_string());
   set_alpha_filename(scan.get_string());
   set_alpha_filename(scan.get_string());
+
+  if (manager->get_file_minor_ver() < 3) {
+    _primary_file_num_channels = 0;
+    _alpha_file_channel = 0;
+  } else {
+    _primary_file_num_channels = scan.get_uint8();
+    _alpha_file_channel = scan.get_uint8();
+  }
 }
 }

+ 17 - 9
panda/src/gobj/imageBuffer.h

@@ -27,10 +27,6 @@
 #include "filename.h"
 #include "filename.h"
 #include "namable.h"
 #include "namable.h"
 
 
-////////////////////////////////////////////////////////////////////
-// Defines
-////////////////////////////////////////////////////////////////////
-
 class RenderBuffer;
 class RenderBuffer;
 class DisplayRegion;
 class DisplayRegion;
 
 
@@ -41,8 +37,8 @@ class DisplayRegion;
 class EXPCL_PANDA ImageBuffer : public ReferenceCount,
 class EXPCL_PANDA ImageBuffer : public ReferenceCount,
                                 public WritableConfigurable, public Namable {
                                 public WritableConfigurable, public Namable {
 PUBLISHED:
 PUBLISHED:
-  ImageBuffer() { }
-  virtual ~ImageBuffer() { }
+  ImageBuffer();
+  virtual ~ImageBuffer();
 
 
 public:
 public:
   virtual void config( void ) { WritableConfigurable::config(); }
   virtual void config( void ) { WritableConfigurable::config(); }
@@ -79,12 +75,24 @@ private:
   Filename _fullpath;
   Filename _fullpath;
   Filename _alpha_fullpath;
   Filename _alpha_fullpath;
 
 
+protected:
+  // These are set by (and read by) the derived Texture class.
+
+  // The number of channels of the primary file we use.  1, 2, 3, or 4.
+  int _primary_file_num_channels;
+
+  // If we have a separate alpha file, this designates which channel
+  // in the alpha file provides the alpha channel.  0 indicates the
+  // combined grayscale value of rgb; otherwise, 1, 2, 3, or 4 are
+  // valid.
+  int _alpha_file_channel;
+
 public:
 public:
-  //Abstract class, so no factory methods for Reading and Writing
-  virtual void write_datagram(BamWriter* manager, Datagram &me);
+  // Abstract class, so no factory methods for Reading and Writing
+  virtual void write_datagram(BamWriter *manager, Datagram &me);
 
 
 protected:
 protected:
-  void fillin(DatagramIterator& scan, BamReader* manager);
+  void fillin(DatagramIterator &scan, BamReader *manager);
 
 
 public:
 public:
 
 

+ 68 - 47
panda/src/gobj/texture.cxx

@@ -106,22 +106,22 @@ consider_rescale(PNMImage &pnmimage, const string &name) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: consider_downgrade
 //     Function: consider_downgrade
 //  Description: Reduces the number of channels in the texture, if
 //  Description: Reduces the number of channels in the texture, if
-//               necessary, according to num_components.
+//               necessary, according to num_channels.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 static void
 static void
-consider_downgrade(PNMImage &pnmimage, int num_components, 
+consider_downgrade(PNMImage &pnmimage, int num_channels, 
                    const string &name) {
                    const string &name) {
-  if (num_components != 0 && num_components < pnmimage.get_num_channels()) {
+  if (num_channels != 0 && num_channels < pnmimage.get_num_channels()) {
     // One special case: we can't reduce from 3 to 2 components, since
     // One special case: we can't reduce from 3 to 2 components, since
     // that would require adding an alpha channel.
     // that would require adding an alpha channel.
-    if (pnmimage.get_num_channels() == 3 && num_components == 2) {
+    if (pnmimage.get_num_channels() == 3 && num_channels == 2) {
       return;
       return;
     }
     }
 
 
     gobj_cat.info()
     gobj_cat.info()
       << "Downgrading " << name << " from " << pnmimage.get_num_channels()
       << "Downgrading " << name << " from " << pnmimage.get_num_channels()
-      << " components to " << num_components << ".\n";
-    pnmimage.set_num_channels(num_components);
+      << " components to " << num_channels << ".\n";
+    pnmimage.set_num_channels(num_channels);
   }
   }
 }
 }
 
 
@@ -179,12 +179,12 @@ Texture::
 //     Function: read
 //     Function: read
 //       Access: Published
 //       Access: Published
 //  Description: Reads the texture from the indicated filename.  If
 //  Description: Reads the texture from the indicated filename.  If
-//               num_components is not 0, it specifies the number of
+//               num_channels is not 0, it specifies the number of
 //               components to downgrade the image to if it is greater
 //               components to downgrade the image to if it is greater
 //               than this number.
 //               than this number.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool Texture::
 bool Texture::
-read(const Filename &fullpath, int num_components) {
+read(const Filename &fullpath, int primary_file_num_channels) {
   PNMImage image;
   PNMImage image;
 
 
   if (!image.read(fullpath)) {
   if (!image.read(fullpath)) {
@@ -206,7 +206,11 @@ read(const Filename &fullpath, int num_components) {
 
 
   // Check to see if we need to scale it.
   // Check to see if we need to scale it.
   consider_rescale(image, get_name());
   consider_rescale(image, get_name());
-  consider_downgrade(image, num_components, get_name());
+  consider_downgrade(image, primary_file_num_channels, get_name());
+
+  _primary_file_num_channels = image.get_num_channels();
+  _alpha_file_channel = 0;
+
   return load(image);
   return load(image);
 }
 }
 
 
@@ -218,7 +222,7 @@ read(const Filename &fullpath, int num_components) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool Texture::
 bool Texture::
 read(const Filename &fullpath, const Filename &alpha_fullpath,
 read(const Filename &fullpath, const Filename &alpha_fullpath,
-     int num_components) {
+     int primary_file_num_channels, int alpha_file_channel) {
   PNMImage image;
   PNMImage image;
   if (!image.read(fullpath)) {
   if (!image.read(fullpath)) {
     gobj_cat.error()
     gobj_cat.error()
@@ -263,16 +267,44 @@ read(const Filename &fullpath, const Filename &alpha_fullpath,
     alpha_image = scaled;
     alpha_image = scaled;
   }
   }
 
 
+  consider_downgrade(image, primary_file_num_channels, get_name());
+
+  _primary_file_num_channels = image.get_num_channels();
+
   // Make the original image a 4-component image by taking the
   // Make the original image a 4-component image by taking the
   // grayscale value from the second image.
   // grayscale value from the second image.
   image.add_alpha();
   image.add_alpha();
-  for (int x = 0; x < image.get_x_size(); x++) {
-    for (int y = 0; y < image.get_y_size(); y++) {
-      image.set_alpha(x, y, alpha_image.get_gray(x, y));
+
+  if (alpha_file_channel == 4 || 
+      (alpha_file_channel == 2 && alpha_image.get_num_channels() == 2)) {
+    // Use the alpha channel.
+    for (int x = 0; x < image.get_x_size(); x++) {
+      for (int y = 0; y < image.get_y_size(); y++) {
+        image.set_alpha(x, y, alpha_image.get_alpha(x, y));
+      }
+    }
+    _alpha_file_channel = alpha_image.get_num_channels();
+
+  } else if (alpha_file_channel >= 1 && alpha_file_channel <= 3 &&
+             alpha_image.get_num_channels() >= 3) {
+    // Use the appropriate red, green, or blue channel.
+    for (int x = 0; x < image.get_x_size(); x++) {
+      for (int y = 0; y < image.get_y_size(); y++) {
+        image.set_alpha(x, y, alpha_image.get_channel_val(x, y, alpha_file_channel - 1));
+      }
+    }
+    _alpha_file_channel = alpha_file_channel;
+
+  } else {
+    // Use the grayscale channel.
+    for (int x = 0; x < image.get_x_size(); x++) {
+      for (int y = 0; y < image.get_y_size(); y++) {
+        image.set_alpha(x, y, alpha_image.get_gray(x, y));
+      }
     }
     }
+    _alpha_file_channel = 0;
   }
   }
 
 
-  consider_downgrade(image, num_components, get_name());
   return load(image);
   return load(image);
 }
 }
 
 
@@ -697,18 +729,16 @@ make_Texture(const FactoryParams &params) {
 
 
   parse_params(params, scan, manager);
   parse_params(params, scan, manager);
 
 
-  string name;
-  Filename filename, alpha_filename;
-
   // Get the properties written by ImageBuffer::write_datagram().
   // Get the properties written by ImageBuffer::write_datagram().
-  name = scan.get_string();
-  filename = scan.get_string();
-  alpha_filename = scan.get_string();
+  string name = scan.get_string();
+  Filename filename = scan.get_string();
+  Filename alpha_filename = scan.get_string();
+  int primary_file_num_channels = 0;  
+  int alpha_file_channel = 0;  
 
 
-  // Get the expected number of components.
-  int num_components = 0;
-  if (manager->get_file_minor_ver() >= 2) {
-    num_components = scan.get_uint8();
+  if (manager->get_file_minor_ver() >= 3) {
+    primary_file_num_channels = scan.get_uint8();
+    alpha_file_channel = scan.get_uint8();
   }
   }
 
 
   PT(Texture) me;
   PT(Texture) me;
@@ -722,9 +752,10 @@ make_Texture(const FactoryParams &params) {
   } else {
   } else {
     // This texture does have a filename, so try to load it from disk.
     // This texture does have a filename, so try to load it from disk.
     if (alpha_filename.empty()) {
     if (alpha_filename.empty()) {
-      me = TexturePool::load_texture(filename, num_components);
+      me = TexturePool::load_texture(filename, primary_file_num_channels);
     } else {
     } else {
-      me = TexturePool::load_texture(filename, alpha_filename, num_components);
+      me = TexturePool::load_texture(filename, alpha_filename, 
+                                     primary_file_num_channels, alpha_file_channel);
     }
     }
   }
   }
 
 
@@ -766,21 +797,17 @@ fillin(DatagramIterator &scan, BamReader *manager) {
   _magfilter = (enum FilterType) scan.get_uint8();
   _magfilter = (enum FilterType) scan.get_uint8();
   _anisotropic_degree = scan.get_int16();
   _anisotropic_degree = scan.get_int16();
 
 
-  if (scan.get_remaining_size() > 0) {
-    bool has_pbuffer = scan.get_bool();
-    if (has_pbuffer) {
-      PixelBuffer::Format format = (PixelBuffer::Format)scan.get_uint8();
-      int num_components = -1;
-      if (scan.get_remaining_size() > 0) {
-        num_components = scan.get_uint8();
-      }
-
-      if (_pbuffer != (PixelBuffer *)NULL) {
-        if (num_components == _pbuffer->get_num_components()) {
-          // Only reset the format if the number of components hasn't
-          // changed.
-          _pbuffer->set_format(format);
-        }
+  bool has_pbuffer = scan.get_bool();
+  if (has_pbuffer) {
+    PixelBuffer::Format format = (PixelBuffer::Format)scan.get_uint8();
+    int num_channels = -1;
+    num_channels = scan.get_uint8();
+
+    if (_pbuffer != (PixelBuffer *)NULL) {
+      if (num_channels == _pbuffer->get_num_components()) {
+        // Only reset the format if the number of components hasn't
+        // changed.
+        _pbuffer->set_format(format);
       }
       }
     }
     }
   }
   }
@@ -800,11 +827,6 @@ write_datagram(BamWriter *manager, Datagram &me) {
 
 
   // These properties are read in again by make_Texture(), above.
   // These properties are read in again by make_Texture(), above.
   ImageBuffer::write_datagram(manager, me);
   ImageBuffer::write_datagram(manager, me);
-  if (has_pbuffer) {
-    me.add_uint8(_pbuffer->get_num_components());
-  } else {
-    me.add_uint8(0);
-  }
 
 
   // These properties are read in again by fillin(), above.
   // These properties are read in again by fillin(), above.
   me.add_uint8(_wrapu);
   me.add_uint8(_wrapu);
@@ -816,7 +838,6 @@ write_datagram(BamWriter *manager, Datagram &me) {
   me.add_bool(has_pbuffer);
   me.add_bool(has_pbuffer);
   if (has_pbuffer) {
   if (has_pbuffer) {
     me.add_uint8(_pbuffer->get_format());
     me.add_uint8(_pbuffer->get_format());
-    // I know this has already been written, above.
     me.add_uint8(_pbuffer->get_num_components());
     me.add_uint8(_pbuffer->get_num_components());
   }
   }
 }
 }

+ 2 - 2
panda/src/gobj/texture.h

@@ -79,9 +79,9 @@ PUBLISHED:
           bool bAllocateRAM);
           bool bAllocateRAM);
   ~Texture();
   ~Texture();
 
 
-  bool read(const Filename &fullpath, int num_components = 0);
+  bool read(const Filename &fullpath, int primary_file_num_channels = 0);
   bool read(const Filename &fullpath, const Filename &alpha_fullpath,
   bool read(const Filename &fullpath, const Filename &alpha_fullpath,
-            int num_components = 0);
+            int primary_file_num_channels = 0, int alpha_file_channel = 0);
   bool write(const Filename &fullpath = "") const;
   bool write(const Filename &fullpath = "") const;
 
 
   void set_wrapu(WrapMode wrap);
   void set_wrapu(WrapMode wrap);

+ 6 - 4
panda/src/gobj/texturePool.I

@@ -52,8 +52,8 @@ verify_texture(const string &filename) {
 //               file cannot be found, returns NULL.
 //               file cannot be found, returns NULL.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE Texture *TexturePool::
 INLINE Texture *TexturePool::
-load_texture(const string &filename, int num_components) {
-  return get_ptr()->ns_load_texture(filename, num_components);
+load_texture(const string &filename, int primary_file_num_channels) {
+  return get_ptr()->ns_load_texture(filename, primary_file_num_channels);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -67,8 +67,10 @@ load_texture(const string &filename, int num_components) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE Texture *TexturePool::
 INLINE Texture *TexturePool::
 load_texture(const string &filename, const string &alpha_filename,
 load_texture(const string &filename, const string &alpha_filename,
-             int num_components) {
-  return get_ptr()->ns_load_texture(filename, alpha_filename, num_components);
+             int primary_file_num_channels, int alpha_file_channel) {
+  return get_ptr()->ns_load_texture(filename, alpha_filename, 
+                                    primary_file_num_channels,
+                                    alpha_file_channel);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 7 - 5
panda/src/gobj/texturePool.cxx

@@ -65,7 +65,7 @@ ns_has_texture(const Filename &orig_filename) {
 //  Description: The nonstatic implementation of load_texture().
 //  Description: The nonstatic implementation of load_texture().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 Texture *TexturePool::
 Texture *TexturePool::
-ns_load_texture(const Filename &orig_filename, int num_components) {
+ns_load_texture(const Filename &orig_filename, int primary_file_num_channels) {
   Filename filename(orig_filename);
   Filename filename(orig_filename);
 
 
   if (!fake_texture_image.empty()) {
   if (!fake_texture_image.empty()) {
@@ -92,7 +92,7 @@ ns_load_texture(const Filename &orig_filename, int num_components) {
   gobj_cat.info()
   gobj_cat.info()
     << "Loading texture " << filename << "\n";
     << "Loading texture " << filename << "\n";
   PT(Texture) tex = new Texture;
   PT(Texture) tex = new Texture;
-  if (!tex->read(filename, num_components)) {
+  if (!tex->read(filename, primary_file_num_channels)) {
     // This texture was not found.
     // This texture was not found.
     gobj_cat.error()
     gobj_cat.error()
       << "Unable to read texture " << filename << "\n";
       << "Unable to read texture " << filename << "\n";
@@ -114,12 +114,13 @@ ns_load_texture(const Filename &orig_filename, int num_components) {
 Texture *TexturePool::
 Texture *TexturePool::
 ns_load_texture(const Filename &orig_filename, 
 ns_load_texture(const Filename &orig_filename, 
                 const Filename &orig_alpha_filename,
                 const Filename &orig_alpha_filename,
-                int num_components) {
+                int primary_file_num_channels,
+                int alpha_file_channel) {
   Filename filename(orig_filename);
   Filename filename(orig_filename);
   Filename alpha_filename(orig_alpha_filename);
   Filename alpha_filename(orig_alpha_filename);
 
 
   if (!fake_texture_image.empty()) {
   if (!fake_texture_image.empty()) {
-    return ns_load_texture(fake_texture_image, num_components);
+    return ns_load_texture(fake_texture_image, primary_file_num_channels);
   }
   }
 
 
   if (use_vfs) {
   if (use_vfs) {
@@ -149,7 +150,8 @@ ns_load_texture(const Filename &orig_filename,
     << "Loading texture " << filename << " and alpha component "
     << "Loading texture " << filename << " and alpha component "
     << alpha_filename << endl;
     << alpha_filename << endl;
   PT(Texture) tex = new Texture;
   PT(Texture) tex = new Texture;
-  if (!tex->read(filename, alpha_filename, num_components)) {
+  if (!tex->read(filename, alpha_filename, primary_file_num_channels,
+                 alpha_file_channel)) {
     // This texture was not found.
     // This texture was not found.
     gobj_cat.error() << "Unable to read texture " << filename << "\n";
     gobj_cat.error() << "Unable to read texture " << filename << "\n";
     return NULL;
     return NULL;

+ 6 - 4
panda/src/gobj/texturePool.h

@@ -41,10 +41,11 @@ PUBLISHED:
   INLINE static bool has_texture(const string &filename);
   INLINE static bool has_texture(const string &filename);
   INLINE static bool verify_texture(const string &filename);
   INLINE static bool verify_texture(const string &filename);
   INLINE static Texture *load_texture(const string &filename, 
   INLINE static Texture *load_texture(const string &filename, 
-                                      int num_components = 0);
+                                      int primary_file_num_channels = 0);
   INLINE static Texture *load_texture(const string &filename,
   INLINE static Texture *load_texture(const string &filename,
                                       const string &alpha_filename, 
                                       const string &alpha_filename, 
-                                      int num_components = 0);
+                                      int primary_file_num_channels = 0,
+                                      int alpha_file_channel = 0);
   INLINE static void add_texture(Texture *texture);
   INLINE static void add_texture(Texture *texture);
   INLINE static void release_texture(Texture *texture);
   INLINE static void release_texture(Texture *texture);
   INLINE static void release_all_textures();
   INLINE static void release_all_textures();
@@ -57,10 +58,11 @@ private:
   INLINE TexturePool();
   INLINE TexturePool();
 
 
   bool ns_has_texture(const Filename &orig_filename);
   bool ns_has_texture(const Filename &orig_filename);
-  Texture *ns_load_texture(const Filename &orig_filename, int num_components);
+  Texture *ns_load_texture(const Filename &orig_filename, int primary_file_num_channels);
   Texture *ns_load_texture(const Filename &orig_filename, 
   Texture *ns_load_texture(const Filename &orig_filename, 
                            const Filename &orig_alpha_filename, 
                            const Filename &orig_alpha_filename, 
-                           int num_components);
+                           int primary_file_num_channels,
+                           int alpha_file_channel);
   void ns_add_texture(Texture *texture);
   void ns_add_texture(Texture *texture);
   void ns_release_texture(Texture *texture);
   void ns_release_texture(Texture *texture);
   void ns_release_all_textures();
   void ns_release_all_textures();

+ 20 - 8
panda/src/pgraph/modelNode.I

@@ -26,20 +26,32 @@ INLINE ModelNode::
 ModelNode(const string &name) :
 ModelNode(const string &name) :
   PandaNode(name)
   PandaNode(name)
 {
 {
-  _preserve_transform = false;
+  _preserve_transform = PT_none;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: ModelNode::set_preserve_transform
 //     Function: ModelNode::set_preserve_transform
 //       Access: Public
 //       Access: Public
-//  Description: Sets the preserve_transform flag.  When this flag is
-//               true, flattening the scene graph will not flatten out
-//               any transformation assigned above this node;
-//               otherwise, any transforms applying to this node may
-//               or may not be flattened.
+//  Description: Sets the preserve_transform flag.  This restricts the
+//               ability of a flatten operation to affect the
+//               transform stored on this node.  If the flag is:
+//
+//               PT_none - the transform may be adjusted at will.
+//
+//               PT_local - the local (and net) transform should not
+//               be changed in any way.  If necessary, an extra
+//               transform will be left on the node above to guarantee
+//               this.  This is the strongest restriction.
+//
+//               PT_net - preserve the net transform from the
+//               root, but it's acceptable to modify the local
+//               transform stored on this particular node if
+//               necessary, so long as the net transform is not
+//               changed.  This eliminates the need to drop an extra
+//               transform on the node above.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void ModelNode::
 INLINE void ModelNode::
-set_preserve_transform(bool preserve_transform) {
+set_preserve_transform(ModelNode::PreserveTransform preserve_transform) {
   _preserve_transform = preserve_transform;
   _preserve_transform = preserve_transform;
 }
 }
 
 
@@ -49,7 +61,7 @@ set_preserve_transform(bool preserve_transform) {
 //  Description: Returns the current setting of the preserve_transform
 //  Description: Returns the current setting of the preserve_transform
 //               flag.  See set_preserve_transform().
 //               flag.  See set_preserve_transform().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE bool ModelNode::
+INLINE ModelNode::PreserveTransform ModelNode::
 get_preserve_transform() const {
 get_preserve_transform() const {
   return _preserve_transform;
   return _preserve_transform;
 }
 }

+ 4 - 4
panda/src/pgraph/modelNode.cxx

@@ -62,7 +62,7 @@ safe_to_flatten() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool ModelNode::
 bool ModelNode::
 safe_to_transform() const {
 safe_to_transform() const {
-  return !_preserve_transform;
+  return _preserve_transform == PT_none;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -79,7 +79,7 @@ safe_to_transform() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool ModelNode::
 bool ModelNode::
 safe_to_modify_transform() const {
 safe_to_modify_transform() const {
-  return !_preserve_transform;
+  return _preserve_transform != PT_local;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -129,7 +129,7 @@ register_with_read_factory() {
 void ModelNode::
 void ModelNode::
 write_datagram(BamWriter *manager, Datagram &dg) {
 write_datagram(BamWriter *manager, Datagram &dg) {
   PandaNode::write_datagram(manager, dg);
   PandaNode::write_datagram(manager, dg);
-  dg.add_bool(_preserve_transform);
+  dg.add_uint8((int)_preserve_transform);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -163,5 +163,5 @@ void ModelNode::
 fillin(DatagramIterator &scan, BamReader *manager) {
 fillin(DatagramIterator &scan, BamReader *manager) {
   PandaNode::fillin(scan, manager);
   PandaNode::fillin(scan, manager);
 
 
-  _preserve_transform = scan.get_bool();
+  _preserve_transform = (PreserveTransform)scan.get_uint8();
 }
 }

+ 9 - 3
panda/src/pgraph/modelNode.h

@@ -52,11 +52,17 @@ public:
   virtual bool preserve_name() const;
   virtual bool preserve_name() const;
 
 
 PUBLISHED:
 PUBLISHED:
-  INLINE void set_preserve_transform(bool preserve_transform);
-  INLINE bool get_preserve_transform() const;
+  enum PreserveTransform {
+    PT_none,
+    PT_local,
+    PT_net
+  };
+
+  INLINE void set_preserve_transform(PreserveTransform preserve_transform);
+  INLINE PreserveTransform get_preserve_transform() const;
 
 
 private:
 private:
-  bool _preserve_transform;
+  PreserveTransform _preserve_transform;
 
 
 public:
 public:
   static void register_with_read_factory();
   static void register_with_read_factory();

+ 2 - 1
panda/src/putil/bam.h

@@ -34,9 +34,10 @@ static const unsigned short _bam_major_ver = 4;
 // Bumped to major version 3 on 12/8/00 to change float64's to float32's.
 // Bumped to major version 3 on 12/8/00 to change float64's to float32's.
 // Bumped to major version 4 on 4/10/02 to store new scene graph.
 // Bumped to major version 4 on 4/10/02 to store new scene graph.
 
 
-static const unsigned short _bam_minor_ver = 2;
+static const unsigned short _bam_minor_ver = 3;
 // Bumped to minor version 1 on 4/10/03 to add CullFaceAttrib::reverse.
 // Bumped to minor version 1 on 4/10/03 to add CullFaceAttrib::reverse.
 // Bumped to minor version 2 on 4/12/03 to add num_components to texture.
 // Bumped to minor version 2 on 4/12/03 to add num_components to texture.
+// Bumped to minor version 3 on 4/15/03 to add ImageBuffer::_alpha_file_channel.
 
 
 
 
 #endif
 #endif