mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-29 00:06:44 -04:00
*** empty log message ***
This commit is contained in:
parent
67faa460e7
commit
e2e9663c4c
@ -322,6 +322,21 @@ sorts_less_than(const EggTexture &other, int eq) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggTexture::has_alpha_channel
|
||||
// Access: Public
|
||||
// Description: Given the number of color components (channels) in
|
||||
// the image file as actually read from the disk, return
|
||||
// true if this texture seems to have an alpha channel
|
||||
// or not. This depends on the EggTexture's format as
|
||||
// well as the number of channels.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool EggTexture::
|
||||
has_alpha_channel(int num_components) const {
|
||||
return (num_components == 2 || num_components == 4 ||
|
||||
(num_components == 1 && _format == F_alpha));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggTexture::string_format
|
||||
// Access: Public
|
||||
|
@ -44,6 +44,8 @@ public:
|
||||
bool is_equivalent_to(const EggTexture &other, int eq) const;
|
||||
bool sorts_less_than(const EggTexture &other, int eq) const;
|
||||
|
||||
bool has_alpha_channel(int num_components) const;
|
||||
|
||||
enum Format {
|
||||
F_unspecified,
|
||||
F_rgba, F_rgba12, F_rgba8, F_rgba4, F_rgba5,
|
||||
|
@ -871,8 +871,7 @@ setup_bucket(BuilderBucket &bucket, NamedNode *parent,
|
||||
Texture *tex = def._texture->get_texture();
|
||||
nassertv(tex != (Texture *)NULL);
|
||||
int num_components = tex->_pbuffer->get_num_components();
|
||||
if (num_components == 2 || num_components == 4 ||
|
||||
(num_components == 1 && egg_tex->get_format() == EggTexture::F_alpha)) {
|
||||
if (egg_tex->has_alpha_channel(num_components)) {
|
||||
implicit_alpha = true;
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,25 @@ INLINE GlobPattern::
|
||||
GlobPattern(const string &pattern) : _pattern(pattern) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GlobPattern::Copy Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE GlobPattern::
|
||||
GlobPattern(const GlobPattern ©) : _pattern(copy._pattern) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GlobPattern::Copy Assignment Operator
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void GlobPattern::
|
||||
operator = (const GlobPattern ©) {
|
||||
_pattern = copy._pattern;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GlobPattern::set_pattern
|
||||
// Access: Public
|
||||
@ -47,3 +66,12 @@ matches(const string &candidate) const {
|
||||
candidate.begin(), candidate.end());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GlobPattern::output
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void GlobPattern::
|
||||
output(ostream &out) const {
|
||||
out << _pattern;
|
||||
}
|
||||
|
@ -26,11 +26,15 @@
|
||||
class EXPCL_PANDA GlobPattern {
|
||||
public:
|
||||
INLINE GlobPattern(const string &pattern = string());
|
||||
INLINE GlobPattern(const GlobPattern ©);
|
||||
INLINE void operator = (const GlobPattern ©);
|
||||
|
||||
INLINE void set_pattern(const string &pattern);
|
||||
INLINE const string &get_pattern() const;
|
||||
|
||||
INLINE bool matches(const string &candidate) const;
|
||||
|
||||
INLINE void output(ostream &out) const;
|
||||
|
||||
private:
|
||||
bool matches_substr(string::const_iterator pi,
|
||||
@ -45,6 +49,12 @@ private:
|
||||
string _pattern;
|
||||
};
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const GlobPattern &glob) {
|
||||
glob.output(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
#include "globPattern.I"
|
||||
|
||||
#endif
|
||||
|
@ -1,4 +1,4 @@
|
||||
#begin bin_target
|
||||
#begin noinst_bin_target
|
||||
#define TARGET egg-palettize
|
||||
#define LOCAL_LIBS \
|
||||
eggbase progbase
|
||||
@ -10,11 +10,14 @@
|
||||
#define SOURCES \
|
||||
attribFile.cxx attribFile.h config_egg_palettize.cxx \
|
||||
eggPalettize.cxx eggPalettize.h \
|
||||
imageFile.cxx imageFile.h palette.cxx palette.h sourceEgg.cxx \
|
||||
sourceEgg.h string_utils.cxx string_utils.h pTexture.cxx pTexture.h \
|
||||
userAttribLine.cxx userAttribLine.h
|
||||
imageFile.cxx imageFile.h palette.cxx palette.h paletteGroup.cxx \
|
||||
paletteGroup.h pTexture.cxx pTexture.h sourceEgg.cxx \
|
||||
sourceEgg.h string_utils.cxx string_utils.h \
|
||||
textureEggRef.cxx textureEggRef.h textureOmitReason.h \
|
||||
texturePacking.cxx \
|
||||
texturePacking.h userAttribLine.cxx userAttribLine.h
|
||||
|
||||
#define INSTALL_HEADERS
|
||||
|
||||
#end bin_target
|
||||
#end noinst_bin_target
|
||||
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include "eggPalettize.h"
|
||||
#include "string_utils.h"
|
||||
#include "pTexture.h"
|
||||
#include "texturePacking.h"
|
||||
#include "paletteGroup.h"
|
||||
#include "palette.h"
|
||||
#include "sourceEgg.h"
|
||||
|
||||
@ -30,7 +32,6 @@ AttribFile(const Filename &filename) {
|
||||
_optimal = false;
|
||||
_txa_needs_rewrite = false;
|
||||
|
||||
_palette_prefix = _name + "-palette.";
|
||||
_pal_xsize = 512;
|
||||
_pal_ysize = 512;
|
||||
_default_margin = 2;
|
||||
@ -87,7 +88,7 @@ release_lock() {
|
||||
}
|
||||
|
||||
bool AttribFile::
|
||||
read() {
|
||||
read(bool force_redo_all) {
|
||||
bool okflag = true;
|
||||
|
||||
okflag = read_txa(_txa_fstrm);
|
||||
@ -102,7 +103,7 @@ read() {
|
||||
return false;
|
||||
}
|
||||
|
||||
okflag = read_pi(infile);
|
||||
okflag = read_pi(infile, force_redo_all);
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,8 +157,80 @@ update_params(EggPalettize *prog) {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AttribFile::get_group
|
||||
// Access: Public
|
||||
// Description: Returns a pointer to the PaletteGroup object with the
|
||||
// given name. If there is not yet any such
|
||||
// PaletteGroup, creates one.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PaletteGroup *AttribFile::
|
||||
get_group(const string &group_name) {
|
||||
Groups::iterator gi;
|
||||
gi = _groups.find(group_name);
|
||||
if (gi != _groups.end()) {
|
||||
return (*gi).second;
|
||||
}
|
||||
|
||||
PaletteGroup *new_group = new PaletteGroup(group_name);
|
||||
_groups[group_name] = new_group;
|
||||
return new_group;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AttribFile::get_default_group
|
||||
// Access: Public
|
||||
// Description: Returns the PaletteGroup that should be associated
|
||||
// with any textures or egg files not explicitly placed
|
||||
// in a different group.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PaletteGroup *AttribFile::
|
||||
get_default_group() {
|
||||
return get_group(_name);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AttribFile::get_egg_group_requests
|
||||
// Access: Public
|
||||
// Description: Checks all of the known egg filenames against the egg
|
||||
// files named in the .txa file, looking to see which
|
||||
// egg files as assigned to which groups.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void AttribFile::
|
||||
get_req_sizes() {
|
||||
get_egg_group_requests() {
|
||||
Eggs::iterator ei;
|
||||
for (ei = _eggs.begin(); ei != _eggs.end(); ++ei) {
|
||||
SourceEgg *egg = (*ei).second;
|
||||
UserLines::const_iterator ui;
|
||||
|
||||
bool matched = false;
|
||||
for (ui = _user_lines.begin();
|
||||
ui != _user_lines.end() && !matched;
|
||||
++ui) {
|
||||
matched = (*ui)->get_group_request(egg);
|
||||
}
|
||||
|
||||
if (matched) {
|
||||
egg->set_matched_anything(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Now go back and make sure that all textures are assigned to
|
||||
// *something*.
|
||||
for (ei = _eggs.begin(); ei != _eggs.end(); ++ei) {
|
||||
SourceEgg *egg = (*ei).second;
|
||||
egg->all_textures_assigned();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AttribFile::get_size_requests
|
||||
// Access: Public
|
||||
// Description: Determines the size/scaling requested for each
|
||||
// texture by scanning the .txa file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void AttribFile::
|
||||
get_size_requests() {
|
||||
PTextures::iterator ti;
|
||||
for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
|
||||
PTexture *tex = (*ti).second;
|
||||
@ -170,7 +243,7 @@ get_req_sizes() {
|
||||
for (ui = _user_lines.begin();
|
||||
ui != _user_lines.end() && !matched;
|
||||
++ui) {
|
||||
matched = (*ui)->match_texture(tex, margin);
|
||||
matched = (*ui)->get_size_request(tex, margin);
|
||||
}
|
||||
|
||||
if (matched) {
|
||||
@ -185,11 +258,11 @@ get_req_sizes() {
|
||||
void AttribFile::
|
||||
update_texture_flags() {
|
||||
// First, clear all the flags.
|
||||
PTextures::iterator ti;
|
||||
for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
|
||||
PTexture *tex = (*ti).second;
|
||||
tex->set_unused(true);
|
||||
tex->set_uses_alpha(false);
|
||||
Packing::iterator pi;
|
||||
for (pi = _packing.begin(); pi != _packing.end(); ++pi) {
|
||||
TexturePacking *packing = (*pi);
|
||||
packing->set_unused(true);
|
||||
packing->set_uses_alpha(false);
|
||||
}
|
||||
|
||||
// Then, for each egg file, mark all the textures it's known to be
|
||||
@ -203,12 +276,12 @@ update_texture_flags() {
|
||||
// Now go back through and omit any unused textures. This is also a
|
||||
// fine time to mark the textures' original packing state, so we can
|
||||
// check later to see if they've been repacked elsewhere.
|
||||
for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
|
||||
PTexture *tex = (*ti).second;
|
||||
tex->record_orig_state();
|
||||
for (pi = _packing.begin(); pi != _packing.end(); ++pi) {
|
||||
TexturePacking *packing = (*pi);
|
||||
packing->record_orig_state();
|
||||
|
||||
if (tex->unused()) {
|
||||
tex->set_omit(PTexture::OR_unused);
|
||||
if (packing->unused()) {
|
||||
packing->set_omit(OR_unused);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -218,31 +291,25 @@ update_texture_flags() {
|
||||
// algorithm can manage.
|
||||
void AttribFile::
|
||||
repack_all_textures() {
|
||||
// First, delete all the existing palettes.
|
||||
Palettes::iterator pi;
|
||||
for (pi = _palettes.begin(); pi != _palettes.end(); ++pi) {
|
||||
// Remove the old palette file?
|
||||
if (_aggressively_clean_mapdir &&
|
||||
!(*pi)->get_filename().empty()) {
|
||||
if (access((*pi)->get_filename().c_str(), F_OK) == 0) {
|
||||
nout << "Deleting " << (*pi)->get_filename() << "\n";
|
||||
unlink((*pi)->get_filename().c_str());
|
||||
}
|
||||
// First, empty all the existing palette groups.
|
||||
Groups::iterator gi;
|
||||
for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
|
||||
PaletteGroup *group = (*gi).second;
|
||||
if (_aggressively_clean_mapdir) {
|
||||
group->remove_palette_files();
|
||||
}
|
||||
|
||||
delete (*pi);
|
||||
group->clear_palettes();
|
||||
}
|
||||
_palettes.clear();
|
||||
|
||||
// Reorder the textures in descending order by height and width for
|
||||
// optimal packing.
|
||||
vector<PTexture *> textures;
|
||||
vector<TexturePacking *> textures;
|
||||
get_eligible_textures(textures);
|
||||
|
||||
// Now pack all the textures. This will create new palettes.
|
||||
vector<PTexture *>::iterator ti;
|
||||
vector<TexturePacking *>::iterator ti;
|
||||
for (ti = textures.begin(); ti != textures.end(); ++ti) {
|
||||
pack_texture(*ti);
|
||||
(*ti)->pack();
|
||||
}
|
||||
|
||||
_optimal = true;
|
||||
@ -254,22 +321,20 @@ repack_all_textures() {
|
||||
// palette.
|
||||
void AttribFile::
|
||||
repack_some_textures() {
|
||||
bool empty_before = _palettes.empty();
|
||||
bool empty_before = _groups.empty();
|
||||
bool any_added = false;
|
||||
|
||||
// Reorder the textures in descending order by height and width for
|
||||
// optimal packing.
|
||||
vector<PTexture *> textures;
|
||||
vector<TexturePacking *> textures;
|
||||
get_eligible_textures(textures);
|
||||
|
||||
// Now pack whatever textures are currently unpacked.
|
||||
vector<PTexture *>::iterator ti;
|
||||
vector<TexturePacking *>::iterator ti;
|
||||
for (ti = textures.begin(); ti != textures.end(); ++ti) {
|
||||
PTexture *tex = (*ti);
|
||||
if (!tex->is_packed()) {
|
||||
if (pack_texture(tex)) {
|
||||
any_added = true;
|
||||
}
|
||||
TexturePacking *packing = (*ti);
|
||||
if (packing->pack()) {
|
||||
any_added = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -278,17 +343,17 @@ repack_some_textures() {
|
||||
|
||||
void AttribFile::
|
||||
optimal_resize() {
|
||||
Palettes::iterator pi;
|
||||
for (pi = _palettes.begin(); pi != _palettes.end(); ++pi) {
|
||||
(*pi)->optimal_resize();
|
||||
Groups::iterator gi;
|
||||
for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
|
||||
(*gi).second->optimal_resize();
|
||||
}
|
||||
}
|
||||
|
||||
void AttribFile::
|
||||
finalize_palettes() {
|
||||
Palettes::iterator pi;
|
||||
for (pi = _palettes.begin(); pi != _palettes.end(); ++pi) {
|
||||
(*pi)->finalize_palette();
|
||||
Groups::iterator gi;
|
||||
for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
|
||||
(*gi).second->finalize_palettes();
|
||||
}
|
||||
}
|
||||
|
||||
@ -310,112 +375,41 @@ remove_unused_lines() {
|
||||
_user_lines.erase(write, _user_lines.end());
|
||||
}
|
||||
|
||||
// Checks that each texture that wants packing has been packed, that
|
||||
// no textures that don't need packing have been packed, and that all
|
||||
// textures are packed at their correct sizes. Returns true if no
|
||||
// changes need to be made, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AttribFile::prepare_repack
|
||||
// Access: Public
|
||||
// Description: Checks if any texture needs to be repacked into a
|
||||
// different location on the palette (for instance,
|
||||
// because it has changed size). If so, unpacks it and
|
||||
// returns true; otherwise, leaves it alone and returns
|
||||
// false.
|
||||
//
|
||||
// If force_optimal is true, returns true if anything
|
||||
// has changed at all that would result in a suboptimal
|
||||
// palette.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool AttribFile::
|
||||
check_packing(bool force_optimal) {
|
||||
bool all_ok = true;
|
||||
prepare_repack(bool force_optimal) {
|
||||
bool needs_repack = false;
|
||||
|
||||
PTextures::iterator ti;
|
||||
for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
|
||||
PTexture *texture = (*ti).second;
|
||||
|
||||
if (texture->get_omit() == PTexture::OR_none) {
|
||||
// Here's a texture that thinks it wants to be packed. Does it?
|
||||
int xsize, ysize;
|
||||
if (!texture->get_req(xsize, ysize)) {
|
||||
// If we don't know the texture's size, we can't place it.
|
||||
nout << "Warning! Can't determine size of " << texture->get_name()
|
||||
<< "\n";
|
||||
texture->set_omit(PTexture::OR_unknown);
|
||||
|
||||
} else if ((xsize > _pal_xsize || ysize > _pal_ysize) ||
|
||||
(xsize == _pal_xsize && ysize == _pal_ysize)) {
|
||||
// If the texture is too big for the palette (or exactly fills the
|
||||
// palette), we can't place it.
|
||||
texture->set_omit(PTexture::OR_size);
|
||||
|
||||
} else {
|
||||
// Ok, this texture really does want to be packed. Is it?
|
||||
int px, py, m;
|
||||
if (texture->get_packed_size(px, py, m)) {
|
||||
// The texture is packed. Does it have the right size?
|
||||
if (px != xsize || py != ysize) {
|
||||
// Oops, we'll have to repack it.
|
||||
unpack_texture(texture);
|
||||
_optimal = false;
|
||||
all_ok = false;
|
||||
}
|
||||
if (m != texture->get_margin()) {
|
||||
// The margin has changed, although not the size. We
|
||||
// won't have to repack it, but we do need to update it.
|
||||
texture->set_changed(true);
|
||||
}
|
||||
} else {
|
||||
// The texture isn't packed. Need to pack it.
|
||||
all_ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (texture->get_omit() != PTexture::OR_none) {
|
||||
// Here's a texture that doesn't want to be packed. Is it?
|
||||
if (unpack_texture(texture)) {
|
||||
// It was! Not any more.
|
||||
_optimal = false;
|
||||
all_ok = false;
|
||||
}
|
||||
Packing::iterator pi;
|
||||
for (pi = _packing.begin(); pi != _packing.end(); ++pi) {
|
||||
TexturePacking *packing = (*pi);
|
||||
if (packing->prepare_repack(_optimal)) {
|
||||
needs_repack = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (force_optimal && !_optimal) {
|
||||
// If the user wants to insist on an optimal packing, we'll have
|
||||
// to give it to him.
|
||||
all_ok = false;
|
||||
needs_repack = true;
|
||||
}
|
||||
|
||||
return all_ok;
|
||||
return needs_repack;
|
||||
}
|
||||
|
||||
|
||||
bool AttribFile::
|
||||
pack_texture(PTexture *texture) {
|
||||
// Now try to place it in each of our existing palettes.
|
||||
Palettes::iterator pi;
|
||||
for (pi = _palettes.begin(); pi != _palettes.end(); ++pi) {
|
||||
if ((*pi)->pack_texture(texture)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// It didn't place anywhere; create a new palette for it.
|
||||
Palette *palette =
|
||||
new Palette(_palettes.size() + 1, _pal_xsize, _pal_ysize, 0, this);
|
||||
if (!palette->pack_texture(texture)) {
|
||||
// Hmm, it didn't fit on an empty palette. Must be too big.
|
||||
texture->set_omit(PTexture::OR_size);
|
||||
delete palette;
|
||||
return false;
|
||||
}
|
||||
_palettes.push_back(palette);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AttribFile::
|
||||
unpack_texture(PTexture *texture) {
|
||||
if (texture->is_packed()) {
|
||||
bool unpacked = texture->get_palette()->unpack_texture(texture);
|
||||
assert(unpacked);
|
||||
return true;
|
||||
}
|
||||
|
||||
// It wasn't packed.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Updates the timestamp on each egg file that will need to be
|
||||
// rebuilt, so that a future make process will pick it up. This is
|
||||
// only necessary to update egg files that may not have been included
|
||||
@ -453,22 +447,23 @@ get_texture(const string &name) {
|
||||
}
|
||||
|
||||
void AttribFile::
|
||||
get_eligible_textures(vector<PTexture *> &textures) {
|
||||
get_eligible_textures(vector<TexturePacking *> &textures) {
|
||||
// First, copy the texture pointers into this map structure to sort
|
||||
// them in descending order by size. This is a 2-d map such that
|
||||
// each map[ysize][xsize] is a set of texture pointers.
|
||||
typedef map<int, map<int, set<PTexture *> > > TexBySize;
|
||||
typedef map<int, map<int, set<TexturePacking *> > > TexBySize;
|
||||
TexBySize tex_by_size;
|
||||
int num_textures = 0;
|
||||
|
||||
PTextures::iterator ti;
|
||||
for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
|
||||
PTexture *texture = (*ti).second;
|
||||
Packing::iterator pi;
|
||||
for (pi = _packing.begin(); pi != _packing.end(); ++pi) {
|
||||
TexturePacking *packing = (*pi);
|
||||
PTexture *texture = packing->get_texture();
|
||||
|
||||
if (texture->get_omit() == PTexture::OR_none) {
|
||||
if (packing->get_omit() == OR_none) {
|
||||
int xsize, ysize;
|
||||
if (texture->get_req(xsize, ysize)) {
|
||||
tex_by_size[-ysize][-xsize].insert(texture);
|
||||
tex_by_size[-ysize][-xsize].insert(packing);
|
||||
num_textures++;
|
||||
}
|
||||
}
|
||||
@ -481,9 +476,9 @@ get_eligible_textures(vector<PTexture *> &textures) {
|
||||
|
||||
TexBySize::const_iterator t1;
|
||||
for (t1 = tex_by_size.begin(); t1 != tex_by_size.end(); ++t1) {
|
||||
map<int, set<PTexture *> >::const_iterator t2;
|
||||
map<int, set<TexturePacking *> >::const_iterator t2;
|
||||
for (t2 = (*t1).second.begin(); t2 != (*t1).second.end(); ++t2) {
|
||||
set<PTexture *>::const_iterator t3;
|
||||
set<TexturePacking *>::const_iterator t3;
|
||||
for (t3 = (*t2).second.begin(); t3 != (*t2).second.end(); ++t3) {
|
||||
textures.push_back(*t3);
|
||||
}
|
||||
@ -499,7 +494,7 @@ get_egg(Filename name) {
|
||||
return (*ei).second;
|
||||
}
|
||||
|
||||
SourceEgg *egg = new SourceEgg();
|
||||
SourceEgg *egg = new SourceEgg(this);
|
||||
egg->resolve_egg_filename(name);
|
||||
egg->set_egg_filename(name);
|
||||
_eggs[name] = egg;
|
||||
@ -510,18 +505,10 @@ bool AttribFile::
|
||||
generate_palette_images() {
|
||||
bool okflag = true;
|
||||
|
||||
Palettes::iterator pi;
|
||||
for (pi = _palettes.begin(); pi != _palettes.end(); ++pi) {
|
||||
Palette *palette = (*pi);
|
||||
if (palette->new_palette()) {
|
||||
// If the palette is a new palette, we'll have to generate a new
|
||||
// image from scratch.
|
||||
okflag = palette->generate_image() && okflag;
|
||||
} else {
|
||||
// Otherwise, we can probably get by with just updating
|
||||
// whichever images, if any, have changed.
|
||||
okflag = palette->refresh_image() && okflag;
|
||||
}
|
||||
Groups::iterator gi;
|
||||
for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
|
||||
PaletteGroup *group = (*gi).second;
|
||||
okflag = group->generate_palette_images() && okflag;
|
||||
}
|
||||
|
||||
return okflag;
|
||||
@ -531,23 +518,24 @@ bool AttribFile::
|
||||
transfer_unplaced_images(bool force_redo_all) {
|
||||
bool okflag = true;
|
||||
|
||||
PTextures::iterator ti;
|
||||
for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
|
||||
PTexture *texture = (*ti).second;
|
||||
Packing::iterator pi;
|
||||
for (pi = _packing.begin(); pi != _packing.end(); ++pi) {
|
||||
TexturePacking *packing = (*pi);
|
||||
PTexture *texture = packing->get_texture();
|
||||
|
||||
if (texture->get_omit() != PTexture::OR_none &&
|
||||
texture->get_omit() != PTexture::OR_unused) {
|
||||
if (packing->get_omit() != OR_none &&
|
||||
packing->get_omit() != OR_unused) {
|
||||
// Here's a texture that needs to be moved to our mapdir. But
|
||||
// maybe it's already there and hasn't changed recently.
|
||||
if (force_redo_all || texture->needs_refresh()) {
|
||||
if (force_redo_all || packing->needs_refresh()) {
|
||||
// Nope, needs to be updated.
|
||||
okflag = texture->transfer() && okflag;
|
||||
}
|
||||
} else {
|
||||
if (_aggressively_clean_mapdir) {
|
||||
if (access(texture->get_filename().c_str(), F_OK) == 0) {
|
||||
if (_aggressively_clean_mapdir && texture->is_unused()) {
|
||||
if (texture->get_filename().exists()) {
|
||||
nout << "Deleting " << texture->get_filename() << "\n";
|
||||
unlink(texture->get_filename().c_str());
|
||||
texture->get_filename().unlink();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -560,6 +548,7 @@ transfer_unplaced_images(bool force_redo_all) {
|
||||
void AttribFile::
|
||||
check_dup_textures(map<string, PTexture *> &textures,
|
||||
map<string, int> &dup_textures) const {
|
||||
/*
|
||||
PTextures::const_iterator ti;
|
||||
for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
|
||||
PTexture *texture = (*ti).second;
|
||||
@ -623,14 +612,16 @@ check_dup_textures(map<string, PTexture *> &textures,
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void AttribFile::
|
||||
collect_statistics(int &num_textures, int &num_placed, int &num_palettes,
|
||||
int &orig_size, int &resized_size,
|
||||
int &palette_size, int &unplaced_size) const {
|
||||
/*
|
||||
num_textures = _textures.size();
|
||||
num_palettes = _palettes.size();
|
||||
num_palettes = 0; //_palettes.size();
|
||||
num_placed = 0;
|
||||
orig_size = 0;
|
||||
resized_size = 0;
|
||||
@ -641,10 +632,10 @@ collect_statistics(int &num_textures, int &num_placed, int &num_palettes,
|
||||
for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
|
||||
PTexture *texture = (*ti).second;
|
||||
|
||||
int xsize, ysize;
|
||||
int xsize, ysize, zsize;
|
||||
int rxsize, rysize;
|
||||
int rsize = 0;
|
||||
if (texture->get_size(xsize, ysize) &&
|
||||
if (texture->get_size(xsize, ysize, zsize) &&
|
||||
texture->get_last_req(rxsize, rysize)) {
|
||||
orig_size += xsize * ysize;
|
||||
resized_size += rxsize * rysize;
|
||||
@ -662,11 +653,12 @@ collect_statistics(int &num_textures, int &num_placed, int &num_palettes,
|
||||
for (pi = _palettes.begin(); pi != _palettes.end(); ++pi) {
|
||||
Palette *palette = (*pi);
|
||||
if (palette->get_num_textures() > 1) {
|
||||
int xsize, ysize;
|
||||
palette->get_size(xsize, ysize);
|
||||
int xsize, ysize, zsize;
|
||||
palette->get_size(xsize, ysize, zsize);
|
||||
palette_size += xsize * ysize;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
@ -695,7 +687,7 @@ read_txa(istream &infile) {
|
||||
}
|
||||
|
||||
bool AttribFile::
|
||||
read_pi(istream &infile) {
|
||||
read_pi(istream &infile, bool force_redo_all) {
|
||||
string line;
|
||||
|
||||
getline(infile, line);
|
||||
@ -734,7 +726,7 @@ read_pi(istream &infile) {
|
||||
okflag = parse_pathname(words, infile, line, line_num);
|
||||
|
||||
} else if (words[0] == "egg") {
|
||||
okflag = parse_egg(words, infile, line, line_num);
|
||||
okflag = parse_egg(words, infile, line, line_num, force_redo_all);
|
||||
|
||||
} else if (words[0] == "palette") {
|
||||
okflag = parse_palette(words, infile, line, line_num);
|
||||
@ -776,6 +768,8 @@ write_txa(ostream &out) const {
|
||||
|
||||
bool AttribFile::
|
||||
write_pi(ostream &out) const {
|
||||
bool any_surprises = false;
|
||||
|
||||
out <<
|
||||
"# This file was generated by egg-palettize. Edit it at your own peril.\n";
|
||||
|
||||
@ -802,19 +796,21 @@ write_pi(ostream &out) const {
|
||||
|
||||
Eggs::const_iterator ei;
|
||||
for (ei = _eggs.begin(); ei != _eggs.end(); ++ei) {
|
||||
SourceEgg *egg = (*ei).second;
|
||||
out << "\n";
|
||||
(*ei).second->write_pi(out);
|
||||
egg->write_pi(out);
|
||||
any_surprises = any_surprises || !egg->matched_anything();
|
||||
}
|
||||
|
||||
Palettes::const_iterator pi;
|
||||
for (pi = _palettes.begin(); pi != _palettes.end(); ++pi) {
|
||||
out << "\n";
|
||||
(*pi)->write(out);
|
||||
Groups::const_iterator gi;
|
||||
for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
|
||||
(*gi).second->write(out);
|
||||
}
|
||||
|
||||
out << "\n";
|
||||
for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
|
||||
(*ti).second->write_unplaced(out);
|
||||
Packing::const_iterator pi;
|
||||
for (pi = _packing.begin(); pi != _packing.end(); ++pi) {
|
||||
(*pi)->write_unplaced(out);
|
||||
}
|
||||
|
||||
// Sort textures in descending order by scale percent.
|
||||
@ -826,8 +822,6 @@ write_pi(ostream &out) const {
|
||||
texture));
|
||||
}
|
||||
|
||||
bool any_surprises = false;
|
||||
|
||||
out << "\ntextures\n";
|
||||
SortPTextures::const_iterator sti;
|
||||
for (sti = sort_textures.begin(); sti != sort_textures.end(); ++sti) {
|
||||
@ -837,8 +831,8 @@ write_pi(ostream &out) const {
|
||||
}
|
||||
|
||||
if (any_surprises) {
|
||||
// Some textures didn't match any commands; they're "surprise"
|
||||
// textures.
|
||||
// Some textures or egg files didn't match any commands; they're
|
||||
// "surprises".
|
||||
out << "\nsurprises\n";
|
||||
for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
|
||||
PTexture *texture = (*ti).second;
|
||||
@ -846,6 +840,13 @@ write_pi(ostream &out) const {
|
||||
out << " " << texture->get_name() << "\n";
|
||||
}
|
||||
}
|
||||
Eggs::const_iterator ei;
|
||||
for (ei = _eggs.begin(); ei != _eggs.end(); ++ei) {
|
||||
SourceEgg *egg = (*ei).second;
|
||||
if (!egg->matched_anything()) {
|
||||
out << " " << egg->get_egg_filename().get_basename() << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!out) {
|
||||
@ -873,14 +874,6 @@ parse_params(const vector<string> &words, istream &infile,
|
||||
|
||||
if (param == "map_directory") {
|
||||
_map_dirname = value;
|
||||
|
||||
// These are all deprecated.
|
||||
} else if (param == "converted_directory") {
|
||||
} else if (param == "convert_extension") {
|
||||
} else if (param == "convert_command") {
|
||||
} else if (param == "palette_prefix") {
|
||||
} else if (param == "map_prefix") {
|
||||
|
||||
} else if (param == "pal_xsize") {
|
||||
_pal_xsize = atoi(value.c_str());
|
||||
} else if (param == "pal_ysize") {
|
||||
@ -944,8 +937,9 @@ parse_texture(const vector<string> &words, istream &infile,
|
||||
while (kw < (int)twords.size()) {
|
||||
if (kw + 3 <= (int)twords.size() && twords[kw] == "orig") {
|
||||
texture->set_size(atoi(twords[kw + 1].c_str()),
|
||||
atoi(twords[kw + 2].c_str()));
|
||||
kw += 3;
|
||||
atoi(twords[kw + 2].c_str()),
|
||||
atoi(twords[kw + 3].c_str()));
|
||||
kw += 4;
|
||||
|
||||
} else if (kw + 3 <= (int)twords.size() && twords[kw] == "new") {
|
||||
texture->set_last_req(atoi(twords[kw + 1].c_str()),
|
||||
@ -1014,7 +1008,7 @@ parse_pathname(const vector<string> &words, istream &infile,
|
||||
|
||||
bool AttribFile::
|
||||
parse_egg(const vector<string> &words, istream &infile,
|
||||
string &line, int &line_num) {
|
||||
string &line, int &line_num, bool force_redo_all) {
|
||||
if (words.size() != 2) {
|
||||
nout << "Egg filename expected.\n";
|
||||
return false;
|
||||
@ -1035,10 +1029,20 @@ parse_egg(const vector<string> &words, istream &infile,
|
||||
string name = twords[0];
|
||||
bool repeats = false;
|
||||
bool alpha = false;
|
||||
PaletteGroup *group = (PaletteGroup *)NULL;
|
||||
|
||||
int kw = 1;
|
||||
while (kw < (int)twords.size()) {
|
||||
if (twords[kw] == "repeats") {
|
||||
if (twords[kw] == "in") {
|
||||
kw++;
|
||||
if (kw >= (int)twords.size()) {
|
||||
nout << "Expected group name\n";
|
||||
return false;
|
||||
}
|
||||
group = get_group(twords[kw]);
|
||||
kw++;
|
||||
|
||||
} else if (twords[kw] == "repeats") {
|
||||
repeats = true;
|
||||
kw++;
|
||||
|
||||
@ -1052,7 +1056,14 @@ parse_egg(const vector<string> &words, istream &infile,
|
||||
}
|
||||
}
|
||||
|
||||
egg->add_texture(get_texture(name), repeats, alpha);
|
||||
PTexture *texture = get_texture(name);
|
||||
TexturePacking *packing = (TexturePacking *)NULL;
|
||||
|
||||
if (!force_redo_all) {
|
||||
packing = texture->add_to_group(group);
|
||||
}
|
||||
|
||||
egg->add_texture(texture, packing, repeats, alpha);
|
||||
|
||||
getline(infile, line);
|
||||
line = trim_right(line);
|
||||
@ -1063,26 +1074,32 @@ parse_egg(const vector<string> &words, istream &infile,
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool AttribFile::
|
||||
parse_palette(const vector<string> &words, istream &infile,
|
||||
string &line, int &line_num) {
|
||||
if (words.size() != 6) {
|
||||
nout << "Palette filename, size, and number of components expected.\n";
|
||||
if (words.size() != 8) {
|
||||
nout << "Palette filename, group, size, and number of components expected.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
string filename = words[1];
|
||||
if (!(words[2] == "size")) {
|
||||
if (!(words[2] == "in")) {
|
||||
nout << "Expected keyword 'in'\n";
|
||||
return false;
|
||||
}
|
||||
PaletteGroup *group = get_group(words[3]);
|
||||
|
||||
if (!(words[4] == "size")) {
|
||||
nout << "Expected keyword 'size'\n";
|
||||
return false;
|
||||
}
|
||||
int xsize = atoi(words[3].c_str());
|
||||
int ysize = atoi(words[4].c_str());
|
||||
int components = atoi(words[5].c_str());
|
||||
int xsize = atoi(words[5].c_str());
|
||||
int ysize = atoi(words[6].c_str());
|
||||
int components = atoi(words[7].c_str());
|
||||
|
||||
Palette *palette = new Palette(filename, xsize, ysize, components, this);
|
||||
_palettes.push_back(palette);
|
||||
Palette *palette =
|
||||
new Palette(filename, group, xsize, ysize, components, this);
|
||||
group->add_palette(palette);
|
||||
|
||||
getline(infile, line);
|
||||
line = trim_right(line);
|
||||
@ -1095,6 +1112,7 @@ parse_palette(const vector<string> &words, istream &infile,
|
||||
}
|
||||
|
||||
PTexture *texture = get_texture(twords[0]);
|
||||
TexturePacking *packing = texture->add_to_group(group);
|
||||
|
||||
if (!(twords[1] == "at")) {
|
||||
nout << "Expected keyword 'at'\n";
|
||||
@ -1115,8 +1133,8 @@ parse_palette(const vector<string> &words, istream &infile,
|
||||
return false;
|
||||
}
|
||||
int margin = atoi(twords[8].c_str());
|
||||
|
||||
palette->place_texture_at(texture, left, top, xsize, ysize, margin);
|
||||
|
||||
palette->place_texture_at(packing, left, top, xsize, ysize, margin);
|
||||
|
||||
getline(infile, line);
|
||||
line = trim_right(line);
|
||||
@ -1131,34 +1149,40 @@ parse_palette(const vector<string> &words, istream &infile,
|
||||
bool AttribFile::
|
||||
parse_unplaced(const vector<string> &words, istream &infile,
|
||||
string &line, int &line_num) {
|
||||
if (words.size() != 4) {
|
||||
if (words.size() != 6) {
|
||||
nout << "Unplaced texture description expected.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
PTexture *texture = get_texture(words[1]);
|
||||
|
||||
if (!(words[2] == "because")) {
|
||||
if (!(words[2] == "in")) {
|
||||
nout << "Expected keyword 'in'\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
PaletteGroup *group = get_group(words[3]);
|
||||
TexturePacking *packing = texture->add_to_group(group);
|
||||
|
||||
if (!(words[4] == "because")) {
|
||||
nout << "Expected keyword 'because'\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (words[3] == "size") {
|
||||
texture->set_omit(PTexture::OR_size);
|
||||
} else if (words[3] == "repeats") {
|
||||
texture->set_omit(PTexture::OR_repeats);
|
||||
} else if (words[3] == "omitted") {
|
||||
texture->set_omit(PTexture::OR_omitted);
|
||||
} else if (words[3] == "unused") {
|
||||
texture->set_omit(PTexture::OR_unused);
|
||||
} else if (words[3] == "unknown") {
|
||||
texture->set_omit(PTexture::OR_unknown);
|
||||
} else if (words[3] == "solitary") {
|
||||
texture->set_omit(PTexture::OR_solitary);
|
||||
} else if (words[3] == "cmdline") {
|
||||
texture->set_omit(PTexture::OR_cmdline);
|
||||
if (words[5] == "size") {
|
||||
packing->set_omit(OR_size);
|
||||
} else if (words[5] == "repeats") {
|
||||
packing->set_omit(OR_repeats);
|
||||
} else if (words[5] == "omitted") {
|
||||
packing->set_omit(OR_omitted);
|
||||
} else if (words[5] == "unused") {
|
||||
packing->set_omit(OR_unused);
|
||||
} else if (words[5] == "unknown") {
|
||||
packing->set_omit(OR_unknown);
|
||||
} else if (words[5] == "solitary") {
|
||||
packing->set_omit(OR_solitary);
|
||||
} else {
|
||||
nout << "Unknown keyword " << words[3] << "\n";
|
||||
nout << "Unknown keyword " << words[5] << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,8 @@
|
||||
|
||||
class UserAttribLine;
|
||||
class PTexture;
|
||||
class TexturePacking;
|
||||
class PaletteGroup;
|
||||
class Palette;
|
||||
class SourceEgg;
|
||||
class EggPalettize;
|
||||
@ -32,12 +34,16 @@ public:
|
||||
bool grab_lock();
|
||||
bool release_lock();
|
||||
|
||||
bool read();
|
||||
bool read(bool force_redo_all);
|
||||
bool write();
|
||||
|
||||
void update_params(EggPalettize *prog);
|
||||
|
||||
void get_req_sizes();
|
||||
PaletteGroup *get_group(const string &group_name);
|
||||
PaletteGroup *get_default_group();
|
||||
|
||||
void get_egg_group_requests();
|
||||
void get_size_requests();
|
||||
void update_texture_flags();
|
||||
|
||||
void repack_all_textures();
|
||||
@ -45,15 +51,13 @@ public:
|
||||
void optimal_resize();
|
||||
void finalize_palettes();
|
||||
void remove_unused_lines();
|
||||
bool check_packing(bool force_optimal);
|
||||
bool pack_texture(PTexture *texture);
|
||||
bool unpack_texture(PTexture *texture);
|
||||
bool prepare_repack(bool force_optimal);
|
||||
|
||||
void touch_dirty_egg_files(bool force_redo_all,
|
||||
bool eggs_include_images);
|
||||
|
||||
PTexture *get_texture(const string &name);
|
||||
void get_eligible_textures(vector<PTexture *> &textures);
|
||||
void get_eligible_textures(vector<TexturePacking *> &textures);
|
||||
SourceEgg *get_egg(Filename name);
|
||||
|
||||
bool generate_palette_images();
|
||||
@ -74,16 +78,17 @@ private:
|
||||
typedef map<string, SourceEgg *> Eggs;
|
||||
Eggs _eggs;
|
||||
|
||||
typedef vector<Palette *> Palettes;
|
||||
Palettes _palettes;
|
||||
typedef map<string, PaletteGroup *> Groups;
|
||||
Groups _groups;
|
||||
|
||||
typedef map<string, PTexture *> PTextures;
|
||||
PTextures _textures;
|
||||
|
||||
string get_pi_filename(const string &txa_filename) const;
|
||||
typedef vector<TexturePacking *> Packing;
|
||||
Packing _packing;
|
||||
|
||||
bool read_txa(istream &outfile);
|
||||
bool read_pi(istream &outfile);
|
||||
bool read_pi(istream &outfile, bool force_redo_all);
|
||||
bool write_txa(ostream &outfile) const;
|
||||
bool write_pi(ostream &outfile) const;
|
||||
|
||||
@ -96,7 +101,7 @@ private:
|
||||
bool parse_pathname(const vector<string> &words, istream &infile,
|
||||
string &line, int &line_num);
|
||||
bool parse_egg(const vector<string> &words, istream &infile,
|
||||
string &line, int &line_num);
|
||||
string &line, int &line_num, bool force_redo_all);
|
||||
bool parse_palette(const vector<string> &words, istream &infile,
|
||||
string &line, int &line_num);
|
||||
bool parse_unplaced(const vector<string> &words, istream &infile,
|
||||
@ -111,7 +116,6 @@ private:
|
||||
Filename _txa_filename;
|
||||
Filename _pi_filename;
|
||||
|
||||
|
||||
public:
|
||||
// These parameter values come from the command line, or from the
|
||||
// .pi file if omitted from the command line. These are the
|
||||
@ -119,7 +123,6 @@ public:
|
||||
// palettes, and thus should be stored in the .pi file for future
|
||||
// reference.
|
||||
Filename _map_dirname;
|
||||
string _palette_prefix;
|
||||
int _pal_xsize, _pal_ysize;
|
||||
int _default_margin;
|
||||
bool _force_power_2;
|
||||
@ -127,6 +130,8 @@ public:
|
||||
|
||||
int _txa_fd;
|
||||
fstream _txa_fstrm;
|
||||
|
||||
friend class PTexture;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "pTexture.h"
|
||||
#include "string_utils.h"
|
||||
#include "sourceEgg.h"
|
||||
#include "textureOmitReason.h"
|
||||
|
||||
#include <pnmImage.h>
|
||||
#include <stdio.h>
|
||||
@ -40,6 +41,11 @@ EggPalettize() : EggMultiFilter(true) {
|
||||
clear_runlines();
|
||||
add_runline("[opts] attribfile.txa file.egg [file.egg ...]");
|
||||
|
||||
// We always have EggMultiBase's -f on: force complete load. In
|
||||
// fact, we use -f for our own purposes, below.
|
||||
remove_option("f");
|
||||
_force_complete = true;
|
||||
|
||||
add_option
|
||||
("s", "", 0,
|
||||
"Do not process anything, but report statistics on all palette "
|
||||
@ -124,10 +130,6 @@ EggPalettize() : EggMultiFilter(true) {
|
||||
"which is an even power of 2. They will be scaled down to "
|
||||
"achieve this.",
|
||||
&EggPalettize::dispatch_none, &_got_force_power_2);
|
||||
add_option
|
||||
("x", "", 0,
|
||||
"Don't palettize anything, but do resize textures.",
|
||||
&EggPalettize::dispatch_none, &_dont_palettize);
|
||||
add_option
|
||||
("k", "", 0,
|
||||
"Kill lines from the attributes file that aren't used on any "
|
||||
@ -227,14 +229,21 @@ read_egg(const Filename &filename) {
|
||||
// We should only call this function if we have exactly one .txa file.
|
||||
nassertr(_attrib_files.size() == 1, (EggData *)NULL);
|
||||
|
||||
SourceEgg *egg = _attrib_files[0]->get_egg(filename);
|
||||
if (egg->read(filename)) {
|
||||
return egg;
|
||||
SourceEgg *data = _attrib_files[0]->get_egg(filename);
|
||||
if (!data->read(filename)) {
|
||||
// Failure reading.
|
||||
delete data;
|
||||
return (EggData *)NULL;
|
||||
}
|
||||
|
||||
// Failure reading.
|
||||
delete egg;
|
||||
return (EggData *)NULL;
|
||||
if (_force_complete) {
|
||||
if (!data->resolve_externals()) {
|
||||
delete data;
|
||||
return (EggData *)NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -267,20 +276,48 @@ describe_input_file() {
|
||||
"applied). Finally, the keyword 'omit' may be included along with the "
|
||||
"size to specify that the texture should not be placed in a palette.\n\n"
|
||||
|
||||
"The attributes file may also assign certain egg files into various "
|
||||
"named palette groups. The syntax is similar to the above:\n\n"
|
||||
|
||||
" car-blue.egg : main\n"
|
||||
" road.egg house.egg : main\n"
|
||||
" plane.egg : phase2 main\n"
|
||||
" car*.egg : phase2\n\n"
|
||||
|
||||
"Any number of egg files may be named on one line, and the group of "
|
||||
"egg files may be simultaneously assigned to one or more groups. Each "
|
||||
"named group represents a semi-independent collection of textures; a "
|
||||
"different set of palette images will be created for each group. Each "
|
||||
"texture that is referenced by a given egg file will be palettized "
|
||||
"in one of the groups assigned to the egg file. Also see the "
|
||||
":group command, below, which defines relationships between the "
|
||||
"different groups.\n\n"
|
||||
|
||||
"There are some other special lines that may appear in this second, "
|
||||
"along with the resize commands. They begin with a colon to "
|
||||
"distinguish them from the resize commands. They are:\n\n"
|
||||
|
||||
":palette xsize ysize\n\n"
|
||||
" :palette xsize ysize\n\n"
|
||||
|
||||
"This specifies the size of the palette file(s) to be created. It "
|
||||
"overrides the -s command-line option.\n\n"
|
||||
|
||||
":margin msize\n\n"
|
||||
" :margin msize\n\n"
|
||||
|
||||
"This specifies the size of the default margin for all subsequent "
|
||||
"resize commands. This may appear several times in a given file.\n\n"
|
||||
|
||||
" :group groupname1 with groupname2 [groupname3 ...]\n\n"
|
||||
|
||||
"This indicates that the palette group named by groupname1 should "
|
||||
"be allowed to shared textures with those on groupname2 or groupname3, "
|
||||
"etc. In other words, that whenever palette group groupname1 is in "
|
||||
"texture memory, we can assume that palette groups groupname2 and "
|
||||
"groupname3 will also be in memory. Textures that already exist on "
|
||||
"groupname2 and other dependent groups will not be added to groupname1; "
|
||||
"instead, egg files will reference the textures directly from the "
|
||||
"other palettes.\n\n"
|
||||
|
||||
"Comments may appear freely throughout the file, and are set off by a "
|
||||
"hash mark (#).\n";
|
||||
}
|
||||
@ -314,6 +351,7 @@ format_space(int size_pixels, bool verbose) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggPalettize::
|
||||
report_statistics() {
|
||||
/*
|
||||
// Look for textures in common.
|
||||
map<string, PTexture *> textures;
|
||||
map<string, int> dup_textures;
|
||||
@ -371,17 +409,17 @@ report_statistics() {
|
||||
int net_orig_size = 0;
|
||||
int net_resized_size = 0;
|
||||
int net_unplaced_size = 0;
|
||||
typedef map<PTexture::OmitReason, pair<int, int> > UnplacedReasons;
|
||||
typedef map<TextureOmitReason, pair<int, int> > UnplacedReasons;
|
||||
UnplacedReasons unplaced_reasons;
|
||||
|
||||
map<string, PTexture *>::iterator ti;
|
||||
for (ti = textures.begin(); ti != textures.end(); ++ti) {
|
||||
PTexture *texture = (*ti).second;
|
||||
|
||||
int xsize, ysize;
|
||||
int xsize, ysize, zsize;
|
||||
int rxsize, rysize;
|
||||
int rsize = 0;
|
||||
if (texture->get_size(xsize, ysize) &&
|
||||
if (texture->get_size(xsize, ysize, zsize) &&
|
||||
texture->get_last_req(rxsize, rysize)) {
|
||||
net_orig_size += xsize * ysize;
|
||||
net_resized_size += rxsize * rysize;
|
||||
@ -427,7 +465,7 @@ report_statistics() {
|
||||
for (uri = unplaced_reasons.begin();
|
||||
uri != unplaced_reasons.end();
|
||||
++uri) {
|
||||
PTexture::OmitReason reason = (*uri).first;
|
||||
TextureOmitReason reason = (*uri).first;
|
||||
int count = (*uri).second.first;
|
||||
int size = (*uri).second.second;
|
||||
cout << count << " textures (" << format_space(size)
|
||||
@ -471,6 +509,7 @@ report_statistics() {
|
||||
}
|
||||
|
||||
cout << "\n";
|
||||
*/
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -503,12 +542,12 @@ run() {
|
||||
|
||||
if (_statistics_only) {
|
||||
nout << "Reading " << af.get_name() << "\n";
|
||||
okflag = af.read();
|
||||
okflag = af.read(false);
|
||||
|
||||
} else {
|
||||
nout << "Processing " << af.get_name() << "\n";
|
||||
|
||||
if (!af.read()) {
|
||||
if (!af.read(_force_redo_all)) {
|
||||
// Failing to read the attribute file is a fatal error.
|
||||
exit(1);
|
||||
}
|
||||
@ -519,15 +558,17 @@ run() {
|
||||
Eggs::iterator ei;
|
||||
for (ei = _eggs.begin(); ei != _eggs.end(); ++ei) {
|
||||
SourceEgg *egg = DCAST(SourceEgg, *ei);
|
||||
egg->get_textures(af, this);
|
||||
egg->get_textures(this);
|
||||
}
|
||||
|
||||
// Assign textures into the appropriate groups.
|
||||
af.get_egg_group_requests();
|
||||
|
||||
// Apply the user's requested size changes onto the textures.
|
||||
af.get_req_sizes();
|
||||
af.get_size_requests();
|
||||
af.update_texture_flags();
|
||||
|
||||
if (!af.check_packing(_force_optimal) || _force_redo_all) {
|
||||
// We need some more palettization work here.
|
||||
if (af.prepare_repack(_force_optimal) || _force_redo_all) {
|
||||
if (_force_redo_all || _force_optimal) {
|
||||
af.repack_all_textures();
|
||||
} else {
|
||||
|
@ -36,7 +36,7 @@ public:
|
||||
AttribFiles _attrib_files;
|
||||
|
||||
// The following parameter values specifically relate to textures
|
||||
// and palettes. These values are store in the .pi file for future
|
||||
// and palettes. These values are stored in the .pi file for future
|
||||
// reference.
|
||||
Filename _map_dirname;
|
||||
bool _got_map_dirname;
|
||||
@ -62,7 +62,6 @@ public:
|
||||
bool _optimal_resize;
|
||||
bool _touch_eggs;
|
||||
bool _eggs_include_images;
|
||||
bool _dont_palettize;
|
||||
bool _remove_unused_lines;
|
||||
|
||||
bool _describe_input_file;
|
||||
|
@ -4,32 +4,46 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "pTexture.h"
|
||||
#include "texturePacking.h"
|
||||
#include "palette.h"
|
||||
#include "attribFile.h"
|
||||
|
||||
#include <pnmImage.h>
|
||||
#include <pnmReader.h>
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PTexture::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PTexture::
|
||||
PTexture(AttribFile *af, const Filename &name) :
|
||||
PTexture(AttribFile *attrib_file, const Filename &name) :
|
||||
_name(name),
|
||||
_attrib_file(af)
|
||||
_attrib_file(attrib_file)
|
||||
{
|
||||
_got_filename = false;
|
||||
_file_exists = false;
|
||||
_texture_changed = false;
|
||||
_unused = true;
|
||||
_matched_anything = false;
|
||||
_got_size = false;
|
||||
_got_req = false;
|
||||
_got_last_req = false;
|
||||
_margin = _attrib_file->_default_margin;
|
||||
_omit = false;
|
||||
_read_header = false;
|
||||
_omit = OR_none;
|
||||
_uses_alpha = false;
|
||||
_is_packed = false;
|
||||
_palette = NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PTexture::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PTexture::
|
||||
~PTexture() {
|
||||
Packing::iterator pi;
|
||||
for (pi = _packing.begin(); pi != _packing.end(); ++pi) {
|
||||
delete (*pi).second;
|
||||
}
|
||||
}
|
||||
|
||||
Filename PTexture::
|
||||
@ -68,15 +82,16 @@ add_filename(const Filename &filename) {
|
||||
read_header();
|
||||
}
|
||||
|
||||
int oxsize, oysize;
|
||||
int oxsize, oysize, ozsize;
|
||||
bool got_other_size =
|
||||
read_image_header(filename, oxsize, oysize);
|
||||
read_image_header(filename, oxsize, oysize, ozsize);
|
||||
|
||||
if (got_other_size) {
|
||||
if (!_got_size || oxsize * oysize > _xsize * _ysize) {
|
||||
_filename = filename;
|
||||
_xsize = oxsize;
|
||||
_ysize = oysize;
|
||||
_zsize = ozsize;
|
||||
_got_size = true;
|
||||
_texture_changed = true;
|
||||
|
||||
@ -106,7 +121,7 @@ get_basename() const {
|
||||
}
|
||||
|
||||
bool PTexture::
|
||||
get_size(int &xsize, int &ysize) {
|
||||
get_size(int &xsize, int &ysize, int &zsize) {
|
||||
if (!_got_size) {
|
||||
read_header();
|
||||
}
|
||||
@ -117,16 +132,18 @@ get_size(int &xsize, int &ysize) {
|
||||
|
||||
xsize = _xsize;
|
||||
ysize = _ysize;
|
||||
zsize = _zsize;
|
||||
return true;
|
||||
}
|
||||
|
||||
void PTexture::
|
||||
set_size(int xsize, int ysize) {
|
||||
set_size(int xsize, int ysize, int zsize) {
|
||||
// If we've already read the file header, don't let anyone tell us
|
||||
// differently.
|
||||
if (!_read_header) {
|
||||
_xsize = xsize;
|
||||
_ysize = ysize;
|
||||
_zsize = zsize;
|
||||
_got_size = true;
|
||||
}
|
||||
}
|
||||
@ -134,7 +151,8 @@ set_size(int xsize, int ysize) {
|
||||
bool PTexture::
|
||||
get_req(int &xsize, int &ysize) {
|
||||
if (!_got_req) {
|
||||
return get_size(xsize, ysize);
|
||||
int zsize;
|
||||
return get_size(xsize, ysize, zsize);
|
||||
}
|
||||
xsize = _req_xsize;
|
||||
ysize = _req_ysize;
|
||||
@ -144,7 +162,8 @@ get_req(int &xsize, int &ysize) {
|
||||
bool PTexture::
|
||||
get_last_req(int &xsize, int &ysize) {
|
||||
if (!_got_last_req) {
|
||||
return get_size(xsize, ysize);
|
||||
int zsize;
|
||||
return get_size(xsize, ysize, zsize);
|
||||
}
|
||||
xsize = _last_req_xsize;
|
||||
ysize = _last_req_ysize;
|
||||
@ -187,12 +206,6 @@ void PTexture::
|
||||
clear_req() {
|
||||
_got_req = false;
|
||||
_margin = _attrib_file->_default_margin;
|
||||
|
||||
if (_omit != OR_cmdline) {
|
||||
// If we previously omitted this texture from the command line,
|
||||
// preserve that property.
|
||||
_omit = OR_none;
|
||||
}
|
||||
}
|
||||
|
||||
double PTexture::
|
||||
@ -219,179 +232,127 @@ set_margin(int margin) {
|
||||
_margin = margin;
|
||||
}
|
||||
|
||||
PTexture::OmitReason PTexture::
|
||||
get_omit() const {
|
||||
return _omit;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PTexture::user_omit
|
||||
// Access: Public
|
||||
// Description: Omits the texture from all palettes, based on a
|
||||
// user-supplied "omit" parameter (presumably read from
|
||||
// the .txa file).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PTexture::
|
||||
set_omit(OmitReason omit) {
|
||||
_omit = omit;
|
||||
user_omit() {
|
||||
_omit = true;
|
||||
|
||||
// Also omit each of our already-packed textures.
|
||||
Packing::iterator pi;
|
||||
for (pi = _packing.begin(); pi != _packing.end(); ++pi) {
|
||||
(*pi).second->set_omit(OR_omitted);
|
||||
}
|
||||
}
|
||||
|
||||
bool PTexture::
|
||||
needs_refresh() {
|
||||
if (!_texture_changed) {
|
||||
// We consider the texture to be out-of-date if it's moved around
|
||||
// in the palette.
|
||||
_texture_changed = packing_changed();
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PTexture::add_to_group
|
||||
// Access: Public
|
||||
// Description: Adds the texture to the indicated PaletteGroup, if it
|
||||
// has not already been added. Returns the
|
||||
// TexturePacking pointer that represents the addition.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
TexturePacking *PTexture::
|
||||
add_to_group(PaletteGroup *group) {
|
||||
Packing::iterator pi;
|
||||
pi = _packing.find(group);
|
||||
if (pi != _packing.end()) {
|
||||
return (*pi).second;
|
||||
}
|
||||
|
||||
if (!_texture_changed && _file_exists) {
|
||||
// Compare the texture's timestamp to that of its palette (or
|
||||
// resized copy). If it's newer, it's changed and must be
|
||||
// replaced.
|
||||
|
||||
Filename target_filename;
|
||||
if (is_packed() && _omit == OR_none) {
|
||||
// Compare to the palette file.
|
||||
target_filename = _palette->get_filename();
|
||||
if (_palette->new_palette()) {
|
||||
// It's a brand new palette; don't even bother comparing
|
||||
// timestamps.
|
||||
_texture_changed = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Compare to the resized file.
|
||||
target_filename = get_filename();
|
||||
}
|
||||
|
||||
if (!_texture_changed) {
|
||||
_texture_changed =
|
||||
(target_filename.compare_timestamps(_filename, true, false) < 0);
|
||||
}
|
||||
}
|
||||
|
||||
return _texture_changed;
|
||||
TexturePacking *packing = new TexturePacking(this, group);
|
||||
_packing[group] = packing;
|
||||
_attrib_file->_packing.push_back(packing);
|
||||
return packing;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PTexture::check_group
|
||||
// Access: Public
|
||||
// Description: If the texture has already been added to the
|
||||
// indicated PaletteGroup, returns the associated
|
||||
// TexturePacking object. If it is not yet been added,
|
||||
// returns NULL.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
TexturePacking *PTexture::
|
||||
check_group(PaletteGroup *group) const {
|
||||
Packing::const_iterator pi;
|
||||
pi = _packing.find(group);
|
||||
if (pi != _packing.end()) {
|
||||
return (*pi).second;
|
||||
}
|
||||
|
||||
return (TexturePacking *)NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PTexture::set_changed
|
||||
// Access: Public
|
||||
// Description: Sets the state of the changed flag. If this is true,
|
||||
// the texture is known to have changed in some way such
|
||||
// that files that depend on it will need to be rebuilt.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PTexture::
|
||||
set_changed(bool changed) {
|
||||
_texture_changed = changed;
|
||||
}
|
||||
|
||||
bool PTexture::
|
||||
unused() const {
|
||||
return _unused;
|
||||
}
|
||||
|
||||
void PTexture::
|
||||
set_unused(bool unused) {
|
||||
_unused = unused;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PTexture::matched_anything
|
||||
// Access: Public
|
||||
// Description: Returns true if the texture matched at least one line
|
||||
// in the .txa file, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PTexture::
|
||||
matched_anything() const {
|
||||
return _matched_anything;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PTexture::set_matched_anything
|
||||
// Access: Public
|
||||
// Description: Sets the state of the matched_anything flag. See
|
||||
// matched_anything().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PTexture::
|
||||
set_matched_anything(bool matched_anything) {
|
||||
_matched_anything = matched_anything;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PTexture::is_unused
|
||||
// Access: Public
|
||||
// Description: Returns true if the texture is not used by any egg
|
||||
// file in any palette group, false if it is used by at
|
||||
// least one in at least one group.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PTexture::
|
||||
uses_alpha() const {
|
||||
return _uses_alpha;
|
||||
}
|
||||
|
||||
void PTexture::
|
||||
set_uses_alpha(bool uses_alpha) {
|
||||
_uses_alpha = uses_alpha;
|
||||
}
|
||||
|
||||
void PTexture::
|
||||
mark_pack_location(Palette *palette, int left, int top,
|
||||
int xsize, int ysize, int margin) {
|
||||
_is_packed = true;
|
||||
_palette = palette;
|
||||
_pleft = left;
|
||||
_ptop = top;
|
||||
_pxsize = xsize;
|
||||
_pysize = ysize;
|
||||
_pmargin = margin;
|
||||
}
|
||||
|
||||
void PTexture::
|
||||
mark_unpacked() {
|
||||
_is_packed = false;
|
||||
}
|
||||
|
||||
bool PTexture::
|
||||
is_packed() const {
|
||||
return _is_packed;
|
||||
}
|
||||
|
||||
// Returns the same thing as is_packed(), except it doesn't consider a
|
||||
// texture that has been left alone on a palette to be packed.
|
||||
bool PTexture::
|
||||
is_really_packed() const {
|
||||
return _is_packed && _omit != OR_solitary;
|
||||
}
|
||||
|
||||
Palette *PTexture::
|
||||
get_palette() const {
|
||||
return _is_packed ? _palette : (Palette *)NULL;
|
||||
}
|
||||
|
||||
bool PTexture::
|
||||
get_packed_location(int &left, int &top) const {
|
||||
left = _pleft;
|
||||
top = _ptop;
|
||||
return _is_packed;
|
||||
}
|
||||
|
||||
bool PTexture::
|
||||
get_packed_size(int &xsize, int &ysize, int &margin) const {
|
||||
xsize = _pxsize;
|
||||
ysize = _pysize;
|
||||
margin = _pmargin;
|
||||
return _is_packed;
|
||||
}
|
||||
|
||||
void PTexture::
|
||||
record_orig_state() {
|
||||
// Records the current packing state, storing it aside as the state
|
||||
// at load time. Later, when the packing state may have changed,
|
||||
// packing_changed() will return true if it has or false if it
|
||||
// has not.
|
||||
_orig_is_packed = _is_packed;
|
||||
if (_is_packed) {
|
||||
_orig_palette_name = _palette->get_filename();
|
||||
_opleft = _pleft;
|
||||
_optop = _ptop;
|
||||
_opxsize = _pxsize;
|
||||
_opysize = _pysize;
|
||||
_opmargin = _pmargin;
|
||||
is_unused() const {
|
||||
Packing::const_iterator pi;
|
||||
for (pi = _packing.begin(); pi != _packing.end(); ++pi) {
|
||||
if (!(*pi).second->unused()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PTexture::
|
||||
packing_changed() const {
|
||||
if (_orig_is_packed != _is_packed) {
|
||||
return true;
|
||||
}
|
||||
if (_is_packed) {
|
||||
return _orig_palette_name != _palette->get_filename() ||
|
||||
_opleft != _pleft ||
|
||||
_optop != _ptop ||
|
||||
_opxsize != _pxsize ||
|
||||
_opysize != _pysize ||
|
||||
_opmargin != _pmargin;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PTexture::
|
||||
write_size(ostream &out) {
|
||||
if (_omit != OR_unused) {
|
||||
if (!is_unused()) {
|
||||
if (!_got_size) {
|
||||
read_header();
|
||||
}
|
||||
out << " " << _name;
|
||||
if (_got_size) {
|
||||
out << " orig " << _xsize << " " << _ysize;
|
||||
out << " orig " << _xsize << " " << _ysize << " " << _zsize;
|
||||
}
|
||||
if (_got_req) {
|
||||
out << " new " << _req_xsize << " " << _req_ysize;
|
||||
@ -402,7 +363,7 @@ write_size(ostream &out) {
|
||||
|
||||
void PTexture::
|
||||
write_pathname(ostream &out) const {
|
||||
if (_got_filename && _omit != OR_unused) {
|
||||
if (_got_filename && !is_unused()) {
|
||||
if (!_file_exists) {
|
||||
nout << "Warning: texture " << _filename << " does not exist.\n";
|
||||
}
|
||||
@ -423,40 +384,6 @@ write_pathname(ostream &out) const {
|
||||
}
|
||||
}
|
||||
|
||||
void PTexture::
|
||||
write_unplaced(ostream &out) const {
|
||||
if (_omit != OR_none && _omit != OR_unused) {
|
||||
out << "unplaced " << get_name() << " because ";
|
||||
switch (_omit) {
|
||||
case OR_size:
|
||||
out << "size";
|
||||
break;
|
||||
case OR_repeats:
|
||||
out << "repeats";
|
||||
break;
|
||||
case OR_omitted:
|
||||
out << "omitted";
|
||||
break;
|
||||
case OR_unused:
|
||||
out << "unused";
|
||||
break;
|
||||
case OR_unknown:
|
||||
out << "unknown";
|
||||
break;
|
||||
case OR_solitary:
|
||||
out << "solitary";
|
||||
break;
|
||||
case OR_cmdline:
|
||||
out << "cmdline";
|
||||
break;
|
||||
default:
|
||||
nout << "Invalid type: " << (int)_omit << "\n";
|
||||
abort();
|
||||
}
|
||||
out << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
bool PTexture::
|
||||
transfer() {
|
||||
bool okflag = true;
|
||||
@ -557,14 +484,15 @@ read_header() {
|
||||
if (_got_filename && _file_exists) {
|
||||
if (!_read_header) {
|
||||
_read_header = true;
|
||||
_got_size = read_image_header(_filename, _xsize, _ysize);
|
||||
_got_size = read_image_header(_filename, _xsize, _ysize, _zsize);
|
||||
}
|
||||
_read_header = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool PTexture::
|
||||
read_image_header(const Filename &filename, int &xsize, int &ysize) {
|
||||
read_image_header(const Filename &filename, int &xsize, int &ysize,
|
||||
int &zsize) {
|
||||
PNMImageHeader header;
|
||||
if (!header.read_header(filename)) {
|
||||
nout << "Warning: cannot read texture " << filename << "\n";
|
||||
@ -573,6 +501,7 @@ read_image_header(const Filename &filename, int &xsize, int &ysize) {
|
||||
|
||||
xsize = header.get_x_size();
|
||||
ysize = header.get_y_size();
|
||||
zsize = header.get_num_channels();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -11,24 +11,26 @@
|
||||
#include "imageFile.h"
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
class Palette;
|
||||
class PNMImage;
|
||||
class AttribFile;
|
||||
class PaletteGroup;
|
||||
class TexturePacking;
|
||||
class TextureEggRef;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : PTexture
|
||||
// Description :
|
||||
// Description : A single texture filename, as read from an egg file
|
||||
// or from a .txa file. This may be considered for
|
||||
// palettization on a number of different groups, but it
|
||||
// must have the same size in each group.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class PTexture : public ImageFile {
|
||||
public:
|
||||
enum OmitReason {
|
||||
OR_none,
|
||||
OR_size, OR_repeats, OR_omitted, OR_unused, OR_unknown,
|
||||
OR_cmdline, OR_solitary
|
||||
};
|
||||
|
||||
PTexture(AttribFile *af, const Filename &name);
|
||||
PTexture(AttribFile *attrib_file, const Filename &name);
|
||||
~PTexture();
|
||||
|
||||
Filename get_name() const;
|
||||
|
||||
@ -37,8 +39,8 @@ public:
|
||||
virtual Filename get_filename() const;
|
||||
virtual Filename get_basename() const;
|
||||
|
||||
bool get_size(int &xsize, int &ysize);
|
||||
void set_size(int xsize, int ysize);
|
||||
bool get_size(int &xsize, int &ysize, int &zsize);
|
||||
void set_size(int xsize, int ysize, int zsize);
|
||||
|
||||
bool get_req(int &xsize, int &ysize);
|
||||
bool get_last_req(int &xsize, int &ysize);
|
||||
@ -51,44 +53,32 @@ public:
|
||||
int get_margin() const;
|
||||
void set_margin(int margin);
|
||||
|
||||
OmitReason get_omit() const;
|
||||
void set_omit(OmitReason omit);
|
||||
void user_omit();
|
||||
|
||||
TexturePacking *add_to_group(PaletteGroup *group);
|
||||
TexturePacking *check_group(PaletteGroup *group) const;
|
||||
|
||||
bool needs_refresh();
|
||||
void set_changed(bool changed);
|
||||
|
||||
bool unused() const;
|
||||
void set_unused(bool unused);
|
||||
|
||||
bool matched_anything() const;
|
||||
void set_matched_anything(bool matched_anything);
|
||||
|
||||
bool uses_alpha() const;
|
||||
void set_uses_alpha(bool uses_alpha);
|
||||
|
||||
void mark_pack_location(Palette *palette, int left, int top,
|
||||
int xsize, int ysize, int margin);
|
||||
void mark_unpacked();
|
||||
bool is_packed() const;
|
||||
bool is_really_packed() const;
|
||||
Palette *get_palette() const;
|
||||
bool get_packed_location(int &left, int &top) const;
|
||||
bool get_packed_size(int &xsize, int &ysize, int &margin) const;
|
||||
void record_orig_state();
|
||||
bool packing_changed() const;
|
||||
bool is_unused() const;
|
||||
|
||||
void write_size(ostream &out);
|
||||
void write_pathname(ostream &out) const;
|
||||
void write_unplaced(ostream &out) const;
|
||||
|
||||
bool transfer();
|
||||
|
||||
PNMImage *read_image();
|
||||
|
||||
typedef set<TextureEggRef *> Eggs;
|
||||
Eggs _eggs;
|
||||
|
||||
private:
|
||||
void check_size();
|
||||
void read_header();
|
||||
bool read_image_header(const Filename &filename, int &xsize, int &ysize);
|
||||
bool read_image_header(const Filename &filename,
|
||||
int &xsize, int &ysize, int &zsize);
|
||||
static int to_power_2(int value);
|
||||
|
||||
Filename _name;
|
||||
@ -100,31 +90,27 @@ private:
|
||||
Filename _filename;
|
||||
bool _file_exists;
|
||||
bool _texture_changed;
|
||||
bool _unused;
|
||||
bool _matched_anything;
|
||||
bool _uses_alpha;
|
||||
|
||||
bool _got_size;
|
||||
int _xsize, _ysize;
|
||||
int _zsize;
|
||||
|
||||
bool _got_req;
|
||||
int _req_xsize, _req_ysize;
|
||||
bool _got_last_req;
|
||||
int _last_req_xsize, _last_req_ysize;
|
||||
int _margin;
|
||||
OmitReason _omit;
|
||||
|
||||
bool _is_packed;
|
||||
Palette *_palette;
|
||||
int _pleft, _ptop, _pxsize, _pysize, _pmargin;
|
||||
|
||||
bool _orig_is_packed;
|
||||
Filename _orig_palette_name;
|
||||
int _opleft, _optop, _opxsize, _opysize, _opmargin;
|
||||
bool _omit;
|
||||
|
||||
bool _read_header;
|
||||
|
||||
AttribFile *_attrib_file;
|
||||
|
||||
typedef map<PaletteGroup *, TexturePacking *> Packing;
|
||||
Packing _packing;
|
||||
|
||||
friend class TexturePacking;
|
||||
};
|
||||
|
||||
|
||||
|
@ -4,7 +4,9 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "palette.h"
|
||||
#include "paletteGroup.h"
|
||||
#include "pTexture.h"
|
||||
#include "texturePacking.h"
|
||||
#include "attribFile.h"
|
||||
#include "string_utils.h"
|
||||
|
||||
@ -135,13 +137,14 @@ add_margins(PNMImage *source) const {
|
||||
|
||||
|
||||
Palette::
|
||||
Palette(const Filename &filename, int xsize, int ysize, int components,
|
||||
AttribFile *af) :
|
||||
Palette(const Filename &filename, PaletteGroup *group,
|
||||
int xsize, int ysize, int components, AttribFile *attrib_file) :
|
||||
_filename(filename),
|
||||
_group(group),
|
||||
_xsize(xsize),
|
||||
_ysize(ysize),
|
||||
_components(components),
|
||||
_attrib_file(af)
|
||||
_attrib_file(attrib_file)
|
||||
{
|
||||
_index = -1;
|
||||
_palette_changed = false;
|
||||
@ -149,12 +152,14 @@ Palette(const Filename &filename, int xsize, int ysize, int components,
|
||||
}
|
||||
|
||||
Palette::
|
||||
Palette(int index, int xsize, int ysize, int components, AttribFile *af) :
|
||||
Palette(PaletteGroup *group, int index,
|
||||
int xsize, int ysize, int components, AttribFile *attrib_file) :
|
||||
_group(group),
|
||||
_index(index),
|
||||
_xsize(xsize),
|
||||
_ysize(ysize),
|
||||
_components(components),
|
||||
_attrib_file(af)
|
||||
_attrib_file(attrib_file)
|
||||
{
|
||||
_palette_changed = false;
|
||||
_new_palette = true;
|
||||
@ -165,7 +170,7 @@ Palette::
|
||||
// Unmark any textures we've had packed.
|
||||
TexPlace::iterator ti;
|
||||
for (ti = _texplace.begin(); ti != _texplace.end(); ++ti) {
|
||||
(*ti)._texture->mark_unpacked();
|
||||
(*ti)._packing->mark_unpacked();
|
||||
}
|
||||
}
|
||||
|
||||
@ -199,7 +204,7 @@ check_uses_alpha() const {
|
||||
// Returns true if any texture in the palette uses alpha.
|
||||
TexPlace::const_iterator ti;
|
||||
for (ti = _texplace.begin(); ti != _texplace.end(); ++ti) {
|
||||
if ((*ti)._texture->uses_alpha()) {
|
||||
if ((*ti)._packing->uses_alpha()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -215,10 +220,11 @@ get_size(int &xsize, int &ysize) const {
|
||||
|
||||
|
||||
void Palette::
|
||||
place_texture_at(PTexture *texture, int left, int top,
|
||||
place_texture_at(TexturePacking *packing, int left, int top,
|
||||
int xsize, int ysize, int margin) {
|
||||
nassertv(_group != (PaletteGroup *)NULL);
|
||||
TexturePlacement tp;
|
||||
tp._texture = texture;
|
||||
tp._packing = packing;
|
||||
tp._left = left;
|
||||
tp._top = top;
|
||||
tp._xsize = xsize;
|
||||
@ -226,11 +232,12 @@ place_texture_at(PTexture *texture, int left, int top,
|
||||
tp._margin = margin;
|
||||
_texplace.push_back(tp);
|
||||
|
||||
texture->mark_pack_location(this, left, top, xsize, ysize, margin);
|
||||
packing->mark_pack_location(this, left, top, xsize, ysize, margin);
|
||||
}
|
||||
|
||||
bool Palette::
|
||||
pack_texture(PTexture *texture) {
|
||||
pack_texture(TexturePacking *packing) {
|
||||
PTexture *texture = packing->get_texture();
|
||||
int xsize, ysize;
|
||||
if (!texture->get_req(xsize, ysize)) {
|
||||
return false;
|
||||
@ -238,7 +245,7 @@ pack_texture(PTexture *texture) {
|
||||
|
||||
int left, top;
|
||||
if (find_home(left, top, xsize, ysize)) {
|
||||
place_texture_at(texture, left, top, xsize, ysize, texture->get_margin());
|
||||
place_texture_at(packing, left, top, xsize, ysize, texture->get_margin());
|
||||
_palette_changed = true;
|
||||
return true;
|
||||
}
|
||||
@ -246,12 +253,12 @@ pack_texture(PTexture *texture) {
|
||||
}
|
||||
|
||||
bool Palette::
|
||||
unpack_texture(PTexture *texture) {
|
||||
unpack_texture(TexturePacking *packing) {
|
||||
TexPlace::iterator ti;
|
||||
for (ti = _texplace.begin(); ti != _texplace.end(); ++ti) {
|
||||
if ((*ti)._texture == texture) {
|
||||
if ((*ti)._packing == packing) {
|
||||
_texplace.erase(ti);
|
||||
texture->mark_unpacked();
|
||||
packing->mark_unpacked();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -308,7 +315,7 @@ optimal_resize() {
|
||||
// these textures will need to be rebuilt.
|
||||
TexPlace::iterator ti;
|
||||
for (ti = _texplace.begin(); ti != _texplace.end(); ++ti) {
|
||||
(*ti)._texture->set_changed(true);
|
||||
(*ti)._packing->set_changed(true);
|
||||
}
|
||||
|
||||
// And we'll have to mark the palette as a new image.
|
||||
@ -323,7 +330,7 @@ finalize_palette() {
|
||||
// Generate a filename based on the index number.
|
||||
char index_str[128];
|
||||
sprintf(index_str, "%03d", _index);
|
||||
_basename = _attrib_file->_palette_prefix + index_str + ".rgb";
|
||||
_basename = _group->get_name() + "-palette." + index_str + ".rgb";
|
||||
_filename = _basename;
|
||||
_filename.set_dirname(_attrib_file->_map_dirname);
|
||||
} else {
|
||||
@ -334,7 +341,7 @@ finalize_palette() {
|
||||
|
||||
if (_texplace.size() == 1) {
|
||||
// If we packed exactly one texture, never mind.
|
||||
PTexture *texture = (*_texplace.begin())._texture;
|
||||
TexturePacking *packing = (*_texplace.begin())._packing;
|
||||
|
||||
// This is a little odd: we mark the texture as being omitted, but
|
||||
// we don't actually unpack it. That way it will still be
|
||||
@ -342,18 +349,18 @@ finalize_palette() {
|
||||
// palettizations), but it will also be copied to the map
|
||||
// directory, and any egg files that reference it will use the
|
||||
// texture and not the palette.
|
||||
texture->set_omit(PTexture::OR_solitary);
|
||||
packing->set_omit(OR_solitary);
|
||||
}
|
||||
}
|
||||
|
||||
void Palette::
|
||||
write(ostream &out) const {
|
||||
out << "palette " << _filename
|
||||
out << "palette " << _filename << " in " << _group->get_name()
|
||||
<< " size " << _xsize << " " << _ysize << " " << _components
|
||||
<< "\n";
|
||||
TexPlace::const_iterator ti;
|
||||
for (ti = _texplace.begin(); ti != _texplace.end(); ++ti) {
|
||||
out << " " << (*ti)._texture->get_name()
|
||||
out << " " << (*ti)._packing->get_texture()->get_name()
|
||||
<< " at " << (*ti)._left << " " << (*ti)._top
|
||||
<< " size " << (*ti)._xsize << " " << (*ti)._ysize
|
||||
<< " margin " << (*ti)._margin
|
||||
@ -371,7 +378,8 @@ generate_image() {
|
||||
|
||||
TexPlace::const_iterator ti;
|
||||
for (ti = _texplace.begin(); ti != _texplace.end(); ++ti) {
|
||||
PTexture *texture = (*ti)._texture;
|
||||
TexturePacking *packing = (*ti)._packing;
|
||||
PTexture *texture = packing->get_texture();
|
||||
nout << " " << texture->get_name() << "\n";
|
||||
okflag = copy_texture_image(palette, *ti) && okflag;
|
||||
}
|
||||
@ -415,8 +423,9 @@ refresh_image() {
|
||||
|
||||
TexPlace::const_iterator ti;
|
||||
for (ti = _texplace.begin(); ti != _texplace.end(); ++ti) {
|
||||
PTexture *texture = (*ti)._texture;
|
||||
if (texture->needs_refresh()) {
|
||||
TexturePacking *packing = (*ti)._packing;
|
||||
PTexture *texture = packing->get_texture();
|
||||
if (packing->needs_refresh()) {
|
||||
if (!any_changed) {
|
||||
nout << "Refreshing " << _filename << "\n";
|
||||
any_changed = true;
|
||||
@ -442,7 +451,7 @@ refresh_image() {
|
||||
Palette *Palette::
|
||||
try_resize(int new_xsize, int new_ysize) const {
|
||||
Palette *np =
|
||||
new Palette(_index, new_xsize, new_ysize,
|
||||
new Palette(_group, _index, new_xsize, new_ysize,
|
||||
_components, _attrib_file);
|
||||
|
||||
bool okflag = true;
|
||||
@ -450,7 +459,7 @@ try_resize(int new_xsize, int new_ysize) const {
|
||||
for (ti = _texplace.begin();
|
||||
ti != _texplace.end() && okflag;
|
||||
++ti) {
|
||||
okflag = np->pack_texture((*ti)._texture);
|
||||
okflag = np->pack_texture((*ti)._packing);
|
||||
}
|
||||
|
||||
if (okflag) {
|
||||
@ -518,9 +527,10 @@ find_home(int &left, int &top, int xsize, int ysize) const {
|
||||
bool Palette::
|
||||
copy_texture_image(PNMImage &palette, const TexturePlacement &tp) {
|
||||
bool okflag = true;
|
||||
PNMImage *image = tp._texture->read_image();
|
||||
PTexture *texture = tp._packing->get_texture();
|
||||
PNMImage *image = texture->read_image();
|
||||
if (image == NULL) {
|
||||
nout << " *** Unable to read " << tp._texture->get_name() << "\n";
|
||||
nout << " *** Unable to read " << texture->get_name() << "\n";
|
||||
okflag = false;
|
||||
|
||||
// Create a solid red texture for images we can't read.
|
||||
|
@ -14,25 +14,33 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
class PTexture;
|
||||
class PaletteGroup;
|
||||
class TexturePacking;
|
||||
class PNMImage;
|
||||
class AttribFile;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : Palette
|
||||
// Description :
|
||||
// Description : A single palettized image file within a palette
|
||||
// group. This represents one page of all the
|
||||
// palettized textures within this group; there might be
|
||||
// multiple Palette images within a single group,
|
||||
// depending on the number and size of the palettized
|
||||
// textures.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class Palette : public ImageFile {
|
||||
public:
|
||||
Palette(const Filename &filename, int xsize, int ysize, int components,
|
||||
AttribFile *af);
|
||||
Palette(int index, int xsize, int ysize, int components,
|
||||
AttribFile *af);
|
||||
Palette(const Filename &filename, PaletteGroup *group,
|
||||
int xsize, int ysize, int components, AttribFile *attrib_file);
|
||||
Palette(PaletteGroup *group, int index,
|
||||
int xsize, int ysize, int components, AttribFile *attrib_file);
|
||||
~Palette();
|
||||
|
||||
virtual Filename get_filename() const;
|
||||
virtual Filename get_basename() const;
|
||||
|
||||
PaletteGroup *get_group() const;
|
||||
|
||||
bool changed() const;
|
||||
bool new_palette() const;
|
||||
int get_num_textures() const;
|
||||
@ -41,11 +49,11 @@ public:
|
||||
|
||||
void get_size(int &xsize, int &ysize) const;
|
||||
|
||||
void place_texture_at(PTexture *texture, int left, int top,
|
||||
void place_texture_at(TexturePacking *packing, int left, int top,
|
||||
int xsize, int ysize, int margin);
|
||||
|
||||
bool pack_texture(PTexture *texture);
|
||||
bool unpack_texture(PTexture *texture);
|
||||
bool pack_texture(TexturePacking *packing);
|
||||
bool unpack_texture(TexturePacking *packing);
|
||||
|
||||
void optimal_resize();
|
||||
|
||||
@ -63,7 +71,7 @@ private:
|
||||
PNMImage *resize_image(PNMImage *source) const;
|
||||
PNMImage *add_margins(PNMImage *source) const;
|
||||
|
||||
PTexture *_texture;
|
||||
TexturePacking *_packing;
|
||||
int _left, _top;
|
||||
int _xsize, _ysize, _margin;
|
||||
};
|
||||
@ -79,6 +87,7 @@ private:
|
||||
|
||||
Filename _filename;
|
||||
Filename _basename;
|
||||
PaletteGroup *_group;
|
||||
int _index;
|
||||
int _xsize, _ysize, _components;
|
||||
bool _palette_changed;
|
||||
|
259
pandatool/src/egg-palettize/paletteGroup.cxx
Normal file
259
pandatool/src/egg-palettize/paletteGroup.cxx
Normal file
@ -0,0 +1,259 @@
|
||||
// Filename: paletteGroup.cxx
|
||||
// Created by: drose (06Nov00)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "paletteGroup.h"
|
||||
#include "texturePacking.h"
|
||||
#include "palette.h"
|
||||
#include "attribFile.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PaletteGroup::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PaletteGroup::
|
||||
PaletteGroup(const string &name) : Namable(name)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PaletteGroup::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PaletteGroup::
|
||||
~PaletteGroup() {
|
||||
clear_palettes();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PaletteGroup::get_num_parents
|
||||
// Access: Public
|
||||
// Description: Returns the number of dependent PaletteGroup this
|
||||
// PaletteGroup can share its textures with. See
|
||||
// get_parent().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int PaletteGroup::
|
||||
get_num_parents() const {
|
||||
return _parents.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PaletteGroup::get_parent
|
||||
// Access: Public
|
||||
// Description: Returns the nth dependent PaletteGroup this
|
||||
// PaletteGroup can share its textures with. If a
|
||||
// texture is added to this group that already appears
|
||||
// one of these groups, the reference to the shared
|
||||
// texture is used instead of adding a new texture.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PaletteGroup *PaletteGroup::
|
||||
get_parent(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_parents.size(), (PaletteGroup *)NULL);
|
||||
return _parents[n];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PaletteGroup::add_parent
|
||||
// Access: Public
|
||||
// Description: Adds a new PaletteGroup to the set of PaletteGroups
|
||||
// this one can share its textures with. See
|
||||
// get_parent().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PaletteGroup::
|
||||
add_parent(PaletteGroup *parent) {
|
||||
_parents.push_back(parent);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PaletteGroup::pack_texture
|
||||
// Access: Public
|
||||
// Description: Adds the texture to some suitable palette image
|
||||
// within the PaletteGroup. Returns true if
|
||||
// successfully packed, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PaletteGroup::
|
||||
pack_texture(TexturePacking *packing, AttribFile *attrib_file) {
|
||||
// Now try to place it in each of our existing palettes.
|
||||
Palettes::iterator pi;
|
||||
for (pi = _palettes.begin(); pi != _palettes.end(); ++pi) {
|
||||
if ((*pi)->pack_texture(packing)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// It didn't place anywhere; create a new palette for it.
|
||||
Palette *palette =
|
||||
new Palette(this, _palettes.size() + 1,
|
||||
attrib_file->_pal_xsize, attrib_file->_pal_ysize,
|
||||
0, attrib_file);
|
||||
if (!palette->pack_texture(packing)) {
|
||||
// Hmm, it didn't fit on an empty palette. Must be too big.
|
||||
packing->set_omit(OR_size);
|
||||
delete palette;
|
||||
return false;
|
||||
}
|
||||
_palettes.push_back(palette);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PaletteGroup::generate_palette_images
|
||||
// Access: Public
|
||||
// Description: After all of the textures has been placed, generates
|
||||
// the actual image files for each palette image within
|
||||
// the group. Returns true if successful, false on
|
||||
// error.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PaletteGroup::
|
||||
generate_palette_images() {
|
||||
bool okflag = true;
|
||||
|
||||
Palettes::iterator pi;
|
||||
for (pi = _palettes.begin(); pi != _palettes.end(); ++pi) {
|
||||
Palette *palette = (*pi);
|
||||
if (palette->new_palette()) {
|
||||
// If the palette is a new palette, we'll have to generate a new
|
||||
// image from scratch.
|
||||
okflag = palette->generate_image() && okflag;
|
||||
} else {
|
||||
// Otherwise, we can probably get by with just updating
|
||||
// whichever images, if any, have changed.
|
||||
okflag = palette->refresh_image() && okflag;
|
||||
}
|
||||
}
|
||||
|
||||
return okflag;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PaletteGroup::optimal_resize
|
||||
// Access: Public
|
||||
// Description: Resizes each palette image within the group downward,
|
||||
// if possible, to the smallest power-of-two size that
|
||||
// holds all of its images.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PaletteGroup::
|
||||
optimal_resize() {
|
||||
Palettes::iterator pi;
|
||||
for (pi = _palettes.begin(); pi != _palettes.end(); ++pi) {
|
||||
(*pi)->optimal_resize();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PaletteGroup::finalize_palettes
|
||||
// Access: Public
|
||||
// Description: Performs some finalization of the palette images,
|
||||
// such as generating filenames.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PaletteGroup::
|
||||
finalize_palettes() {
|
||||
Palettes::iterator pi;
|
||||
for (pi = _palettes.begin(); pi != _palettes.end(); ++pi) {
|
||||
(*pi)->finalize_palette();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PaletteGroup::add_palette
|
||||
// Access: Public
|
||||
// Description: Adds the indicated already-created Palette image to
|
||||
// the group. This is mainly intended to be called from
|
||||
// AttribFile when reading in a previously-built .pi
|
||||
// file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PaletteGroup::
|
||||
add_palette(Palette *palette) {
|
||||
_palettes.push_back(palette);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PaletteGroup::remove_palette_files
|
||||
// Access: Public
|
||||
// Description: Removes all the image files generated for the Palette
|
||||
// images within the group.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PaletteGroup::
|
||||
remove_palette_files() {
|
||||
Palettes::iterator pi;
|
||||
for (pi = _palettes.begin(); pi != _palettes.end(); ++pi) {
|
||||
// Remove the old palette file?
|
||||
Palette *palette = *pi;
|
||||
if (!palette->get_filename().empty()) {
|
||||
if (palette->get_filename().exists()) {
|
||||
nout << "Deleting " << palette->get_filename() << "\n";
|
||||
palette->get_filename().unlink();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PaletteGroup::clear_palettes
|
||||
// Access: Public
|
||||
// Description: Deletes all of the Palette objects within the group.
|
||||
// This loses all information about where textures are
|
||||
// packed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PaletteGroup::
|
||||
clear_palettes() {
|
||||
Palettes::iterator pi;
|
||||
for (pi = _palettes.begin(); pi != _palettes.end(); ++pi) {
|
||||
delete *pi;
|
||||
}
|
||||
_palettes.clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PaletteGroup::complete_groups
|
||||
// Access: Public, Static
|
||||
// Description: Expands the set of PaletteGroups to include all
|
||||
// parents and parents of parents.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PaletteGroup::
|
||||
complete_groups(PaletteGroups &groups) {
|
||||
// Make a copy so we can safely modify the original set as we
|
||||
// traverse the copy.
|
||||
PaletteGroups groups_copy = groups;
|
||||
PaletteGroups::const_iterator gi;
|
||||
for (gi = groups_copy.begin(); gi != groups_copy.end(); ++gi) {
|
||||
(*gi)->add_ancestors(groups);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PaletteGroup::add_ancestors
|
||||
// Access: Public
|
||||
// Description: Adds all the ancestors of this PaletteGroup to the
|
||||
// indicated set.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PaletteGroup::
|
||||
add_ancestors(PaletteGroups &groups) {
|
||||
Parents::const_iterator pri;
|
||||
for (pri = _parents.begin(); pri != _parents.end(); ++pri) {
|
||||
PaletteGroup *parent = *pri;
|
||||
bool inserted = groups.insert(parent).second;
|
||||
if (inserted) {
|
||||
parent->add_ancestors(groups);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PaletteGroup::write
|
||||
// Access: Public
|
||||
// Description: Writes out a .pi file description of the palette
|
||||
// group and all of its nested Palette images.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PaletteGroup::
|
||||
write(ostream &out) const {
|
||||
Palettes::const_iterator pi;
|
||||
for (pi = _palettes.begin(); pi != _palettes.end(); ++pi) {
|
||||
out << "\n";
|
||||
(*pi)->write(out);
|
||||
}
|
||||
}
|
79
pandatool/src/egg-palettize/paletteGroup.h
Normal file
79
pandatool/src/egg-palettize/paletteGroup.h
Normal file
@ -0,0 +1,79 @@
|
||||
// Filename: paletteGroup.h
|
||||
// Created by: drose (06Nov00)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef PALETTEGROUP_H
|
||||
#define PALETTEGROUP_H
|
||||
|
||||
#include <pandatoolbase.h>
|
||||
|
||||
#include <namable.h>
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
class Palette;
|
||||
class TexturePacking;
|
||||
class AttribFile;
|
||||
class PaletteGroup;
|
||||
|
||||
typedef set<PaletteGroup *> PaletteGroups;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : PaletteGroup
|
||||
// Description : A named collection of textures. This is a group of
|
||||
// textures that are to be palettized together as a
|
||||
// unit; all of these textures are expected to be loaded
|
||||
// into texture memory at one time. The PaletteGroup
|
||||
// consists of a number of discrete Palette images, as
|
||||
// many as are necessary to represent all of the
|
||||
// textures within the PaletteGroup that are to be
|
||||
// palettized.
|
||||
//
|
||||
// A PaletteGroup is also associated with one or more
|
||||
// other PaletteGroups, which are assumed to be
|
||||
// available in texture memory whenever this
|
||||
// PaletteGroup is. If a texture is to be placed on
|
||||
// this PaletteGroup that already exists on one of the
|
||||
// dependent PaletteGroups, it is not placed; instead,
|
||||
// it is referenced directly from the other
|
||||
// PaletteGroup. This allows an intelligent sharing of
|
||||
// textures between palettes with a minimum of wasted
|
||||
// space.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class PaletteGroup : public Namable {
|
||||
public:
|
||||
PaletteGroup(const string &name);
|
||||
~PaletteGroup();
|
||||
|
||||
int get_num_parents() const;
|
||||
PaletteGroup *get_parent(int n) const;
|
||||
void add_parent(PaletteGroup *parent);
|
||||
|
||||
bool pack_texture(TexturePacking *packing, AttribFile *attrib_file);
|
||||
bool generate_palette_images();
|
||||
void optimal_resize();
|
||||
void finalize_palettes();
|
||||
|
||||
void add_palette(Palette *palette);
|
||||
|
||||
void remove_palette_files();
|
||||
void clear_palettes();
|
||||
|
||||
static void complete_groups(PaletteGroups &groups);
|
||||
void add_ancestors(PaletteGroups &groups);
|
||||
|
||||
void write(ostream &out) const;
|
||||
|
||||
private:
|
||||
typedef vector<PaletteGroup *> Parents;
|
||||
Parents _parents;
|
||||
|
||||
typedef vector<Palette *> Palettes;
|
||||
Palettes _palettes;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -5,6 +5,9 @@
|
||||
|
||||
#include "sourceEgg.h"
|
||||
#include "pTexture.h"
|
||||
#include "textureEggRef.h"
|
||||
#include "texturePacking.h"
|
||||
#include "paletteGroup.h"
|
||||
#include "eggPalettize.h"
|
||||
#include "string_utils.h"
|
||||
#include "palette.h"
|
||||
@ -14,30 +17,52 @@
|
||||
#include <eggNurbsSurface.h>
|
||||
#include <eggPrimitive.h>
|
||||
#include <eggTextureCollection.h>
|
||||
#include <eggAlphaMode.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
TypeHandle SourceEgg::_type_handle;
|
||||
|
||||
SourceEgg::TextureRef::
|
||||
TextureRef(PTexture *texture, bool repeats, bool alpha) :
|
||||
_texture(texture),
|
||||
_repeats(repeats),
|
||||
_alpha(alpha)
|
||||
{
|
||||
_eggtex = NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SourceEgg::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
SourceEgg::
|
||||
SourceEgg() {
|
||||
SourceEgg(AttribFile *attrib_file) : _attrib_file(attrib_file) {
|
||||
_matched_anything = false;
|
||||
}
|
||||
|
||||
SourceEgg::TextureRef &SourceEgg::
|
||||
add_texture(PTexture *texture, bool repeats, bool alpha) {
|
||||
_texrefs.push_back(TextureRef(texture, repeats, alpha));
|
||||
return _texrefs.back();
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SourceEgg::add_texture
|
||||
// Access: Public
|
||||
// Description: Adds a new texture to the set of textures known by
|
||||
// the egg file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
TextureEggRef *SourceEgg::
|
||||
add_texture(PTexture *texture, TexturePacking *packing,
|
||||
bool repeats, bool alpha) {
|
||||
TextureEggRef *ref =
|
||||
new TextureEggRef(this, texture, packing, repeats, alpha);
|
||||
_texrefs.insert(ref);
|
||||
texture->_eggs.insert(ref);
|
||||
return ref;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SourceEgg::get_textures
|
||||
// Access: Public
|
||||
// Description: Examines the egg file for all of the texture
|
||||
// references and assigns each texture to a suitable
|
||||
// palette group.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SourceEgg::
|
||||
get_textures(AttribFile &af, EggPalettize *prog) {
|
||||
get_textures(EggPalettize *prog) {
|
||||
TexRefs::iterator tri;
|
||||
for (tri = _texrefs.begin(); tri != _texrefs.end(); ++tri) {
|
||||
TextureEggRef *texref = (*tri);
|
||||
texref->_texture->_eggs.erase(texref);
|
||||
}
|
||||
_texrefs.clear();
|
||||
|
||||
EggTextureCollection tc;
|
||||
@ -48,20 +73,9 @@ get_textures(AttribFile &af, EggPalettize *prog) {
|
||||
EggTexture *eggtex = (*ti);
|
||||
string name = eggtex->get_basename();
|
||||
|
||||
PTexture *texture = af.get_texture(name);
|
||||
PTexture *texture = _attrib_file->get_texture(name);
|
||||
texture->add_filename(*eggtex);
|
||||
|
||||
if (prog->_dont_palettize) {
|
||||
// If the user specified -x, it means to omit all textures
|
||||
// processed in this run, forever.
|
||||
texture->set_omit(PTexture::OR_cmdline);
|
||||
} else {
|
||||
// Or until we next see it without -x.
|
||||
if (texture->get_omit() == PTexture::OR_cmdline) {
|
||||
texture->set_omit(PTexture::OR_none);
|
||||
}
|
||||
}
|
||||
|
||||
bool repeats =
|
||||
eggtex->get_wrap_mode() == EggTexture::WM_repeat ||
|
||||
eggtex->get_wrap_u() == EggTexture::WM_repeat ||
|
||||
@ -72,7 +86,21 @@ get_textures(AttribFile &af, EggPalettize *prog) {
|
||||
eggtex->get_wrap_u() == EggTexture::WM_unspecified &&
|
||||
eggtex->get_wrap_v() == EggTexture::WM_unspecified;
|
||||
|
||||
bool alpha = true; //eggtex->uses_alpha();
|
||||
bool alpha = false;
|
||||
|
||||
EggAlphaMode::AlphaMode alpha_mode = eggtex->get_alpha_mode();
|
||||
if (alpha_mode == EggAlphaMode::AM_unspecified) {
|
||||
int xsize, ysize, zsize;
|
||||
if (texture->get_size(xsize, ysize, zsize)) {
|
||||
alpha = eggtex->has_alpha_channel(zsize);
|
||||
}
|
||||
|
||||
} else if (alpha_mode == EggAlphaMode::AM_off) {
|
||||
alpha = false;
|
||||
|
||||
} else {
|
||||
alpha = true;
|
||||
}
|
||||
|
||||
// Check the range of UV's actually used within the egg file.
|
||||
bool any_uvs = false;
|
||||
@ -153,48 +181,94 @@ get_textures(AttribFile &af, EggPalettize *prog) {
|
||||
}
|
||||
}
|
||||
|
||||
TextureRef &texref = add_texture(texture, repeats, alpha);
|
||||
texref._eggtex = eggtex;
|
||||
TextureEggRef *texref = add_texture(texture, (TexturePacking *)NULL,
|
||||
repeats, alpha);
|
||||
texref->_eggtex = eggtex;
|
||||
}
|
||||
}
|
||||
|
||||
// Updates each PTexture with the flags stored in the various egg
|
||||
// files. Also marks textures as used.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SourceEgg::require_groups
|
||||
// Access: Public
|
||||
// Description: Ensures that each texture in the egg file is packed
|
||||
// into at least one of the indicated groups.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SourceEgg::
|
||||
require_groups(PaletteGroup *preferred, const PaletteGroups &groups) {
|
||||
TexRefs::iterator ti;
|
||||
for (ti = _texrefs.begin(); ti != _texrefs.end(); ++ti) {
|
||||
(*ti)->require_groups(preferred, groups);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SourceEgg::all_textures_assigned
|
||||
// Access: Public
|
||||
// Description: Ensures that each texture in the egg file is packed
|
||||
// into at least one group, any group.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SourceEgg::
|
||||
all_textures_assigned() {
|
||||
TexRefs::iterator ti;
|
||||
for (ti = _texrefs.begin(); ti != _texrefs.end(); ++ti) {
|
||||
TextureEggRef *texref = (*ti);
|
||||
if (texref->_packing == (TexturePacking *)NULL) {
|
||||
texref->_packing =
|
||||
texref->_texture->add_to_group(_attrib_file->get_default_group());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SourceEgg::mark_texture_flags
|
||||
// Access: Public
|
||||
// Description: Updates each PTexture with the flags stored in the
|
||||
// various egg files. Also marks textures as used.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SourceEgg::
|
||||
mark_texture_flags() {
|
||||
TexRefs::iterator ti;
|
||||
for (ti = _texrefs.begin(); ti != _texrefs.end(); ++ti) {
|
||||
PTexture *texture = (*ti)._texture;
|
||||
texture->set_unused(false);
|
||||
if ((*ti)._alpha) {
|
||||
texture->set_uses_alpha(true);
|
||||
TexturePacking *packing = (*ti)->_packing;
|
||||
packing->set_unused(false);
|
||||
if ((*ti)->_alpha) {
|
||||
packing->set_uses_alpha(true);
|
||||
}
|
||||
if ((*ti)._repeats) {
|
||||
texture->set_omit(PTexture::OR_repeats);
|
||||
if ((*ti)->_repeats) {
|
||||
packing->set_omit(OR_repeats);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Updates the egg file to point to the new palettes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SourceEgg::update_trefs
|
||||
// Access: Public
|
||||
// Description: Updates the egg file to point to the new palettes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SourceEgg::
|
||||
update_trefs() {
|
||||
TexRefs::iterator ti;
|
||||
for (ti = _texrefs.begin(); ti != _texrefs.end(); ++ti) {
|
||||
PTexture *texture = (*ti)._texture;
|
||||
EggTexture *eggtex = (*ti)._eggtex;
|
||||
TexturePacking *packing = (*ti)->_packing;
|
||||
PTexture *texture = packing->get_texture();
|
||||
EggTexture *eggtex = (*ti)->_eggtex;
|
||||
|
||||
if (eggtex != NULL) {
|
||||
// Make the alpha mode explicit if it isn't already.
|
||||
|
||||
/*
|
||||
if (eggtex->get_alpha_mode == EggTexture::AM_unspecified) {
|
||||
eggtex->set_alpha = eggtex->UsesAlpha() ?
|
||||
EggTexture::AM_on : EggTexture::AM_off;
|
||||
if (eggtex->get_alpha_mode() == EggTexture::AM_unspecified) {
|
||||
int xsize, ysize, zsize;
|
||||
if (texture->get_size(xsize, ysize, zsize)) {
|
||||
if (eggtex->has_alpha_channel(zsize)) {
|
||||
eggtex->set_alpha_mode(EggAlphaMode::AM_on);
|
||||
} else {
|
||||
eggtex->set_alpha_mode(EggAlphaMode::AM_off);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if (!texture->is_packed() ||
|
||||
texture->get_omit() != PTexture::OR_none) {
|
||||
if (!packing->is_packed() ||
|
||||
packing->get_omit() != OR_none) {
|
||||
// This texture wasn't palettized, so just rename the
|
||||
// reference to the new one.
|
||||
eggtex->set_fullpath(texture->get_filename());
|
||||
@ -202,7 +276,7 @@ update_trefs() {
|
||||
} else {
|
||||
// This texture was palettized, so redirect the tref to point
|
||||
// within the palette.
|
||||
Palette *palette = texture->get_palette();
|
||||
Palette *palette = packing->get_palette();
|
||||
|
||||
eggtex->set_fullpath(palette->get_filename());
|
||||
|
||||
@ -217,8 +291,8 @@ update_trefs() {
|
||||
// Build a matrix that will scale the UV's to their new place
|
||||
// on the palette.
|
||||
int left, top, xsize, ysize, margin;
|
||||
texture->get_packed_location(left, top);
|
||||
texture->get_packed_size(xsize, ysize, margin);
|
||||
packing->get_packed_location(left, top);
|
||||
packing->get_packed_size(xsize, ysize, margin);
|
||||
|
||||
// Shrink the box to be within the margins.
|
||||
top += margin;
|
||||
@ -254,9 +328,14 @@ update_trefs() {
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if any of the textures referenced by the egg file have
|
||||
// been adjusted this pass, implying that the egg file will have to be
|
||||
// re-run through egg-palettize, and/or re-pfb'ed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SourceEgg::needs_rebuild
|
||||
// Access: Public
|
||||
// Description: Returns true if any of the textures referenced by the
|
||||
// egg file have been adjusted this pass, implying that
|
||||
// the egg file will have to be re-run through
|
||||
// egg-palettize, and/or re-pfb'ed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool SourceEgg::
|
||||
needs_rebuild(bool force_redo_all,
|
||||
bool eggs_include_images) const {
|
||||
@ -265,8 +344,8 @@ needs_rebuild(bool force_redo_all,
|
||||
for (ti = _texrefs.begin(); ti != _texrefs.end(); ++ti) {
|
||||
bool dirty =
|
||||
eggs_include_images ?
|
||||
(*ti)._texture->needs_refresh() :
|
||||
(*ti)._texture->packing_changed();
|
||||
(*ti)->_packing->needs_refresh() :
|
||||
(*ti)->_packing->packing_changed();
|
||||
if (force_redo_all || dirty) {
|
||||
return true;
|
||||
}
|
||||
@ -276,22 +355,57 @@ needs_rebuild(bool force_redo_all,
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SourceEgg::matched_anything
|
||||
// Access: Public
|
||||
// Description: Returns true if the egg file matched at least one
|
||||
// line in the .txa file, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool SourceEgg::
|
||||
matched_anything() const {
|
||||
return _matched_anything;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SourceEgg::set_matched_anything
|
||||
// Access: Public
|
||||
// Description: Sets the state of the matched_anything flag. See
|
||||
// matched_anything().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SourceEgg::
|
||||
set_matched_anything(bool matched_anything) {
|
||||
_matched_anything = matched_anything;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SourceEgg::write_pi
|
||||
// Access: Public
|
||||
// Description: Writes the entry for this egg file to the .pi file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SourceEgg::
|
||||
write_pi(ostream &out) const {
|
||||
out << "egg " << get_egg_filename() << "\n";
|
||||
TexRefs::const_iterator ti;
|
||||
for (ti = _texrefs.begin(); ti != _texrefs.end(); ++ti) {
|
||||
out << " " << (*ti)._texture->get_name();
|
||||
if ((*ti)._repeats) {
|
||||
out << " " << (*ti)->_packing->get_texture()->get_name()
|
||||
<< " in " << (*ti)->_packing->get_group()->get_name();
|
||||
if ((*ti)->_repeats) {
|
||||
out << " repeats";
|
||||
}
|
||||
if ((*ti)._alpha) {
|
||||
if ((*ti)->_alpha) {
|
||||
out << " alpha";
|
||||
}
|
||||
out << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SourceEgg::get_uv_range
|
||||
// Access: Private
|
||||
// Description: Checks the geometry in the egg file to see what range
|
||||
// of UV's are requested for this particular texture
|
||||
// reference.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SourceEgg::
|
||||
get_uv_range(EggGroupNode *group, EggTexture *tref,
|
||||
bool &any_uvs, TexCoordd &min_uv, TexCoordd &max_uv) {
|
||||
|
@ -8,24 +8,28 @@
|
||||
|
||||
#include <pandatoolbase.h>
|
||||
|
||||
#include "paletteGroup.h"
|
||||
|
||||
#include <eggData.h>
|
||||
#include <luse.h>
|
||||
|
||||
|
||||
class PTexture;
|
||||
class TexturePacking;
|
||||
class AttribFile;
|
||||
class EggPalettize;
|
||||
class EggTexture;
|
||||
class EggGroup;
|
||||
class TextureEggRef;
|
||||
|
||||
class SourceEgg : public EggData {
|
||||
public:
|
||||
class TextureRef;
|
||||
SourceEgg(AttribFile *attrib_file);
|
||||
|
||||
SourceEgg();
|
||||
|
||||
TextureRef &add_texture(PTexture *texture, bool repeats, bool alpha);
|
||||
void get_textures(AttribFile &af, EggPalettize *prog);
|
||||
TextureEggRef *add_texture(PTexture *texture, TexturePacking *packing,
|
||||
bool repeats, bool alpha);
|
||||
void get_textures(EggPalettize *prog);
|
||||
void require_groups(PaletteGroup *preferred, const PaletteGroups &groups);
|
||||
void all_textures_assigned();
|
||||
|
||||
void mark_texture_flags();
|
||||
void update_trefs();
|
||||
@ -33,26 +37,22 @@ public:
|
||||
bool needs_rebuild(bool force_redo_all,
|
||||
bool eggs_include_images) const;
|
||||
|
||||
bool matched_anything() const;
|
||||
void set_matched_anything(bool matched_anything);
|
||||
|
||||
void write_pi(ostream &out) const;
|
||||
|
||||
|
||||
class TextureRef {
|
||||
public:
|
||||
TextureRef(PTexture *texture, bool repeats, bool alpha);
|
||||
|
||||
PTexture *_texture;
|
||||
bool _repeats;
|
||||
bool _alpha;
|
||||
|
||||
EggTexture *_eggtex;
|
||||
};
|
||||
typedef set<TextureEggRef *> TexRefs;
|
||||
TexRefs _texrefs;
|
||||
|
||||
private:
|
||||
void get_uv_range(EggGroupNode *group, EggTexture *tref,
|
||||
bool &any_uvs, TexCoordd &min_uv, TexCoordd &max_uv);
|
||||
|
||||
typedef vector<TextureRef> TexRefs;
|
||||
TexRefs _texrefs;
|
||||
|
||||
AttribFile *_attrib_file;
|
||||
bool _matched_anything;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
|
69
pandatool/src/egg-palettize/textureEggRef.cxx
Normal file
69
pandatool/src/egg-palettize/textureEggRef.cxx
Normal file
@ -0,0 +1,69 @@
|
||||
// Filename: textureEggRef.cxx
|
||||
// Created by: drose (08Nov00)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "textureEggRef.h"
|
||||
#include "texturePacking.h"
|
||||
#include "pTexture.h"
|
||||
|
||||
#include <notify.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TextureEggRef::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
TextureEggRef::
|
||||
TextureEggRef(SourceEgg *egg, PTexture *texture, TexturePacking *packing,
|
||||
bool repeats, bool alpha) :
|
||||
_egg(egg),
|
||||
_texture(texture),
|
||||
_packing(packing),
|
||||
_repeats(repeats),
|
||||
_alpha(alpha)
|
||||
{
|
||||
_eggtex = NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TextureEggRef::require_groups
|
||||
// Access: Public
|
||||
// Description: Indicates the set of PaletteGroups that this texture
|
||||
// (as appearing on this egg file) wants to be listed
|
||||
// on. If the texture is already listed on one of these
|
||||
// groups, does nothing; otherwise, moves the texture.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TextureEggRef::
|
||||
require_groups(PaletteGroup *preferred, const PaletteGroups &groups) {
|
||||
nassertv(!groups.empty());
|
||||
|
||||
if (_packing != (TexturePacking *)NULL) {
|
||||
PaletteGroup *now_on = _packing->get_group();
|
||||
if (groups.count(now_on) != 0) {
|
||||
// The group we're on is on the list; no problem.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Has the texture already been packed into any of the groups?
|
||||
PaletteGroups::const_iterator gi;
|
||||
for (gi = groups.begin(); gi != groups.end(); ++gi) {
|
||||
TexturePacking *packing = _texture->check_group(*gi);
|
||||
if (packing != (TexturePacking *)NULL) {
|
||||
// It has, use that group.
|
||||
_packing = packing;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We need to pack the texture into one of the requested groups.
|
||||
|
||||
// For now, we arbitrarily pick the preferred group. Later, maybe
|
||||
// we'll try to be smart about this and do some kind of graph
|
||||
// minimization to choose the group the leads to the least redundant
|
||||
// packing.
|
||||
_packing = _texture->add_to_group(preferred);
|
||||
}
|
43
pandatool/src/egg-palettize/textureEggRef.h
Normal file
43
pandatool/src/egg-palettize/textureEggRef.h
Normal file
@ -0,0 +1,43 @@
|
||||
// Filename: textureEggRef.h
|
||||
// Created by: drose (08Nov00)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef TEXTUREEGGREF_H
|
||||
#define TEXTUREEGGREF_H
|
||||
|
||||
#include <pandatoolbase.h>
|
||||
|
||||
#include "paletteGroup.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class SourceEgg;
|
||||
class PTexture;
|
||||
class TexturePacking;
|
||||
class EggTexture;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : TextureEggRef
|
||||
// Description : This associates a texture with the egg files it is
|
||||
// placed on, and also associated an egg file with the
|
||||
// various textures it contains.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class TextureEggRef {
|
||||
public:
|
||||
TextureEggRef(SourceEgg *egg, PTexture *texture,
|
||||
TexturePacking *packing,
|
||||
bool repeats, bool alpha);
|
||||
|
||||
void require_groups(PaletteGroup *preferred, const PaletteGroups &groups);
|
||||
|
||||
SourceEgg *_egg;
|
||||
PTexture *_texture;
|
||||
TexturePacking *_packing;
|
||||
bool _repeats;
|
||||
bool _alpha;
|
||||
|
||||
EggTexture *_eggtex;
|
||||
};
|
||||
|
||||
#endif
|
26
pandatool/src/egg-palettize/textureOmitReason.h
Normal file
26
pandatool/src/egg-palettize/textureOmitReason.h
Normal file
@ -0,0 +1,26 @@
|
||||
// Filename: textureOmitReason.h
|
||||
// Created by: drose (06Nov00)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef TEXTUREOMITREASON_H
|
||||
#define TEXTUREOMITREASON_H
|
||||
|
||||
#include <pandatoolbase.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Enum : TextureOmitReason
|
||||
// Description : This enumerates the various reasons a texture might
|
||||
// have been omitted from a palette.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
enum TextureOmitReason {
|
||||
OR_none, // No reason: not omitted
|
||||
OR_size, // Too big to put on a palette
|
||||
OR_repeats, // The texture repeats and can't be palettized
|
||||
OR_omitted, // Explicitly omitted by user in .txa file
|
||||
OR_unused, // Not used by any egg files
|
||||
OR_unknown, // The texture file is unknown, so can't determine its size
|
||||
OR_solitary // Would be palettized, but no other textures are on the palette.
|
||||
};
|
||||
|
||||
#endif
|
463
pandatool/src/egg-palettize/texturePacking.cxx
Normal file
463
pandatool/src/egg-palettize/texturePacking.cxx
Normal file
@ -0,0 +1,463 @@
|
||||
// Filename: texturePacking.cxx
|
||||
// Created by: drose (06Nov00)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "texturePacking.h"
|
||||
#include "paletteGroup.h"
|
||||
#include "attribFile.h"
|
||||
#include "palette.h"
|
||||
#include "pTexture.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TexturePacking::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
TexturePacking::
|
||||
TexturePacking(PTexture *texture, PaletteGroup *group) :
|
||||
_texture(texture),
|
||||
_group(group)
|
||||
{
|
||||
_attrib_file = _texture->_attrib_file;
|
||||
_omit = _texture->_omit ? OR_omitted : OR_none;
|
||||
_unused = true;
|
||||
_uses_alpha = false;
|
||||
_is_packed = false;
|
||||
_palette = NULL;
|
||||
_packing_changed = false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TexturePacking::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
TexturePacking::
|
||||
~TexturePacking() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TexturePacking::get_texture
|
||||
// Access: Public
|
||||
// Description: Returns the texture this TexturePacking object refers
|
||||
// to.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PTexture *TexturePacking::
|
||||
get_texture() const {
|
||||
return _texture;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TexturePacking::get_group
|
||||
// Access: Public
|
||||
// Description: Returns the palette group this TexturePacking object
|
||||
// refers to.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PaletteGroup *TexturePacking::
|
||||
get_group() const {
|
||||
return _group;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TexturePacking::get_omit
|
||||
// Access: Public
|
||||
// Description: Returns the reason this texture was omitted from the
|
||||
// particular palette group, if it was.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
TextureOmitReason TexturePacking::
|
||||
get_omit() const {
|
||||
return _omit;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TexturePacking::set_omit
|
||||
// Access: Public
|
||||
// Description: Indicates the reason this texture was omitted from
|
||||
// the particular palette group, if it was.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TexturePacking::
|
||||
set_omit(TextureOmitReason omit) {
|
||||
_omit = omit;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TexturePacking::unused
|
||||
// Access: Public
|
||||
// Description: Returns true if this particular texture/group
|
||||
// combination seems to be unused by any egg files,
|
||||
// false if at least one egg file uses it.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool TexturePacking::
|
||||
unused() const {
|
||||
return _unused;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TexturePacking::set_unused
|
||||
// Access: Public
|
||||
// Description: Sets the state of the unused flag. See unused().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TexturePacking::
|
||||
set_unused(bool unused) {
|
||||
_unused = unused;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TexturePacking::uses_alpha
|
||||
// Access: Public
|
||||
// Description: Returns true if this texture seems to require alpha;
|
||||
// that is, at least one egg file that references the
|
||||
// texture specifies an alpha mode.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool TexturePacking::
|
||||
uses_alpha() const {
|
||||
return _uses_alpha;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TexturePacking::set_uses_alpha
|
||||
// Access: Public
|
||||
// Description: Sets the state of the uses_alpha flag. See
|
||||
// uses_alpha().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TexturePacking::
|
||||
set_uses_alpha(bool uses_alpha) {
|
||||
_uses_alpha = uses_alpha;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TexturePacking::pack
|
||||
// Access: Public
|
||||
// Description: Adds this texture to its appropriate palette group,
|
||||
// if it has not already been packed. Returns true if
|
||||
// anything has changed (e.g. it has been packed), false
|
||||
// otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool TexturePacking::
|
||||
pack() {
|
||||
if (!_is_packed) {
|
||||
return _group->pack_texture(this, _attrib_file);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TexturePacking::unpack
|
||||
// Access: Public
|
||||
// Description: Removes this texture from its palette image if it is
|
||||
// on one. Returns true if anything has changed
|
||||
// (e.g. it has been unpacked), false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool TexturePacking::
|
||||
unpack() {
|
||||
if (_is_packed) {
|
||||
return _palette->unpack_texture(this);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TexturePacking::prepare_repack
|
||||
// Access: Public
|
||||
// Description: Checks if the texture needs to be repacked into a
|
||||
// different location on the palette (for instance,
|
||||
// because it has changed size). If so, unpacks it and
|
||||
// returns true; otherwise, leaves it alone and returns
|
||||
// false.
|
||||
//
|
||||
// If unpacking it will leave a hole or some similar
|
||||
// nonsense, also sets optimal to false.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool TexturePacking::
|
||||
prepare_repack(bool &optimal) {
|
||||
bool needs_repack = false;
|
||||
|
||||
if (get_omit() == OR_none) {
|
||||
// Here's a texture that thinks it wants to be packed. Does it?
|
||||
int xsize, ysize;
|
||||
int pal_xsize = _attrib_file->_pal_xsize;
|
||||
int pal_ysize = _attrib_file->_pal_ysize;
|
||||
if (!_texture->get_req(xsize, ysize)) {
|
||||
// If we don't know the texture's size, we can't place it.
|
||||
nout << "Warning! Can't determine size of " << _texture->get_name()
|
||||
<< "\n";
|
||||
set_omit(OR_unknown);
|
||||
|
||||
} else if ((xsize > pal_xsize || ysize > pal_ysize) ||
|
||||
(xsize == pal_xsize && ysize == pal_ysize)) {
|
||||
// If the texture is too big for the palette (or exactly fills the
|
||||
// palette), we can't place it.
|
||||
set_omit(OR_size);
|
||||
|
||||
} else {
|
||||
// Ok, this texture really does want to be packed. Is it?
|
||||
int px, py, m;
|
||||
if (get_packed_size(px, py, m)) {
|
||||
// The texture is packed. Does it have the right size?
|
||||
if (px != xsize || py != ysize) {
|
||||
// Oops, we'll have to repack it.
|
||||
unpack();
|
||||
optimal = false;
|
||||
needs_repack = true;
|
||||
}
|
||||
if (m != _texture->get_margin()) {
|
||||
// The margin has changed, although not the size. We
|
||||
// won't have to repack it, but we do need to update it.
|
||||
_texture->set_changed(true);
|
||||
}
|
||||
} else {
|
||||
// The texture isn't packed. Need to pack it.
|
||||
needs_repack = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (get_omit() != OR_none) {
|
||||
// Here's a texture that doesn't want to be packed. Is it?
|
||||
if (unpack()) {
|
||||
// It was! Not any more.
|
||||
optimal = false;
|
||||
}
|
||||
}
|
||||
|
||||
return needs_repack;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TexturePacking::mark_pack_location
|
||||
// Access: Public
|
||||
// Description: Records the location at which the texture has been
|
||||
// packed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TexturePacking::
|
||||
mark_pack_location(Palette *palette, int left, int top,
|
||||
int xsize, int ysize, int margin) {
|
||||
_is_packed = true;
|
||||
_palette = palette;
|
||||
_pleft = left;
|
||||
_ptop = top;
|
||||
_pxsize = xsize;
|
||||
_pysize = ysize;
|
||||
_pmargin = margin;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TexturePacking::mark_unpacked
|
||||
// Access: Public
|
||||
// Description: Records that the texture has not been packed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TexturePacking::
|
||||
mark_unpacked() {
|
||||
_is_packed = false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TexturePacking::is_packed
|
||||
// Access: Public
|
||||
// Description: Returns true if the texture has been packed, false
|
||||
// otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool TexturePacking::
|
||||
is_packed() const {
|
||||
return _is_packed;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TexturePacking::is_really_packed
|
||||
// Access: Public
|
||||
// Description: Returns the same thing as is_packed(), except it
|
||||
// doesn't consider a texture that has been left alone
|
||||
// on a palette to be packed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool TexturePacking::
|
||||
is_really_packed() const {
|
||||
return _is_packed && _omit != OR_solitary;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TexturePacking::get_palette
|
||||
// Access: Public
|
||||
// Description: Returns the particular palette image the texture has
|
||||
// been packed into, or NULL if the texture is unpacked.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
Palette *TexturePacking::
|
||||
get_palette() const {
|
||||
return _is_packed ? _palette : (Palette *)NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TexturePacking::get_packed_location
|
||||
// Access: Public
|
||||
// Description: Fills left and top with the upper-left corner of the
|
||||
// rectangle in which the texture has been packed within
|
||||
// its Palette image. Returns true if the texture has
|
||||
// been packed, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool TexturePacking::
|
||||
get_packed_location(int &left, int &top) const {
|
||||
left = _pleft;
|
||||
top = _ptop;
|
||||
return _is_packed;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TexturePacking::get_packed_size
|
||||
// Access: Public
|
||||
// Description: Fills xsize, ysize, and margin with the size of the
|
||||
// rectangle in which the texture has been packed within
|
||||
// its Palette image. The margin is an interior margin.
|
||||
// Returns true if the texture has been packed, false
|
||||
// otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool TexturePacking::
|
||||
get_packed_size(int &xsize, int &ysize, int &margin) const {
|
||||
xsize = _pxsize;
|
||||
ysize = _pysize;
|
||||
margin = _pmargin;
|
||||
return _is_packed;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TexturePacking::record_orig_state
|
||||
// Access: Public
|
||||
// Description: Records the current packing state, storing it aside
|
||||
// as the state at load time. Later, when the packing
|
||||
// state may have changed, packing_changed() will return
|
||||
// true if it has or false if it has not.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TexturePacking::
|
||||
record_orig_state() {
|
||||
_orig_is_packed = _is_packed;
|
||||
if (_is_packed) {
|
||||
_orig_palette_name = _palette->get_filename();
|
||||
_opleft = _pleft;
|
||||
_optop = _ptop;
|
||||
_opxsize = _pxsize;
|
||||
_opysize = _pysize;
|
||||
_opmargin = _pmargin;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TexturePacking::packing_changed
|
||||
// Access: Public
|
||||
// Description: Returns true if the packing has changed in any way
|
||||
// since the last call to record_orig_state(), false
|
||||
// otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool TexturePacking::
|
||||
packing_changed() const {
|
||||
if (_orig_is_packed != _is_packed) {
|
||||
return true;
|
||||
}
|
||||
if (_is_packed) {
|
||||
return _orig_palette_name != _palette->get_filename() ||
|
||||
_opleft != _pleft ||
|
||||
_optop != _ptop ||
|
||||
_opxsize != _pxsize ||
|
||||
_opysize != _pysize ||
|
||||
_opmargin != _pmargin;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TexturePacking::set_changed
|
||||
// Access: Public
|
||||
// Description: Sets the state of the changed flag. If this is true,
|
||||
// the state of this texture on this group is known to
|
||||
// have changed in some way such that files that depend
|
||||
// on it will need to be rebuilt.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TexturePacking::
|
||||
set_changed(bool changed) {
|
||||
_packing_changed = changed;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TexturePacking::needs_refresh
|
||||
// Access: Public
|
||||
// Description: Returns true if the texture has changed in any
|
||||
// significant way and the palette it's placed on needs
|
||||
// to be regenerated.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool TexturePacking::
|
||||
needs_refresh() {
|
||||
bool any_change =
|
||||
_texture->_texture_changed || _packing_changed;
|
||||
|
||||
if (!any_change) {
|
||||
// We consider the texture to be out-of-date if it's moved around
|
||||
// in the palette.
|
||||
any_change = packing_changed();
|
||||
}
|
||||
|
||||
if (!any_change && _texture->_file_exists) {
|
||||
// Compare the texture's timestamp to that of its palette (or
|
||||
// resized copy). If it's newer, it's changed and must be
|
||||
// replaced.
|
||||
|
||||
Filename target_filename;
|
||||
if (is_packed() && _omit == OR_none) {
|
||||
// Compare to the palette file.
|
||||
target_filename = _palette->get_filename();
|
||||
if (_palette->new_palette()) {
|
||||
// It's a brand new palette; don't even bother comparing
|
||||
// timestamps.
|
||||
any_change = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Compare to the resized file.
|
||||
target_filename = _texture->get_filename();
|
||||
}
|
||||
|
||||
if (!any_change) {
|
||||
any_change =
|
||||
(target_filename.compare_timestamps(_texture->_filename, true, false) < 0);
|
||||
}
|
||||
}
|
||||
|
||||
return any_change;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TexturePacking::write_unplaced
|
||||
// Access: Public
|
||||
// Description: Writes an "unplaced" entry to the .pi file if this
|
||||
// texture has not been placed on the group, describing
|
||||
// the reason for the failure.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TexturePacking::
|
||||
write_unplaced(ostream &out) const {
|
||||
if (_omit != OR_none && _omit != OR_unused) {
|
||||
out << "unplaced " << _texture->get_name()
|
||||
<< " in " << _group->get_name() << " because ";
|
||||
switch (_omit) {
|
||||
case OR_size:
|
||||
out << "size";
|
||||
break;
|
||||
case OR_repeats:
|
||||
out << "repeats";
|
||||
break;
|
||||
case OR_omitted:
|
||||
out << "omitted";
|
||||
break;
|
||||
case OR_unused:
|
||||
out << "unused";
|
||||
break;
|
||||
case OR_unknown:
|
||||
out << "unknown";
|
||||
break;
|
||||
case OR_solitary:
|
||||
out << "solitary";
|
||||
break;
|
||||
default:
|
||||
nout << "Invalid type: " << (int)_omit << "\n";
|
||||
abort();
|
||||
}
|
||||
out << "\n";
|
||||
}
|
||||
}
|
82
pandatool/src/egg-palettize/texturePacking.h
Normal file
82
pandatool/src/egg-palettize/texturePacking.h
Normal file
@ -0,0 +1,82 @@
|
||||
// Filename: texturePacking.h
|
||||
// Created by: drose (06Nov00)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef TEXTUREPACKING_H
|
||||
#define TEXTUREPACKING_H
|
||||
|
||||
#include <pandatoolbase.h>
|
||||
|
||||
#include "textureOmitReason.h"
|
||||
|
||||
#include <filename.h>
|
||||
|
||||
class PTexture;
|
||||
class PaletteGroup;
|
||||
class Palette;
|
||||
class AttribFile;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : TexturePacking
|
||||
// Description : This structure defines how a particular texture is
|
||||
// packed into a Palette image, or even whether it is
|
||||
// packed at all.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class TexturePacking {
|
||||
public:
|
||||
TexturePacking(PTexture *texture, PaletteGroup *group);
|
||||
~TexturePacking();
|
||||
|
||||
PTexture *get_texture() const;
|
||||
PaletteGroup *get_group() const;
|
||||
|
||||
TextureOmitReason get_omit() const;
|
||||
void set_omit(TextureOmitReason omit);
|
||||
|
||||
bool unused() const;
|
||||
void set_unused(bool unused);
|
||||
|
||||
bool uses_alpha() const;
|
||||
void set_uses_alpha(bool uses_alpha);
|
||||
|
||||
bool pack();
|
||||
bool unpack();
|
||||
bool prepare_repack(bool &optimal);
|
||||
|
||||
void mark_pack_location(Palette *palette, int left, int top,
|
||||
int xsize, int ysize, int margin);
|
||||
void mark_unpacked();
|
||||
bool is_packed() const;
|
||||
bool is_really_packed() const;
|
||||
Palette *get_palette() const;
|
||||
bool get_packed_location(int &left, int &top) const;
|
||||
bool get_packed_size(int &xsize, int &ysize, int &margin) const;
|
||||
void record_orig_state();
|
||||
bool packing_changed() const;
|
||||
|
||||
void set_changed(bool changed);
|
||||
bool needs_refresh();
|
||||
|
||||
void write_unplaced(ostream &out) const;
|
||||
|
||||
private:
|
||||
AttribFile *_attrib_file;
|
||||
PTexture *_texture;
|
||||
PaletteGroup *_group;
|
||||
TextureOmitReason _omit;
|
||||
bool _unused;
|
||||
bool _uses_alpha;
|
||||
|
||||
bool _is_packed;
|
||||
Palette *_palette;
|
||||
int _pleft, _ptop, _pxsize, _pysize, _pmargin;
|
||||
|
||||
bool _orig_is_packed;
|
||||
Filename _orig_palette_name;
|
||||
int _opleft, _optop, _opxsize, _opysize, _opmargin;
|
||||
|
||||
bool _packing_changed;
|
||||
};
|
||||
|
||||
#endif
|
@ -6,16 +6,14 @@
|
||||
#include "userAttribLine.h"
|
||||
#include "string_utils.h"
|
||||
#include "pTexture.h"
|
||||
#include "paletteGroup.h"
|
||||
#include "sourceEgg.h"
|
||||
#include "attribFile.h"
|
||||
#include "textureEggRef.h"
|
||||
|
||||
#include <notify.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <fnmatch.h>
|
||||
|
||||
UserAttribLine::TextureName::
|
||||
TextureName(const string &pattern) : _pattern(pattern) {
|
||||
}
|
||||
|
||||
UserAttribLine::
|
||||
UserAttribLine(const string &cline, AttribFile *af) : _attrib_file(af) {
|
||||
@ -91,6 +89,8 @@ was_used() const {
|
||||
|
||||
void UserAttribLine::
|
||||
write(ostream &out) const {
|
||||
int i;
|
||||
|
||||
switch (_line_type) {
|
||||
case LT_invalid:
|
||||
out << "*** invalid line ***\n";
|
||||
@ -107,8 +107,16 @@ write(ostream &out) const {
|
||||
out << ":palette " << _xsize << " " << _ysize;
|
||||
break;
|
||||
|
||||
case LT_group_relate:
|
||||
out << ":group " << _names[0] << " with";
|
||||
for (i = 1; i < (int)_names.size(); i++) {
|
||||
out << " " << _names[i];
|
||||
}
|
||||
out << "\n";
|
||||
break;
|
||||
|
||||
case LT_size:
|
||||
list_textures(out) << " : " << _xsize << " " << _ysize;
|
||||
list_patterns(out) << " : " << _xsize << " " << _ysize;
|
||||
if (_msize > 0) {
|
||||
out << " " << _msize;
|
||||
}
|
||||
@ -118,7 +126,7 @@ write(ostream &out) const {
|
||||
break;
|
||||
|
||||
case LT_scale:
|
||||
list_textures(out) << " : " << _scale_pct << "%";
|
||||
list_patterns(out) << " : " << _scale_pct << "%";
|
||||
if (_msize > 0) {
|
||||
out << " " << _msize;
|
||||
}
|
||||
@ -128,12 +136,17 @@ write(ostream &out) const {
|
||||
break;
|
||||
|
||||
case LT_name:
|
||||
list_textures(out) << " :";
|
||||
list_patterns(out) << " :";
|
||||
if (_omit) {
|
||||
out << " omit";
|
||||
}
|
||||
break;
|
||||
|
||||
case LT_group_assign:
|
||||
list_patterns(out) << " : ";
|
||||
list_names(out);
|
||||
break;
|
||||
|
||||
default:
|
||||
nout << "Unexpected type: " << (int)_line_type << "\n";
|
||||
abort();
|
||||
@ -143,17 +156,36 @@ write(ostream &out) const {
|
||||
}
|
||||
|
||||
bool UserAttribLine::
|
||||
match_texture(PTexture *texture, int &margin) {
|
||||
get_size_request(PTexture *texture, int &margin) {
|
||||
if (_line_type == LT_group_assign) {
|
||||
// We don't care about group lines for the size check.
|
||||
return false;
|
||||
}
|
||||
|
||||
// See if the texture name matches any of the filename patterns on
|
||||
// this line.
|
||||
string texture_name = texture->get_name();
|
||||
|
||||
bool matched_any = false;
|
||||
TextureNames::const_iterator tni;
|
||||
for (tni = _texture_names.begin();
|
||||
tni != _texture_names.end() && !matched_any;
|
||||
++tni) {
|
||||
if (fnmatch((*tni)._pattern.c_str(), texture->get_name().c_str(), 0) == 0) {
|
||||
Patterns::const_iterator pi;
|
||||
for (pi = _patterns.begin();
|
||||
pi != _patterns.end() && !matched_any;
|
||||
++pi) {
|
||||
if ((*pi).matches(texture_name)) {
|
||||
matched_any = true;
|
||||
}
|
||||
|
||||
// Also check if it matches any of the egg files this texture is
|
||||
// on.
|
||||
PTexture::Eggs::const_iterator ei;
|
||||
for (ei = texture->_eggs.begin();
|
||||
ei != texture->_eggs.end() && !matched_any;
|
||||
++ei) {
|
||||
string egg_name = (*ei)->_egg->get_egg_filename().get_basename();
|
||||
if ((*pi).matches(egg_name)) {
|
||||
matched_any = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (matched_any) {
|
||||
@ -164,6 +196,7 @@ match_texture(PTexture *texture, int &margin) {
|
||||
case LT_invalid:
|
||||
case LT_comment:
|
||||
case LT_palette:
|
||||
case LT_group_relate:
|
||||
return false;
|
||||
|
||||
case LT_margin:
|
||||
@ -174,7 +207,7 @@ match_texture(PTexture *texture, int &margin) {
|
||||
texture->reset_req(_xsize, _ysize);
|
||||
texture->set_margin(_msize < 0 ? margin : _msize);
|
||||
if (_omit) {
|
||||
texture->set_omit(PTexture::OR_omitted);
|
||||
texture->user_omit();
|
||||
}
|
||||
return true;
|
||||
|
||||
@ -182,13 +215,13 @@ match_texture(PTexture *texture, int &margin) {
|
||||
texture->scale_req(_scale_pct);
|
||||
texture->set_margin(_msize < 0 ? margin : _msize);
|
||||
if (_omit) {
|
||||
texture->set_omit(PTexture::OR_omitted);
|
||||
texture->user_omit();
|
||||
}
|
||||
return true;
|
||||
|
||||
case LT_name:
|
||||
if (_omit) {
|
||||
texture->set_omit(PTexture::OR_omitted);
|
||||
texture->user_omit();
|
||||
}
|
||||
return true;
|
||||
|
||||
@ -201,12 +234,73 @@ match_texture(PTexture *texture, int &margin) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UserAttribLine::
|
||||
get_group_request(SourceEgg *egg) {
|
||||
if (_line_type != LT_group_assign) {
|
||||
// We're only looking for group lines now.
|
||||
return false;
|
||||
}
|
||||
|
||||
// See if the egg filename matches any of the filename patterns on
|
||||
// this line.
|
||||
string egg_name = egg->get_egg_filename().get_basename();
|
||||
|
||||
bool matched_any = false;
|
||||
Patterns::const_iterator pi;
|
||||
for (pi = _patterns.begin();
|
||||
pi != _patterns.end() && !matched_any;
|
||||
++pi) {
|
||||
if ((*pi).matches(egg_name)) {
|
||||
matched_any = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (matched_any) {
|
||||
_was_used = true;
|
||||
|
||||
// It does! Record the list of required groups with all of the
|
||||
// textures on this egg file.
|
||||
nassertr(!_names.empty(), false);
|
||||
PaletteGroups groups;
|
||||
Names::const_iterator ni = _names.begin();
|
||||
PaletteGroup *group = _attrib_file->get_group(*ni);
|
||||
groups.insert(group);
|
||||
|
||||
// The first-named group is preferred for any textures not already
|
||||
// on another group.
|
||||
PaletteGroup *preferred = group;
|
||||
|
||||
while (ni != _names.end()) {
|
||||
group = _attrib_file->get_group(*ni);
|
||||
groups.insert(group);
|
||||
++ni;
|
||||
}
|
||||
PaletteGroup::complete_groups(groups);
|
||||
egg->require_groups(preferred, groups);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ostream &UserAttribLine::
|
||||
list_textures(ostream &out) const {
|
||||
if (!_texture_names.empty()) {
|
||||
out << _texture_names[0]._pattern;
|
||||
for (int i = 1; i < (int)_texture_names.size(); i++) {
|
||||
out << " " << _texture_names[i]._pattern;
|
||||
list_patterns(ostream &out) const {
|
||||
if (!_patterns.empty()) {
|
||||
out << _patterns[0];
|
||||
for (int i = 1; i < (int)_patterns.size(); i++) {
|
||||
out << " " << _patterns[i];
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
ostream &UserAttribLine::
|
||||
list_names(ostream &out) const {
|
||||
if (!_names.empty()) {
|
||||
out << _names[0];
|
||||
for (int i = 1; i < (int)_names.size(); i++) {
|
||||
out << " " << _names[i];
|
||||
}
|
||||
}
|
||||
return out;
|
||||
@ -229,7 +323,7 @@ keyword_line(const string &line) {
|
||||
} else if (words[0] == ":palette") {
|
||||
_line_type = LT_palette;
|
||||
if (words.size() != 3) {
|
||||
nout << "Expected xsize ysize of palette.\n";
|
||||
nout << "Expected :palette xsize ysize.\n";
|
||||
return false;
|
||||
}
|
||||
_xsize = atoi(words[1].c_str());
|
||||
@ -237,6 +331,18 @@ keyword_line(const string &line) {
|
||||
_attrib_file->_pal_xsize = _xsize;
|
||||
_attrib_file->_pal_ysize = _ysize;
|
||||
|
||||
} else if (words[0] == ":group") {
|
||||
_line_type = LT_group_relate;
|
||||
if (words.size() < 4 || !(words[2] == "with")) {
|
||||
nout << "Expected :group groupname with groupname [groupname ...].\n";
|
||||
return false;
|
||||
}
|
||||
PaletteGroup *group = _attrib_file->get_group(words[1]);
|
||||
|
||||
for (int i = 3; i < (int)words.size(); i++) {
|
||||
group->add_parent(_attrib_file->get_group(words[i]));
|
||||
}
|
||||
|
||||
} else {
|
||||
nout << "Unknown keyword: " << words[0] << "\n";
|
||||
return false;
|
||||
@ -262,7 +368,7 @@ texture_line(const string &line) {
|
||||
|
||||
vector<string>::const_iterator ni;
|
||||
for (ni = names.begin(); ni != names.end(); ++ni) {
|
||||
_texture_names.push_back(TextureName(*ni));
|
||||
_patterns.push_back(GlobPattern(*ni));
|
||||
}
|
||||
|
||||
if (!params.empty() && params[params.size() - 1] == "omit") {
|
||||
@ -277,6 +383,14 @@ texture_line(const string &line) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Is it a group name? If it is, this is an assignment of a texture
|
||||
// or egg file to one or more groups.
|
||||
if (!params[0].empty() && isalpha(params[0][0])) {
|
||||
_names = params;
|
||||
_line_type = LT_group_assign;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Is it a percentage?
|
||||
if (!params[0].empty() && params[0][params[0].size() - 1] == '%') {
|
||||
_line_type = LT_scale;
|
||||
@ -335,7 +449,7 @@ old_style_line(const string &line) {
|
||||
|
||||
_is_old_style = true;
|
||||
_line_type = LT_size;
|
||||
_texture_names.push_back(TextureName(words[0]));
|
||||
_patterns.push_back(GlobPattern(words[0]));
|
||||
_xsize = atoi(words[1].c_str());
|
||||
_ysize = atoi(words[2].c_str());
|
||||
if (words.size() > 3) {
|
||||
|
@ -8,16 +8,18 @@
|
||||
|
||||
#include <pandatoolbase.h>
|
||||
|
||||
#include <globPattern.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
class AttribFile;
|
||||
class PTexture;
|
||||
class SourceEgg;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : UserAttribLine
|
||||
// Description : A single entry in the user part (the beginning) of
|
||||
// the attrib file, this defines how the user would like
|
||||
// some particular texture to be scaled.
|
||||
// Description : A single entry in the .txa file, this defines how the
|
||||
// user would like some particular texture to be scaled.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
//
|
||||
@ -27,10 +29,13 @@ class PTexture;
|
||||
// # Comment
|
||||
// :margin msize
|
||||
// :palette xsize ysize
|
||||
// :group groupname with groupname [groupname ...]
|
||||
// texturename xsize ysize msize
|
||||
// texturename [texturename ...] : xsize ysize [msize] [omit]
|
||||
// texturename [texturename ...] : scale% [msize] [omit]
|
||||
// texturename [texturename ...] : [omit]
|
||||
// texturename [texturename ...] : groupname [groupname ...]
|
||||
// eggname [eggname ...] : groupname [groupname ...]
|
||||
//
|
||||
|
||||
class UserAttribLine {
|
||||
@ -44,28 +49,25 @@ public:
|
||||
|
||||
void write(ostream &out) const;
|
||||
|
||||
bool match_texture(PTexture *texture, int &margin);
|
||||
bool get_size_request(PTexture *texture, int &margin);
|
||||
bool get_group_request(SourceEgg *egg);
|
||||
|
||||
private:
|
||||
enum LineType {
|
||||
LT_invalid,
|
||||
LT_comment,
|
||||
LT_margin, LT_palette,
|
||||
LT_size, LT_scale, LT_name
|
||||
};
|
||||
class TextureName {
|
||||
public:
|
||||
TextureName(const string &pattern);
|
||||
TextureName(const TextureName ©) :
|
||||
_pattern(copy._pattern) { }
|
||||
|
||||
string _pattern;
|
||||
LT_margin, LT_palette, LT_group_relate,
|
||||
LT_size, LT_scale, LT_name,
|
||||
LT_group_assign
|
||||
};
|
||||
|
||||
typedef vector<TextureName> TextureNames;
|
||||
TextureNames _texture_names;
|
||||
typedef vector<GlobPattern> Patterns;
|
||||
Patterns _patterns;
|
||||
typedef vector<string> Names;
|
||||
Names _names;
|
||||
|
||||
ostream &list_textures(ostream &out) const;
|
||||
ostream &list_patterns(ostream &out) const;
|
||||
ostream &list_names(ostream &out) const;
|
||||
bool keyword_line(const string &line);
|
||||
bool texture_line(const string &line);
|
||||
bool old_style_line(const string &line);
|
||||
|
Loading…
x
Reference in New Issue
Block a user