From df2a60cfb09c24ed56e42c0eafd1d7ca759f818e Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 15 Apr 2003 22:35:07 +0000 Subject: [PATCH] extend ModelNode::preserve_transform and Texture::alpha_file_channel --- panda/src/doc/eggSyntax.txt | 32 ++++---- panda/src/egg/eggData.cxx | 11 ++- panda/src/egg/eggGroup.I | 22 +++--- panda/src/egg/eggGroup.cxx | 45 ++++++++++- panda/src/egg/eggGroup.h | 17 ++++- panda/src/egg/eggTexture.I | 64 ++++++++++++++-- panda/src/egg/eggTexture.cxx | 8 ++ panda/src/egg/eggTexture.h | 7 ++ panda/src/egg/parser.yxx | 18 ++++- panda/src/egg2pg/characterMaker.cxx | 4 +- panda/src/egg2pg/eggLoader.cxx | 43 ++++++++--- panda/src/gobj/imageBuffer.cxx | 42 ++++++++--- panda/src/gobj/imageBuffer.h | 26 ++++--- panda/src/gobj/texture.cxx | 113 +++++++++++++++++----------- panda/src/gobj/texture.h | 4 +- panda/src/gobj/texturePool.I | 10 ++- panda/src/gobj/texturePool.cxx | 12 +-- panda/src/gobj/texturePool.h | 10 ++- panda/src/pgraph/modelNode.I | 28 +++++-- panda/src/pgraph/modelNode.cxx | 8 +- panda/src/pgraph/modelNode.h | 12 ++- panda/src/putil/bam.h | 3 +- 22 files changed, 391 insertions(+), 148 deletions(-) diff --git a/panda/src/doc/eggSyntax.txt b/panda/src/doc/eggSyntax.txt index 03fcf1b179..42f561f31f 100644 --- a/panda/src/doc/eggSyntax.txt +++ b/panda/src/doc/eggSyntax.txt @@ -761,26 +761,30 @@ GROUPING ENTRIES { 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 , below. + 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 , below. - { boolean-value } + { dcs-type } - 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 . + This is another syntax for the 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. { boolean-value } This indicates that the show code might need a pointer to this - particular group. If any nodes in the egg file have the - 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 flag set. This allows quick access to these nodes by - the show code at run time. In the old player this also implied - , 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 flag, above. { boolean-value } diff --git a/panda/src/egg/eggData.cxx b/panda/src/egg/eggData.cxx index 1792fb46dd..ee22c881b4 100644 --- a/panda/src/egg/eggData.cxx +++ b/panda/src/egg/eggData.cxx @@ -165,7 +165,16 @@ read(istream &in) { //////////////////////////////////////////////////////////////////// void EggData:: 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); } diff --git a/panda/src/egg/eggGroup.I b/panda/src/egg/eggGroup.I index 158984b1d6..f1d8fd0016 100644 --- a/panda/src/egg/eggGroup.I +++ b/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 // Description: //////////////////////////////////////////////////////////////////// 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 // 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: //////////////////////////////////////////////////////////////////// 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. nassertv((type & ~F_dart_type)==0); _flags = (_flags & ~F_dart_type) | type; diff --git a/panda/src/egg/eggGroup.cxx b/panda/src/egg/eggGroup.cxx index 324934d404..c5a0f2187a 100644 --- a/panda/src/egg/eggGroup.cxx +++ b/panda/src/egg/eggGroup.cxx @@ -236,8 +236,9 @@ write(ostream &out, int indent_level) const { out << " }\n"; } - if (get_dcs_flag()) { - indent(out, indent_level + 2) << " { 1 }\n"; + if (get_dcs_type() != DC_none) { + indent(out, indent_level + 2) + << " { " << get_dcs_type() << " }\n"; } 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 // Access: Public, Static @@ -897,6 +918,26 @@ ostream &operator << (ostream &out, EggGroup::DartType t) { 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 // Description: diff --git a/panda/src/egg/eggGroup.h b/panda/src/egg/eggGroup.h index 798c745ebb..0df92c0e46 100644 --- a/panda/src/egg/eggGroup.h +++ b/panda/src/egg/eggGroup.h @@ -56,6 +56,13 @@ public: DT_nosync = 0x00000008, 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 { // The bits here must correspond to those in Flags, below. BT_none = 0x00000000, @@ -121,8 +128,8 @@ public: INLINE bool has_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 DartType get_dart_type() const; @@ -192,6 +199,7 @@ public: static GroupType string_group_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 CollisionSolidType string_cs_type(const string &string); static CollideFlags string_collide_flags(const string &string); @@ -211,7 +219,7 @@ private: enum Flags { F_group_type = 0x00000003, F_dart_type = 0x0000000c, - F_dcs_flag = 0x00000010, + F_billboard_type = 0x000000e0, F_switch_flag = 0x00000100, F_model_flag = 0x00000400, @@ -227,6 +235,8 @@ private: F2_from_collide_mask = 0x00000002, F2_into_collide_mask = 0x00000004, F2_billboard_center = 0x00000008, + + F2_dcs_type = 0x00000030, }; int _flags; @@ -263,6 +273,7 @@ private: ostream &operator << (ostream &out, EggGroup::GroupType 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::CollisionSolidType t); ostream &operator << (ostream &out, EggGroup::CollideFlags t); diff --git a/panda/src/egg/eggTexture.I b/panda/src/egg/eggTexture.I index bf25cc17d7..7bd6fdf0d2 100644 --- a/panda/src/egg/eggTexture.I +++ b/panda/src/egg/eggTexture.I @@ -206,15 +206,13 @@ has_anisotropic_degree() const { // Function: EggTexture::get_anisotropic_degree // Access: Public // 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:: 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; } @@ -382,6 +380,60 @@ set_alpha_fullpath(const Filename &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 // Access: Public diff --git a/panda/src/egg/eggTexture.cxx b/panda/src/egg/eggTexture.cxx index 747b91e709..83ede469c8 100644 --- a/panda/src/egg/eggTexture.cxx +++ b/panda/src/egg/eggTexture.cxx @@ -45,6 +45,7 @@ EggTexture(const string &tref_name, const string &filename) _env_type = ET_unspecified; _flags = 0; _transform = LMatrix3d::ident_mat(); + _alpha_file_channel = 0; } //////////////////////////////////////////////////////////////////// @@ -79,6 +80,7 @@ operator = (const EggTexture ©) { _transform = copy._transform; _alpha_filename = copy._alpha_filename; _alpha_fullpath = copy._alpha_fullpath; + _alpha_file_channel = copy._alpha_file_channel; return *this; } @@ -101,6 +103,12 @@ write(ostream &out, int indent_level) const { out << " }\n"; } + if (has_alpha_file_channel()) { + indent(out, indent_level + 2) + << " alpha-file-channel { " + << get_alpha_file_channel() << " }\n"; + } + if (get_format() != F_unspecified) { indent(out, indent_level + 2) << " format { " << get_format() << " }\n"; diff --git a/panda/src/egg/eggTexture.h b/panda/src/egg/eggTexture.h index 026849295c..db96d8edae 100644 --- a/panda/src/egg/eggTexture.h +++ b/panda/src/egg/eggTexture.h @@ -128,6 +128,11 @@ public: INLINE void set_alpha_fullpath(const Filename &fullpath); 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 WrapMode string_wrap_mode(const string &string); static FilterType string_filter_type(const string &string); @@ -141,6 +146,7 @@ private: F_has_transform = 0x0001, F_has_alpha_filename = 0x0002, F_has_anisotropic_degree = 0x0004, + F_has_alpha_file_channel = 0x0008, }; Format _format; @@ -152,6 +158,7 @@ private: LMatrix3d _transform; Filename _alpha_filename; Filename _alpha_fullpath; + int _alpha_file_channel; public: diff --git a/panda/src/egg/parser.yxx b/panda/src/egg/parser.yxx index e242e329a2..5bbc1b8270 100644 --- a/panda/src/egg/parser.yxx +++ b/panda/src/egg/parser.yxx @@ -397,6 +397,9 @@ texture_body: } else if (cmp_nocase_uh(name, "alpha_file") == 0) { texture->set_alpha_filename(strval); + } else if (cmp_nocase_uh(name, "alpha_file_channel") == 0) { + texture->set_alpha_file_channel((int)value); + } else { eggyywarning("Unsupported texture scalar: " + name); } @@ -940,7 +943,20 @@ group_body: { EggGroup *group = DCAST(EggGroup, egg_stack.back()); 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 '}' { diff --git a/panda/src/egg2pg/characterMaker.cxx b/panda/src/egg2pg/characterMaker.cxx index 13aeaeb00e..b6943be7ba 100644 --- a/panda/src/egg2pg/characterMaker.cxx +++ b/panda/src/egg2pg/characterMaker.cxx @@ -185,7 +185,7 @@ build_joint_hierarchy(EggNode *egg_node, PartGroup *part) { index = _parts.size(); _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 // it. joint->_geom_node = new PandaNode(egg_group->get_name()); @@ -375,7 +375,7 @@ determine_primitive_home(EggPrimitive *egg_primitive) { if (egg_group != (EggGroup *)NULL && 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 flag--this is the normal // case--we'll move the polygon under the character node and // animate it from there explicitly. diff --git a/panda/src/egg2pg/eggLoader.cxx b/panda/src/egg2pg/eggLoader.cxx index 71010db013..80dde693da 100644 --- a/panda/src/egg2pg/eggLoader.cxx +++ b/panda/src/egg2pg/eggLoader.cxx @@ -476,21 +476,24 @@ load_textures() { //////////////////////////////////////////////////////////////////// bool EggLoader:: 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. - int wanted_components = 0; + int wanted_channels = 0; + bool wanted_alpha = false; switch (egg_tex->get_format()) { case EggTexture::F_red: case EggTexture::F_green: case EggTexture::F_blue: case EggTexture::F_alpha: case EggTexture::F_luminance: - wanted_components = 1; + wanted_channels = 1; + wanted_alpha = false; break; case EggTexture::F_luminance_alpha: case EggTexture::F_luminance_alphamask: - wanted_components = 2; + wanted_channels = 2; + wanted_alpha = true; break; case EggTexture::F_rgb: @@ -498,7 +501,8 @@ load_texture(TextureDef &def, const EggTexture *egg_tex) { case EggTexture::F_rgb8: case EggTexture::F_rgb5: case EggTexture::F_rgb332: - wanted_components = 3; + wanted_channels = 3; + wanted_alpha = false; break; case EggTexture::F_rgba: @@ -507,7 +511,8 @@ load_texture(TextureDef &def, const EggTexture *egg_tex) { case EggTexture::F_rgba8: case EggTexture::F_rgba4: case EggTexture::F_rgba5: - wanted_components = 4; + wanted_channels = 4; + wanted_alpha = true; break; case EggTexture::F_unspecified: @@ -515,13 +520,14 @@ load_texture(TextureDef &def, const EggTexture *egg_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(), egg_tex->get_alpha_fullpath(), - wanted_components); + wanted_channels, + egg_tex->get_alpha_file_channel()); } else { tex = TexturePool::load_texture(egg_tex->get_fullpath(), - wanted_components); + wanted_channels); } if (tex == (Texture *)NULL) { 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 // if the bam file is written out. 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()); } @@ -1373,10 +1379,23 @@ make_node(EggGroup *egg_group, PandaNode *parent) { 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. 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; for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) { diff --git a/panda/src/gobj/imageBuffer.cxx b/panda/src/gobj/imageBuffer.cxx index 0fae8ad217..a7b5fa7fb1 100644 --- a/panda/src/gobj/imageBuffer.cxx +++ b/panda/src/gobj/imageBuffer.cxx @@ -16,23 +16,37 @@ // //////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////// -// Includes -//////////////////////////////////////////////////////////////////// -#include +#include "pandabase.h" #include "imageBuffer.h" #include "config_gobj.h" #include "config_util.h" -#include -#include -#include +#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 @@ -85,6 +99,8 @@ write_datagram(BamWriter *, Datagram &me) me.add_string(get_name()); me.add_string(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_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(); + } } diff --git a/panda/src/gobj/imageBuffer.h b/panda/src/gobj/imageBuffer.h index 528ba46eaf..1c88680a31 100644 --- a/panda/src/gobj/imageBuffer.h +++ b/panda/src/gobj/imageBuffer.h @@ -27,10 +27,6 @@ #include "filename.h" #include "namable.h" -//////////////////////////////////////////////////////////////////// -// Defines -//////////////////////////////////////////////////////////////////// - class RenderBuffer; class DisplayRegion; @@ -41,8 +37,8 @@ class DisplayRegion; class EXPCL_PANDA ImageBuffer : public ReferenceCount, public WritableConfigurable, public Namable { PUBLISHED: - ImageBuffer() { } - virtual ~ImageBuffer() { } + ImageBuffer(); + virtual ~ImageBuffer(); public: virtual void config( void ) { WritableConfigurable::config(); } @@ -79,12 +75,24 @@ private: Filename _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: - //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: - void fillin(DatagramIterator& scan, BamReader* manager); + void fillin(DatagramIterator &scan, BamReader *manager); public: diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index fca2a3a486..6def4e5307 100644 --- a/panda/src/gobj/texture.cxx +++ b/panda/src/gobj/texture.cxx @@ -106,22 +106,22 @@ consider_rescale(PNMImage &pnmimage, const string &name) { //////////////////////////////////////////////////////////////////// // Function: consider_downgrade // Description: Reduces the number of channels in the texture, if -// necessary, according to num_components. +// necessary, according to num_channels. //////////////////////////////////////////////////////////////////// static void -consider_downgrade(PNMImage &pnmimage, int num_components, +consider_downgrade(PNMImage &pnmimage, int num_channels, 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 // 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; } gobj_cat.info() << "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 // Access: Published // 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 // than this number. //////////////////////////////////////////////////////////////////// bool Texture:: -read(const Filename &fullpath, int num_components) { +read(const Filename &fullpath, int primary_file_num_channels) { PNMImage image; if (!image.read(fullpath)) { @@ -206,7 +206,11 @@ read(const Filename &fullpath, int num_components) { // Check to see if we need to scale it. 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); } @@ -218,7 +222,7 @@ read(const Filename &fullpath, int num_components) { //////////////////////////////////////////////////////////////////// bool Texture:: read(const Filename &fullpath, const Filename &alpha_fullpath, - int num_components) { + int primary_file_num_channels, int alpha_file_channel) { PNMImage image; if (!image.read(fullpath)) { gobj_cat.error() @@ -263,16 +267,44 @@ read(const Filename &fullpath, const Filename &alpha_fullpath, 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 // grayscale value from the second image. 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); } @@ -697,18 +729,16 @@ make_Texture(const FactoryParams ¶ms) { parse_params(params, scan, manager); - string name; - Filename filename, alpha_filename; - // 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; @@ -722,9 +752,10 @@ make_Texture(const FactoryParams ¶ms) { } else { // This texture does have a filename, so try to load it from disk. if (alpha_filename.empty()) { - me = TexturePool::load_texture(filename, num_components); + me = TexturePool::load_texture(filename, primary_file_num_channels); } 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(); _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(); - } + 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_components == _pbuffer->get_num_components()) { - // Only reset the format if the number of components hasn't - // changed. - _pbuffer->set_format(format); - } + 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. 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. me.add_uint8(_wrapu); @@ -816,7 +838,6 @@ write_datagram(BamWriter *manager, Datagram &me) { me.add_bool(has_pbuffer); if (has_pbuffer) { me.add_uint8(_pbuffer->get_format()); - // I know this has already been written, above. me.add_uint8(_pbuffer->get_num_components()); } } diff --git a/panda/src/gobj/texture.h b/panda/src/gobj/texture.h index 15efbdaf3f..b8885b6e0c 100644 --- a/panda/src/gobj/texture.h +++ b/panda/src/gobj/texture.h @@ -79,9 +79,9 @@ PUBLISHED: bool bAllocateRAM); ~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, - int num_components = 0); + int primary_file_num_channels = 0, int alpha_file_channel = 0); bool write(const Filename &fullpath = "") const; void set_wrapu(WrapMode wrap); diff --git a/panda/src/gobj/texturePool.I b/panda/src/gobj/texturePool.I index 19ba6cb466..4e7f15cb12 100644 --- a/panda/src/gobj/texturePool.I +++ b/panda/src/gobj/texturePool.I @@ -52,8 +52,8 @@ verify_texture(const string &filename) { // file cannot be found, returns NULL. //////////////////////////////////////////////////////////////////// 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:: 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); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/gobj/texturePool.cxx b/panda/src/gobj/texturePool.cxx index 3746bbc1cc..b65f8ecdb3 100644 --- a/panda/src/gobj/texturePool.cxx +++ b/panda/src/gobj/texturePool.cxx @@ -65,7 +65,7 @@ ns_has_texture(const Filename &orig_filename) { // Description: The nonstatic implementation of load_texture(). //////////////////////////////////////////////////////////////////// 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); if (!fake_texture_image.empty()) { @@ -92,7 +92,7 @@ ns_load_texture(const Filename &orig_filename, int num_components) { gobj_cat.info() << "Loading texture " << filename << "\n"; PT(Texture) tex = new Texture; - if (!tex->read(filename, num_components)) { + if (!tex->read(filename, primary_file_num_channels)) { // This texture was not found. gobj_cat.error() << "Unable to read texture " << filename << "\n"; @@ -114,12 +114,13 @@ ns_load_texture(const Filename &orig_filename, int num_components) { Texture *TexturePool:: ns_load_texture(const Filename &orig_filename, const Filename &orig_alpha_filename, - int num_components) { + int primary_file_num_channels, + int alpha_file_channel) { Filename filename(orig_filename); Filename alpha_filename(orig_alpha_filename); 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) { @@ -149,7 +150,8 @@ ns_load_texture(const Filename &orig_filename, << "Loading texture " << filename << " and alpha component " << alpha_filename << endl; 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. gobj_cat.error() << "Unable to read texture " << filename << "\n"; return NULL; diff --git a/panda/src/gobj/texturePool.h b/panda/src/gobj/texturePool.h index 4b9b9c1b8a..2600dcd47c 100644 --- a/panda/src/gobj/texturePool.h +++ b/panda/src/gobj/texturePool.h @@ -41,10 +41,11 @@ PUBLISHED: INLINE static bool has_texture(const string &filename); INLINE static bool verify_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, 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 release_texture(Texture *texture); INLINE static void release_all_textures(); @@ -57,10 +58,11 @@ private: INLINE TexturePool(); 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, 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_release_texture(Texture *texture); void ns_release_all_textures(); diff --git a/panda/src/pgraph/modelNode.I b/panda/src/pgraph/modelNode.I index 523fae891c..b2eb59d80a 100644 --- a/panda/src/pgraph/modelNode.I +++ b/panda/src/pgraph/modelNode.I @@ -26,20 +26,32 @@ INLINE ModelNode:: ModelNode(const string &name) : PandaNode(name) { - _preserve_transform = false; + _preserve_transform = PT_none; } //////////////////////////////////////////////////////////////////// // Function: ModelNode::set_preserve_transform // 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:: -set_preserve_transform(bool preserve_transform) { +set_preserve_transform(ModelNode::PreserveTransform 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 // flag. See set_preserve_transform(). //////////////////////////////////////////////////////////////////// -INLINE bool ModelNode:: +INLINE ModelNode::PreserveTransform ModelNode:: get_preserve_transform() const { return _preserve_transform; } diff --git a/panda/src/pgraph/modelNode.cxx b/panda/src/pgraph/modelNode.cxx index cea656d76f..fed68c9b2c 100644 --- a/panda/src/pgraph/modelNode.cxx +++ b/panda/src/pgraph/modelNode.cxx @@ -62,7 +62,7 @@ safe_to_flatten() const { //////////////////////////////////////////////////////////////////// bool ModelNode:: safe_to_transform() const { - return !_preserve_transform; + return _preserve_transform == PT_none; } //////////////////////////////////////////////////////////////////// @@ -79,7 +79,7 @@ safe_to_transform() const { //////////////////////////////////////////////////////////////////// bool ModelNode:: safe_to_modify_transform() const { - return !_preserve_transform; + return _preserve_transform != PT_local; } //////////////////////////////////////////////////////////////////// @@ -129,7 +129,7 @@ register_with_read_factory() { void ModelNode:: write_datagram(BamWriter *manager, Datagram &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) { PandaNode::fillin(scan, manager); - _preserve_transform = scan.get_bool(); + _preserve_transform = (PreserveTransform)scan.get_uint8(); } diff --git a/panda/src/pgraph/modelNode.h b/panda/src/pgraph/modelNode.h index d90658b431..57b51505a5 100644 --- a/panda/src/pgraph/modelNode.h +++ b/panda/src/pgraph/modelNode.h @@ -52,11 +52,17 @@ public: virtual bool preserve_name() const; 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: - bool _preserve_transform; + PreserveTransform _preserve_transform; public: static void register_with_read_factory(); diff --git a/panda/src/putil/bam.h b/panda/src/putil/bam.h index a185bbb3f5..f66ee6fa0b 100644 --- a/panda/src/putil/bam.h +++ b/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 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 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