mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 02:15:43 -04:00
extend ModelNode::preserve_transform and Texture::alpha_file_channel
This commit is contained in:
parent
a7967b955c
commit
df2a60cfb0
@ -761,26 +761,30 @@ GROUPING ENTRIES
|
||||
|
||||
<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.
|
||||
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.
|
||||
|
||||
<TexList> { boolean-value }
|
||||
<DCS> { 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 <Model>.
|
||||
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 }
|
||||
|
||||
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 }
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -236,8 +236,9 @@ write(ostream &out, int indent_level) const {
|
||||
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) {
|
||||
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
<< "<Scalar> alpha-file-channel { "
|
||||
<< get_alpha_file_channel() << " }\n";
|
||||
}
|
||||
|
||||
if (get_format() != F_unspecified) {
|
||||
indent(out, indent_level + 2)
|
||||
<< "<Scalar> format { " << get_format() << " }\n";
|
||||
|
@ -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:
|
||||
|
@ -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 '}'
|
||||
{
|
||||
|
@ -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 <DCS> flag--this is the normal
|
||||
// case--we'll move the polygon under the character node and
|
||||
// animate it from there explicitly.
|
||||
|
@ -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) {
|
||||
|
@ -16,23 +16,37 @@
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Includes
|
||||
////////////////////////////////////////////////////////////////////
|
||||
#include <pandabase.h>
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "imageBuffer.h"
|
||||
#include "config_gobj.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
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user