*** empty log message ***

This commit is contained in:
David Rose 2000-12-06 04:51:13 +00:00
parent 60f7913ab9
commit 07a1bca3a0
30 changed files with 1484 additions and 179 deletions

View File

@ -102,11 +102,13 @@ write_data(xel *array, xelval *) {
*/
cinfo.image_width = _x_size; /* image width and height, in pixels */
cinfo.image_height = _y_size;
if (is_grayscale())
if (is_grayscale()) {
cinfo.input_components = 1;
else
cinfo.in_color_space = JCS_GRAYSCALE;
} else {
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
cinfo.in_color_space = JCS_RGB;
}
/* Now use the library's routine to set default compression parameters.
* (You must set at least cinfo.in_color_space before calling this,
* since the defaults depend on the source color space.)

View File

@ -9,7 +9,9 @@
#define SOURCES \
config_egg_palettize.cxx config_egg_palettize.h \
destTextureImage.cxx destTextureImage.h \
eggFile.cxx eggFile.h eggPalettize.cxx eggPalettize.h \
filenameUnifier.cxx filenameUnifier.h \
imageFile.cxx imageFile.h omitReason.cxx omitReason.h \
paletteGroup.h paletteGroup.cxx \
paletteGroups.h paletteGroups.cxx paletteImage.h paletteImage.cxx \

View File

@ -12,6 +12,7 @@
#include "textureProperties.h"
#include "imageFile.h"
#include "sourceTextureImage.h"
#include "destTextureImage.h"
#include "textureImage.h"
#include "paletteImage.h"
#include "texturePlacement.h"
@ -31,6 +32,7 @@ ConfigureFn(config_egg_palettize) {
TextureProperties::init_type();
ImageFile::init_type();
SourceTextureImage::init_type();
DestTextureImage::init_type();
TextureImage::init_type();
PaletteImage::init_type();
TexturePlacement::init_type();
@ -46,6 +48,7 @@ ConfigureFn(config_egg_palettize) {
TextureReference::register_with_read_factory();
TextureProperties::register_with_read_factory();
SourceTextureImage::register_with_read_factory();
DestTextureImage::register_with_read_factory();
TextureImage::register_with_read_factory();
PaletteImage::register_with_read_factory();
TexturePlacement::register_with_read_factory();

View File

@ -0,0 +1,126 @@
// Filename: destTextureImage.cxx
// Created by: drose (05Dec00)
//
////////////////////////////////////////////////////////////////////
#include "destTextureImage.h"
#include "texturePlacement.h"
#include "textureImage.h"
#include <datagram.h>
#include <datagramIterator.h>
#include <bamReader.h>
#include <bamWriter.h>
TypeHandle DestTextureImage::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: DestTextureImage::Default Constructor
// Access: Private
// Description: The default constructor is only for the convenience
// of the Bam reader.
////////////////////////////////////////////////////////////////////
DestTextureImage::
DestTextureImage() {
}
////////////////////////////////////////////////////////////////////
// Function: DestTextureImage::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
DestTextureImage::
DestTextureImage(TexturePlacement *placement) {
TextureImage *texture = placement->get_texture();
_properties = texture->get_properties();
_size_known = true;
_x_size = texture->get_x_size();
_y_size = texture->get_y_size();
set_filename(placement->get_group(), texture->get_name());
}
////////////////////////////////////////////////////////////////////
// Function: DestTextureImage::copy
// Access: Public
// Description: Unconditionally copies the source texture into the
// appropriate filename.
////////////////////////////////////////////////////////////////////
void DestTextureImage::
copy(TextureImage *texture) {
PNMImage image = texture->get_dest_image();
write(image);
}
////////////////////////////////////////////////////////////////////
// Function: DestTextureImage::copy_if_stale
// Access: Public
// Description: Copies the source texture into the appropriate
// filename only if the indicated old reference, which
// represents the way it was last copied, is now
// out-of-date.
////////////////////////////////////////////////////////////////////
void DestTextureImage::
copy_if_stale(const DestTextureImage *other, TextureImage *texture) {
if (other->get_x_size() != get_x_size() ||
other->get_y_size() != get_y_size() ||
other->get_num_channels() != get_num_channels()) {
copy(texture);
}
}
////////////////////////////////////////////////////////////////////
// Function: DestTextureImage::register_with_read_factory
// Access: Public, Static
// Description: Registers the current object as something that can be
// read from a Bam file.
////////////////////////////////////////////////////////////////////
void DestTextureImage::
register_with_read_factory() {
BamReader::get_factory()->
register_factory(get_class_type(), make_DestTextureImage);
}
////////////////////////////////////////////////////////////////////
// Function: DestTextureImage::write_datagram
// Access: Public, Virtual
// Description: Fills the indicated datagram up with a binary
// representation of the current object, in preparation
// for writing to a Bam file.
////////////////////////////////////////////////////////////////////
void DestTextureImage::
write_datagram(BamWriter *writer, Datagram &datagram) {
ImageFile::write_datagram(writer, datagram);
}
////////////////////////////////////////////////////////////////////
// Function: DestTextureImage::make_DestTextureImage
// Access: Protected
// Description: This method is called by the BamReader when an object
// of this type is encountered in a Bam file; it should
// allocate and return a new object with all the data
// read.
////////////////////////////////////////////////////////////////////
TypedWriteable* DestTextureImage::
make_DestTextureImage(const FactoryParams &params) {
DestTextureImage *me = new DestTextureImage;
BamReader *manager;
Datagram packet;
parse_params(params, manager, packet);
DatagramIterator scan(packet);
me->fillin(scan, manager);
return me;
}
////////////////////////////////////////////////////////////////////
// Function: DestTextureImage::fillin
// Access: Protected
// Description: Reads the binary data from the given datagram
// iterator, which was written by a previous call to
// write_datagram().
////////////////////////////////////////////////////////////////////
void DestTextureImage::
fillin(DatagramIterator &scan, BamReader *manager) {
ImageFile::fillin(scan, manager);
}

View File

@ -0,0 +1,65 @@
// Filename: destTextureImage.h
// Created by: drose (05Dec00)
//
////////////////////////////////////////////////////////////////////
#ifndef DESTTEXTUREIMAGE_H
#define DESTTEXTUREIMAGE_H
#include <pandatoolbase.h>
#include "imageFile.h"
class TexturePlacement;
class TextureImage;
////////////////////////////////////////////////////////////////////
// Class : DestTextureImage
// Description : This represents a texture filename as it has been
// resized and copied to the map directory (e.g. for an
// unplaced texture).
////////////////////////////////////////////////////////////////////
class DestTextureImage : public ImageFile {
private:
DestTextureImage();
public:
DestTextureImage(TexturePlacement *placement);
void copy(TextureImage *texture);
void copy_if_stale(const DestTextureImage *other, TextureImage *texture);
// The TypedWriteable interface follows.
public:
static void register_with_read_factory();
virtual void write_datagram(BamWriter *writer, Datagram &datagram);
protected:
static TypedWriteable *make_DestTextureImage(const FactoryParams &params);
void fillin(DatagramIterator &scan, BamReader *manager);
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
ImageFile::init_type();
register_type(_type_handle, "DestTextureImage",
ImageFile::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
private:
static TypeHandle _type_handle;
};
INLINE ostream &
operator << (ostream &out, const DestTextureImage &dest) {
dest.output_filename(out);
return out;
}
#endif

View File

@ -8,6 +8,7 @@
#include "paletteGroup.h"
#include "texturePlacement.h"
#include "palettizer.h"
#include "filenameUnifier.h"
#include <eggData.h>
#include <eggTextureCollection.h>
@ -26,6 +27,10 @@ TypeHandle EggFile::_type_handle;
EggFile::
EggFile() {
_data = (EggData *)NULL;
_default_group = (PaletteGroup *)NULL;
_is_surprise = true;
_is_stale = true;
_first_txa_match = false;
}
////////////////////////////////////////////////////////////////////
@ -41,6 +46,11 @@ from_command_line(EggData *data,
_data = data;
_source_filename = source_filename;
_dest_filename = dest_filename;
// We save the default PaletteGroup at this point, because the egg
// file inherits the default group that was in effect when it was
// specified on the command line.
_default_group = pal->get_default_group();
}
////////////////////////////////////////////////////////////////////
@ -70,7 +80,7 @@ scan_textures() {
EggTexture *egg_tex = (*eti);
TextureReference *ref = new TextureReference;
ref->from_egg(_data, egg_tex);
ref->from_egg(this, _data, egg_tex);
_textures.push_back(ref);
}
@ -93,6 +103,39 @@ get_textures(set<TextureImage *> &result) const {
}
}
////////////////////////////////////////////////////////////////////
// Function: EggFile::pre_txa_file
// Access: Public
// Description: Does some processing prior to scanning the .txa file.
////////////////////////////////////////////////////////////////////
void EggFile::
pre_txa_file() {
_is_surprise = true;
_first_txa_match = true;
}
////////////////////////////////////////////////////////////////////
// Function: EggFile::match_txa_groups
// Access: Public
// Description: Adds the indicated set of groups, read from the .txa
// file, to the set of groups to which the egg file is
// assigned.
////////////////////////////////////////////////////////////////////
void EggFile::
match_txa_groups(const PaletteGroups &groups) {
if (_first_txa_match) {
// If this is the first line we matched in the .txa file, clear
// the set of groups we'd matched from before. We don't clear
// until we match a line in the .txa file, because if we don't
// match any lines we still want to remember what groups we used
// to be assigned to.
_explicitly_assigned_groups.clear();
_first_txa_match = false;
}
_explicitly_assigned_groups.make_union(_explicitly_assigned_groups, groups);
}
////////////////////////////////////////////////////////////////////
// Function: EggFile::post_txa_file
// Access: Public
@ -102,22 +145,90 @@ get_textures(set<TextureImage *> &result) const {
////////////////////////////////////////////////////////////////////
void EggFile::
post_txa_file() {
if (_assigned_groups.empty()) {
// If the egg file has been assigned to no groups, we have to
// assign it to something.
_assigned_groups.insert(pal->get_default_group());
}
}
////////////////////////////////////////////////////////////////////
// Function: EggFile::get_groups
// Function: EggFile::get_explicit_groups
// Access: Public
// Description: Returns the set of PaletteGroups that the egg file
// has been explicitly assigned to in the .txa file.
////////////////////////////////////////////////////////////////////
const PaletteGroups &EggFile::
get_groups() const {
return _assigned_groups;
get_explicit_groups() const {
return _explicitly_assigned_groups;
}
////////////////////////////////////////////////////////////////////
// Function: EggFile::get_default_group
// Access: Public
// Description: Returns the PaletteGroup that was specified as the
// default group on the command line at the time the egg
// file last appeared on the command line.
////////////////////////////////////////////////////////////////////
PaletteGroup *EggFile::
get_default_group() const {
return _default_group;
}
////////////////////////////////////////////////////////////////////
// Function: EggFile::get_complete_groups
// Access: Public
// Description: Returns the complete set of PaletteGroups that the
// egg file is assigned to. This is the set of all the
// groups it is explicitly assigned to, plus all the
// groups that these groups depend on.
////////////////////////////////////////////////////////////////////
const PaletteGroups &EggFile::
get_complete_groups() const {
return _complete_groups;
}
////////////////////////////////////////////////////////////////////
// Function: EggFile::clear_surprise
// Access: Public
// Description: Removes the 'surprise' flag; this file has been
// successfully matched against a line in the .txa file.
////////////////////////////////////////////////////////////////////
void EggFile::
clear_surprise() {
_is_surprise = false;
}
////////////////////////////////////////////////////////////////////
// Function: EggFile::is_surprise
// Access: Public
// Description: Returns true if this particular egg file is a
// 'surprise', i.e. it wasn't matched by a line in the
// .txa file that didn't include the keyword 'cont'.
////////////////////////////////////////////////////////////////////
bool EggFile::
is_surprise() const {
return _is_surprise;
}
////////////////////////////////////////////////////////////////////
// Function: EggFile::mark_stale
// Access: Public
// Description: Marks this particular egg file as stale, meaning that
// something has changed, such as the location of a
// texture within its palette, which causes the egg file
// to need to be regenerated.
////////////////////////////////////////////////////////////////////
void EggFile::
mark_stale() {
_is_stale = true;
}
////////////////////////////////////////////////////////////////////
// Function: EggFile::is_stale
// Access: Public
// Description: Returns true if the egg file needs to be updated,
// i.e. some palettizations have changed affecting it,
// or false otherwise.
////////////////////////////////////////////////////////////////////
bool EggFile::
is_stale() const {
return _is_stale;
}
////////////////////////////////////////////////////////////////////
@ -132,16 +243,25 @@ get_groups() const {
////////////////////////////////////////////////////////////////////
void EggFile::
build_cross_links() {
if (_explicitly_assigned_groups.empty()) {
// If the egg file has been assigned to no groups, we have to
// assign it to something.
_complete_groups.clear();
_complete_groups.insert(_default_group);
_complete_groups.make_complete(_complete_groups);
} else {
_complete_groups.make_complete(_explicitly_assigned_groups);
}
Textures::const_iterator ti;
for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
(*ti)->get_texture()->note_egg_file(this);
}
_assigned_groups.make_complete(_assigned_groups);
PaletteGroups::const_iterator gi;
for (gi = _assigned_groups.begin();
gi != _assigned_groups.end();
for (gi = _complete_groups.begin();
gi != _complete_groups.end();
++gi) {
(*gi)->increment_egg_count();
}
@ -174,7 +294,7 @@ choose_placements() {
} else {
// We need to select a new TexturePlacement.
PaletteGroups groups;
groups.make_intersection(get_groups(), texture->get_groups());
groups.make_intersection(get_complete_groups(), texture->get_groups());
// Now groups is the set of groups that the egg file requires,
// which also happen to include the texture. It better not be
@ -195,6 +315,17 @@ choose_placements() {
}
}
////////////////////////////////////////////////////////////////////
// Function: EggFile::has_data
// Access: Public
// Description: Returns true if the EggData for this EggFile has ever
// been loaded.
////////////////////////////////////////////////////////////////////
bool EggFile::
has_data() const {
return (_data != (EggData *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: EggFile::update_egg
// Access: Public
@ -211,6 +342,88 @@ update_egg() {
}
}
////////////////////////////////////////////////////////////////////
// Function: EggFile::read_egg
// Access: Public
// Description: Reads in the egg file from its _source_filename. It
// is only valid to call this if it has not already been
// read in, e.g. from the command line. Returns true if
// successful, false if there is an error.
////////////////////////////////////////////////////////////////////
bool EggFile::
read_egg() {
nassertr(_data == (EggData *)NULL, false);
nassertr(!_source_filename.empty(), false);
if (!_source_filename.exists()) {
nout << _source_filename << " does not exist.\n";
return false;
}
EggData *data = new EggData;
if (!data->read(_source_filename)) {
// Failure reading.
delete data;
return false;
}
if (!data->resolve_externals()) {
// Failure reading an external.
delete data;
return false;
}
_data = data;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: EggFile::write_egg
// Access: Public
// Description: Writes out the egg file to its _dest_filename.
// Returns true if successful, false if there is an
// error.
////////////////////////////////////////////////////////////////////
bool EggFile::
write_egg() {
nassertr(_data != (EggData *)NULL, false);
nassertr(!_dest_filename.empty(), false);
_dest_filename.make_dir();
nout << "Writing " << _dest_filename << "\n";
if (!_data->write_egg(_dest_filename)) {
// Some error while writing. Most unusual.
_is_stale = true;
return false;
}
_is_stale = false;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: EggFile::write_description
// Access: Public
// Description: Writes a one-line description of the egg file and its
// group assignments to the indicated output stream.
////////////////////////////////////////////////////////////////////
void EggFile::
write_description(ostream &out, int indent_level) const {
indent(out, indent_level) << get_name() << ": ";
if (_explicitly_assigned_groups.empty()) {
if (_default_group != (PaletteGroup *)NULL) {
out << _default_group->get_name();
}
} else {
out << _explicitly_assigned_groups;
}
if (is_stale()) {
out << " (needs update)";
}
out << "\n";
}
////////////////////////////////////////////////////////////////////
// Function: EggFile::write_texture_refs
// Access: Public
@ -251,8 +464,8 @@ write_datagram(BamWriter *writer, Datagram &datagram) {
// We don't write out _data; that needs to be reread each session.
datagram.add_string(_source_filename);
datagram.add_string(_dest_filename);
datagram.add_string(FilenameUnifier::make_bam_filename(_source_filename));
datagram.add_string(FilenameUnifier::make_bam_filename(_dest_filename));
datagram.add_uint32(_textures.size());
Textures::iterator ti;
@ -260,7 +473,14 @@ write_datagram(BamWriter *writer, Datagram &datagram) {
writer->write_pointer(datagram, (*ti));
}
_assigned_groups.write_datagram(writer, datagram);
_explicitly_assigned_groups.write_datagram(writer, datagram);
writer->write_pointer(datagram, _default_group);
// We don't write out _complete_groups; that is recomputed each
// session.
datagram.add_bool(_is_surprise);
datagram.add_bool(_is_stale);
}
////////////////////////////////////////////////////////////////////
@ -274,7 +494,7 @@ write_datagram(BamWriter *writer, Datagram &datagram) {
////////////////////////////////////////////////////////////////////
int EggFile::
complete_pointers(vector_typedWriteable &plist, BamReader *manager) {
nassertr((int)plist.size() >= _num_textures, 0);
nassertr((int)plist.size() >= _num_textures + 1, 0);
int index = 0;
int i;
@ -286,6 +506,11 @@ complete_pointers(vector_typedWriteable &plist, BamReader *manager) {
index++;
}
if (plist[index] != (TypedWriteable *)NULL) {
DCAST_INTO_R(_default_group, plist[index], index);
}
index++;
return index;
}
@ -320,11 +545,15 @@ make_EggFile(const FactoryParams &params) {
void EggFile::
fillin(DatagramIterator &scan, BamReader *manager) {
set_name(scan.get_string());
_source_filename = scan.get_string();
_dest_filename = scan.get_string();
_source_filename = FilenameUnifier::get_bam_filename(scan.get_string());
_dest_filename = FilenameUnifier::get_bam_filename(scan.get_string());
_num_textures = scan.get_uint32();
manager->read_pointers(scan, this, _num_textures);
_assigned_groups.fillin(scan, manager);
_explicitly_assigned_groups.fillin(scan, manager);
manager->read_pointer(scan, this); // _default_group
_is_surprise = scan.get_bool();
_is_stale = scan.get_bool();
}

View File

@ -40,15 +40,29 @@ public:
void scan_textures();
void get_textures(set<TextureImage *> &result) const;
void pre_txa_file();
void match_txa_groups(const PaletteGroups &groups);
void post_txa_file();
const PaletteGroups &get_groups() const;
const PaletteGroups &get_explicit_groups() const;
PaletteGroup *get_default_group() const;
const PaletteGroups &get_complete_groups() const;
void clear_surprise();
bool is_surprise() const;
void mark_stale();
bool is_stale() const;
void build_cross_links();
void choose_placements();
bool has_data() const;
void update_egg();
bool read_egg();
bool write_egg();
void write_description(ostream &out, int indent_level = 0) const;
void write_texture_refs(ostream &out, int indent_level = 0) const;
private:
@ -59,7 +73,12 @@ private:
typedef vector<TextureReference *> Textures;
Textures _textures;
PaletteGroups _assigned_groups;
bool _first_txa_match;
PaletteGroups _explicitly_assigned_groups;
PaletteGroup *_default_group;
PaletteGroups _complete_groups;
bool _is_surprise;
bool _is_stale;
// The TypedWriteable interface follows.
@ -95,8 +114,6 @@ public:
private:
static TypeHandle _type_handle;
friend class TxaLine;
};
#endif

View File

@ -7,6 +7,7 @@
#include "palettizer.h"
#include "eggFile.h"
#include "string_utils.h"
#include "filenameUnifier.h"
#include <eggData.h>
#include <bamFile.h>
@ -76,7 +77,7 @@ EggPalettize() : EggMultiFilter(true) {
("dm", "dirname", 0,
"The directory in which to place all maps: generated palettes, "
"as well as images which were not placed on palettes "
"(but may have been resized). If this contains the string %s, "
"(but may have been resized). If this contains the string %g, "
"this will be replaced with the \"dir\" string associated with a "
"palette group.",
&EggPalettize::dispatch_string, &_got_map_dirname, &_map_dirname);
@ -97,7 +98,13 @@ EggPalettize() : EggMultiFilter(true) {
&EggPalettize::dispatch_string, &_got_default_groupdir, &_default_groupdir);
add_option
("f", "", 0,
("all", "", 0,
"Consider all the textures referenced in all egg files that have "
"ever been palettized, not just the egg files that appear on "
"the command line.",
&EggPalettize::dispatch_none, &_all_textures);
add_option
("opt", "", 0,
"Force an optimal packing. By default, textures are added to "
"existing palettes without disturbing them, which can lead to "
"suboptimal packing. Including this switch forces the palettes "
@ -105,7 +112,7 @@ EggPalettize() : EggMultiFilter(true) {
"may invalidate other egg files which share this palette.",
&EggPalettize::dispatch_none, &_force_optimal);
add_option
("F", "", 0,
("redo", "", 0,
"Force a redo of everything. This is useful in case something "
"has gotten out of sync and the old palettes are just bad.",
&EggPalettize::dispatch_none, &_force_redo_all);
@ -114,12 +121,10 @@ EggPalettize() : EggMultiFilter(true) {
"Resize mostly-empty palettes to their minimal size.",
&EggPalettize::dispatch_none, &_optimal_resize);
add_option
("t", "", 0,
"Touch any additional egg files that share this palette and will "
"need to be refreshed, but were not included on the command "
"line. Presumably a future make pass will cause them to be run "
"through egg-palettize again.",
&EggPalettize::dispatch_none, &_touch_eggs);
("egg", "", 0,
"Regenerate all egg files that need modification, even those that "
"aren't named on the command line.",
&EggPalettize::dispatch_none, &_redo_eggs);
add_option
("nolock", "", 0,
@ -244,38 +249,40 @@ run() {
exit(1);
}
Filename pi_filename = _txa_filename;
pi_filename.set_extension("boo");
FilenameUnifier::set_txa_filename(_txa_filename);
BamFile pi_file;
Filename state_filename = _txa_filename;
state_filename.set_extension("boo");
if (!pi_filename.exists()) {
nout << pi_filename << " does not exist; starting palettization from scratch.\n";
BamFile state_file;
if (!state_filename.exists()) {
nout << state_filename << " does not exist; starting palettization from scratch.\n";
pal = new Palettizer;
} else {
// Read the Palettizer object from the Bam file written
// previously. This will recover all of the state saved from the
// past session.
if (!pi_file.open_read(pi_filename)) {
nout << pi_filename << " exists, but cannot be read. Perhaps you should remove it so a new one can be created.\n";
if (!state_file.open_read(state_filename)) {
nout << state_filename << " exists, but cannot be read. Perhaps you should remove it so a new one can be created.\n";
exit(1);
}
TypedWriteable *obj = pi_file.read_object();
if (obj == (TypedWriteable *)NULL || !pi_file.resolve()) {
nout << pi_filename << " exists, but appears to be corrupt. Perhaps you should remove it so a new one can be created.\n";
TypedWriteable *obj = state_file.read_object();
if (obj == (TypedWriteable *)NULL || !state_file.resolve()) {
nout << state_filename << " exists, but appears to be corrupt. Perhaps you should remove it so a new one can be created.\n";
exit(1);
}
if (!obj->is_of_type(Palettizer::get_class_type())) {
nout << pi_filename << " exists, but does not appear to be "
nout << state_filename << " exists, but does not appear to be "
<< "an egg-palettize output file. Perhaps you "
<< "should remove it so a new one can be created.\n";
exit(1);
}
pi_file.close();
state_file.close();
pal = DCAST(Palettizer, obj);
}
@ -285,15 +292,26 @@ run() {
exit(0);
}
bool okflag = true;
pal->read_txa_file(_txa_filename);
if (_got_default_groupname) {
pal->_default_groupname = _default_groupname;
} else {
pal->_default_groupname = _txa_filename.get_basename_wo_extension();
}
TxaFile txa_file;
if (!txa_file.read(_txa_filename)) {
exit(1);
if (_got_default_groupdir) {
pal->_default_groupdir = _default_groupdir;
}
if (_got_map_dirname) {
pal->_map_dirname = _map_dirname;
}
if (_got_rel_dirname) {
pal->_rel_dirname = _rel_dirname;
FilenameUnifier::set_rel_dirname(_rel_dirname);
}
Eggs::const_iterator ei;
@ -309,18 +327,36 @@ run() {
pal->_command_line_eggs.push_back(egg_file);
}
pal->run(txa_file);
if (_all_textures) {
pal->process_all();
} else {
pal->process_command_line_eggs();
}
if (!pi_file.open_write(pi_filename) ||
!pi_file.write_object(pal)) {
nout << "Unable to write palettization information to " << pi_filename
if (_redo_eggs) {
if (!pal->read_stale_eggs()) {
okflag = false;
}
}
pal->generate_images();
if (!pal->write_eggs()) {
okflag = false;
}
if (!state_file.open_write(state_filename) ||
!state_file.write_object(pal)) {
nout << "Unable to write palettization information to " << state_filename
<< "\n";
exit(1);
}
pi_file.close();
state_file.close();
write_eggs();
if (!okflag) {
exit(1);
}
}
int

View File

@ -43,10 +43,11 @@ private:
// They're not saved for future sessions.
bool _report_pi;
bool _statistics_only;
bool _all_textures;
bool _force_optimal;
bool _force_redo_all;
bool _optimal_resize;
bool _touch_eggs;
bool _redo_eggs;
bool _dont_lock_pi;
bool _describe_input_file;

View File

@ -0,0 +1,109 @@
// Filename: filenameUnifier.cxx
// Created by: drose (05Dec00)
//
////////////////////////////////////////////////////////////////////
#include "filenameUnifier.h"
#include <executionEnvironment.h>
Filename FilenameUnifier::_txa_filename;
Filename FilenameUnifier::_txa_dir;
Filename FilenameUnifier::_rel_dirname;
////////////////////////////////////////////////////////////////////
// Function: FilenameUnifier::set_txa_filename
// Access: Public, Static
// Description: Notes the filename the .txa file was found in. This
// may have come from the command line, or it may have
// been implicitly located. This has other implications
// for the FilenameUnifier, particularly in locating the bam
// file that saves the filenameUnifier state from last
// session.
////////////////////////////////////////////////////////////////////
void FilenameUnifier::
set_txa_filename(const Filename &txa_filename) {
_txa_filename = txa_filename;
_txa_dir = txa_filename.get_dirname();
_txa_dir.make_canonical();
}
////////////////////////////////////////////////////////////////////
// Function: FilenameUnifier::set_rel_dirname
// Access: Public, Static
// Description: Sets the name of the directory that texture filenames
// will be written relative to, when generating egg
// files. This is not the directory the textures are
// actually written to (see set_map_dirname()), but
// rather is the name of some directory above that,
// which will be the starting point for the pathnames
// written to the egg files. If this is empty, the full
// pathnames will be written to the egg files.
////////////////////////////////////////////////////////////////////
void FilenameUnifier::
set_rel_dirname(const Filename &rel_dirname) {
_rel_dirname = rel_dirname;
if (!_rel_dirname.empty()) {
_rel_dirname.make_canonical();
}
}
////////////////////////////////////////////////////////////////////
// Function: FilenameUnifier::make_bam_filename
// Access: Public, Static
// Description: Returns a new filename that's made relative to the
// bam file itself, suitable for writing to the bam file.
////////////////////////////////////////////////////////////////////
Filename FilenameUnifier::
make_bam_filename(Filename filename) {
filename.make_canonical();
filename.make_relative_to(_txa_dir);
return filename;
}
////////////////////////////////////////////////////////////////////
// Function: FilenameUnifier::get_bam_filename
// Access: Public, Static
// Description: Returns an absolute pathname based on the given
// relative pathname, presumably read from the bam file
// and relative to the bam file.
////////////////////////////////////////////////////////////////////
Filename FilenameUnifier::
get_bam_filename(Filename filename) {
if (!filename.empty()) {
filename.make_absolute(_txa_dir);
}
return filename;
}
////////////////////////////////////////////////////////////////////
// Function: FilenameUnifier::make_egg_filename
// Access: Public, Static
// Description: Returns a new filename that's made relative to the
// rel_directory, suitable for writing out within egg
// files.
////////////////////////////////////////////////////////////////////
Filename FilenameUnifier::
make_egg_filename(Filename filename) {
if (!filename.empty()) {
filename.make_canonical();
filename.make_relative_to(_rel_dirname);
}
return filename;
}
////////////////////////////////////////////////////////////////////
// Function: FilenameUnifier::make_user_filename
// Access: Public, Static
// Description: Returns a new filename that's made relative to the
// current directory, suitable for reporting to the
// user.
////////////////////////////////////////////////////////////////////
Filename FilenameUnifier::
make_user_filename(Filename filename) {
if (!filename.empty()) {
filename.make_canonical();
filename.make_relative_to(ExecutionEnvironment::get_cwd());
}
return filename;
}

View File

@ -0,0 +1,40 @@
// Filename: filenameUnifier.h
// Created by: drose (05Dec00)
//
////////////////////////////////////////////////////////////////////
#ifndef FILENAMEUNIFIER_H
#define FILENAMEUNIFIER_H
#include <pandatoolbase.h>
#include <filename.h>
////////////////////////////////////////////////////////////////////
// Class : FilenameUnifier
// Description : This static class does the job of converting
// filenames from relative to absolute to canonical or
// whatever is appropriate. Its main purpose is to
// allow us to write relative pathnames to the bam file
// and turn them back into absolute pathnames on read,
// so that a given bam file does not get tied to
// absolute pathnames.
////////////////////////////////////////////////////////////////////
class FilenameUnifier {
public:
static void set_txa_filename(const Filename &txa_filename);
static void set_rel_dirname(const Filename &rel_dirname);
static Filename make_bam_filename(Filename filename);
static Filename get_bam_filename(Filename filename);
static Filename make_egg_filename(Filename filename);
static Filename make_user_filename(Filename filename);
private:
static Filename _txa_filename;
static Filename _txa_dir;
static Filename _rel_dirname;
};
#endif

View File

@ -4,6 +4,9 @@
////////////////////////////////////////////////////////////////////
#include "imageFile.h"
#include "palettizer.h"
#include "filenameUnifier.h"
#include "paletteGroup.h"
#include <pnmImage.h>
#include <pnmFileType.h>
@ -118,8 +121,33 @@ update_properties(const TextureProperties &properties) {
// automatically applied.
////////////////////////////////////////////////////////////////////
void ImageFile::
set_filename(const string &basename) {
_filename = basename;
set_filename(PaletteGroup *group, const string &basename) {
// Synthesize the directory name based on the map_dirname set to the
// palettizer, and the group's dirname.
string dirname;
string::iterator pi;
pi = pal->_map_dirname.begin();
while (pi != pal->_map_dirname.end()) {
if (*pi == '%') {
++pi;
switch (*pi) {
case '%':
dirname += '%';
break;
case 'g':
if (group != (PaletteGroup *)NULL) {
dirname += group->get_dirname();
}
break;
}
} else {
dirname += *pi;
}
++pi;
}
_filename = Filename(dirname, basename);
if (_properties._color_type != (PNMFileType *)NULL) {
_filename.set_extension
@ -189,17 +217,17 @@ read(PNMImage &image) const {
nassertr(!_filename.empty(), false);
image.set_type(_properties._color_type);
nout << "Reading " << _filename << "\n";
nout << "Reading " << FilenameUnifier::make_user_filename(_filename) << "\n";
if (!image.read(_filename)) {
nout << "Unable to read.\n";
return false;
}
if (!_alpha_filename.empty()) {
if (!_alpha_filename.empty() && _alpha_filename.exists()) {
// Read in a separate color image and an alpha channel image.
PNMImage alpha_image;
alpha_image.set_type(_properties._alpha_type);
nout << "Reading " << _alpha_filename << "\n";
nout << "Reading " << FilenameUnifier::make_user_filename(_alpha_filename) << "\n";
if (!alpha_image.read(_alpha_filename)) {
nout << "Unable to read.\n";
return false;
@ -236,9 +264,11 @@ write(PNMImage &image) const {
if (!image.has_alpha() ||
_properties._alpha_type == (PNMFileType *)NULL) {
if (!_alpha_filename.empty() && _alpha_filename.exists()) {
nout << "Deleting " << FilenameUnifier::make_user_filename(_alpha_filename) << "\n";
_alpha_filename.unlink();
}
nout << "Writing " << _filename << "\n";
nout << "Writing " << FilenameUnifier::make_user_filename(_filename) << "\n";
_filename.make_dir();
if (!image.write(_filename, _properties._color_type)) {
nout << "Unable to write.\n";
return false;
@ -256,12 +286,14 @@ write(PNMImage &image) const {
}
image.remove_alpha();
nout << "Writing " << _filename << "\n";
nout << "Writing " << FilenameUnifier::make_user_filename(_filename) << "\n";
_filename.make_dir();
if (!image.write(_filename, _properties._color_type)) {
nout << "Unable to write.\n";
return false;
}
nout << "Writing " << _alpha_filename << "\n";
nout << "Writing " << FilenameUnifier::make_user_filename(_alpha_filename) << "\n";
_alpha_filename.make_dir();
if (!alpha_image.write(_alpha_filename, _properties._alpha_type)) {
nout << "Unable to write.\n";
return false;
@ -277,11 +309,11 @@ write(PNMImage &image) const {
void ImageFile::
unlink() {
if (!_filename.empty() && _filename.exists()) {
nout << "Deleting " << _filename << "\n";
nout << "Deleting " << FilenameUnifier::make_user_filename(_filename) << "\n";
_filename.unlink();
}
if (!_alpha_filename.empty() && _alpha_filename.exists()) {
nout << "Deleting " << _alpha_filename << "\n";
nout << "Deleting " << FilenameUnifier::make_user_filename(_alpha_filename) << "\n";
_alpha_filename.unlink();
}
}
@ -298,6 +330,7 @@ update_egg_tex(EggTexture *egg_tex) const {
egg_tex->set_filename(_filename);
if (_properties._alpha_type != (PNMFileType *)NULL &&
_properties.uses_alpha() &&
!_alpha_filename.empty()) {
egg_tex->set_alpha_file(_alpha_filename);
} else {
@ -315,10 +348,11 @@ update_egg_tex(EggTexture *egg_tex) const {
////////////////////////////////////////////////////////////////////
void ImageFile::
output_filename(ostream &out) const {
out << _filename;
out << FilenameUnifier::make_user_filename(_filename);
if (_properties._alpha_type != (PNMFileType *)NULL &&
_properties.uses_alpha() &&
!_alpha_filename.empty()) {
out << " " << _alpha_filename;
out << " " << FilenameUnifier::make_user_filename(_alpha_filename);
}
}
@ -332,8 +366,8 @@ output_filename(ostream &out) const {
void ImageFile::
write_datagram(BamWriter *writer, Datagram &datagram) {
_properties.write_datagram(writer, datagram);
datagram.add_string(_filename);
datagram.add_string(_alpha_filename);
datagram.add_string(FilenameUnifier::make_bam_filename(_filename));
datagram.add_string(FilenameUnifier::make_bam_filename(_alpha_filename));
datagram.add_bool(_size_known);
datagram.add_int32(_x_size);
datagram.add_int32(_y_size);
@ -349,8 +383,8 @@ write_datagram(BamWriter *writer, Datagram &datagram) {
void ImageFile::
fillin(DatagramIterator &scan, BamReader *manager) {
_properties.fillin(scan, manager);
_filename = scan.get_string();
_alpha_filename = scan.get_string();
_filename = FilenameUnifier::get_bam_filename(scan.get_string());
_alpha_filename = FilenameUnifier::get_bam_filename(scan.get_string());
_size_known = scan.get_bool();
_x_size = scan.get_int32();
_y_size = scan.get_int32();

View File

@ -15,6 +15,7 @@
class PNMImage;
class EggTexture;
class PaletteGroup;
////////////////////////////////////////////////////////////////////
// Class : ImageFile
@ -36,7 +37,7 @@ public:
const TextureProperties &get_properties() const;
void update_properties(const TextureProperties &properties);
void set_filename(const string &basename);
void set_filename(PaletteGroup *group, const string &basename);
const Filename &get_filename() const;
const Filename &get_alpha_filename() const;
bool exists() const;

View File

@ -24,6 +24,7 @@ TypeHandle PaletteGroup::_type_handle;
PaletteGroup::
PaletteGroup() {
_egg_count = 0;
_dependency_level = 0;
}
////////////////////////////////////////////////////////////////////
@ -39,6 +40,41 @@ set_dirname(const string &dirname) {
_dirname = dirname;
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::has_dirname
// Access: Public
// Description: Returns true if the directory name has been
// explicitly set for this group. If it has not,
// get_dirname() returns an empty string.
////////////////////////////////////////////////////////////////////
bool PaletteGroup::
has_dirname() const {
return !_dirname.empty();
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::get_dirname
// Access: Public
// Description: Returns the directory name associated with the
// palette group. See set_dirname().
////////////////////////////////////////////////////////////////////
const string &PaletteGroup::
get_dirname() const {
return _dirname;
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::clear_depends
// Access: Public
// Description: Eliminates all the dependency information for this
// group.
////////////////////////////////////////////////////////////////////
void PaletteGroup::
clear_depends() {
_dependent.clear();
_dependency_level = 0;
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::group_with
// Access: Public
@ -66,6 +102,55 @@ get_groups() const {
return _dependent;
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::set_dependency_level
// Access: Public
// Description: Sets the dependency level of this group to the
// indicated level, provided that level is not lower
// than the level that was set previously. Also
// cascades to all dependent groups. See
// get_dependency_level().
//
// This call recurses to correctly set the dependency
// level of all PaletteGroups in the hierarchy.
////////////////////////////////////////////////////////////////////
void PaletteGroup::
set_dependency_level(int level) {
if (level > _dependency_level) {
_dependency_level = level;
PaletteGroups::iterator gi;
for (gi = _dependent.begin(); gi != _dependent.end(); ++gi) {
(*gi)->set_dependency_level(level + 1);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::get_dependency_level
// Access: Public
// Description: Returns the dependency level of this group. This is
// a measure of how specific the group is; the lower the
// dependency level, the more specific the group.
//
// Groups depend on other groups in a hierarchical
// relationship. In general, if group a depends on
// group b, then b->get_dependency_level() >
// a->get_dependency_level().
//
// Thus, groups that lots of other groups depend on have
// a higher dependency level; groups that no one else
// depends on have a low dependency level. This is
// important when deciding which groups are best suited
// for assigning a texture to; in general, the texture
// should be assigned to the most specific suitable
// group (i.e. the one with the lowest dependency
// level).
////////////////////////////////////////////////////////////////////
int PaletteGroup::
get_dependency_level() const {
return _dependency_level;
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::increment_egg_count
// Access: Public
@ -261,6 +346,9 @@ write_datagram(BamWriter *writer, Datagram &datagram) {
datagram.add_string(_dirname);
_dependent.write_datagram(writer, datagram);
// We don't write out _dependency_level. It's best to recompute
// that each time.
datagram.add_uint32(_placements.size());
Placements::const_iterator pli;
for (pli = _placements.begin(); pli != _placements.end(); ++pli) {

View File

@ -37,10 +37,16 @@ public:
PaletteGroup();
void set_dirname(const string &dirname);
bool has_dirname() const;
const string &get_dirname() const;
void clear_depends();
void group_with(PaletteGroup *other);
const PaletteGroups &get_groups() const;
void set_dependency_level(int level);
int get_dependency_level() const;
void increment_egg_count();
int get_egg_count() const;
@ -59,6 +65,7 @@ private:
string _dirname;
int _egg_count;
PaletteGroups _dependent;
int _dependency_level;
typedef set<TexturePlacement *> Placements;
Placements _placements;

View File

@ -143,6 +143,16 @@ make_intersection(const PaletteGroups &a, const PaletteGroups &b) {
_groups.swap(i);
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroups::clear
// Access: Public
// Description: Empties the set.
////////////////////////////////////////////////////////////////////
void PaletteGroups::
clear() {
_groups.clear();
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroups::empty
// Access: Public

View File

@ -43,6 +43,7 @@ public:
void make_complete(const PaletteGroups &a);
void make_union(const PaletteGroups &a, const PaletteGroups &b);
void make_intersection(const PaletteGroups &a, const PaletteGroups &b);
void clear();
bool empty() const;
size_type size() const;

View File

@ -163,7 +163,7 @@ PaletteImage(PalettePage *page, int index) :
name << page->get_group()->get_name() << "_palette_"
<< page->get_name() << "_" << index + 1;
set_filename(name.str());
set_filename(page->get_group(), name.str());
}
////////////////////////////////////////////////////////////////////
@ -465,9 +465,10 @@ write_datagram(BamWriter *writer, Datagram &datagram) {
writer->write_pointer(datagram, _page);
datagram.add_uint32(_index);
datagram.add_bool(_new_image);
// We don't write _new_image, _got_image, or _image. These are all
// loaded per-session.
// We don't write _got_image or _image. These are loaded
// per-session.
}
////////////////////////////////////////////////////////////////////
@ -546,4 +547,5 @@ fillin(DatagramIterator &scan, BamReader *manager) {
manager->read_pointer(scan, this); // _page
_index = scan.get_uint32();
_new_image = scan.get_bool();
}

View File

@ -8,6 +8,7 @@
#include "textureImage.h"
#include "string_utils.h"
#include "paletteGroup.h"
#include "filenameUnifier.h"
#include <pnmImage.h>
#include <pnmFileTypeRegistry.h>
@ -36,6 +37,7 @@ Palettizer() {
// version number for all bam and boo files anywhere in the world.
_pi_version = 0;
_map_dirname = "%g";
_margin = 2;
_repeat_threshold = 250.0;
_aggressively_clean_mapdir = true;
@ -61,6 +63,9 @@ void Palettizer::
report_pi() const {
cout
<< "\nparams\n"
<< " map directory: " << _map_dirname << "\n"
<< " egg relative directory: "
<< FilenameUnifier::make_user_filename(_rel_dirname) << "\n"
<< " palettize size: " << _pal_x_size << " by " << _pal_y_size << "\n"
<< " margin: " << _margin << "\n"
<< " repeat threshold: " << _repeat_threshold << "%\n"
@ -108,8 +113,7 @@ report_pi() const {
EggFiles::const_iterator ei;
for (ei = _egg_files.begin(); ei != _egg_files.end(); ++ei) {
EggFile *egg_file = (*ei).second;
cout << " " << egg_file->get_name() << ": "
<< egg_file->get_groups() << "\n";
egg_file->write_description(cout, 2);
egg_file->write_texture_refs(cout, 4);
}
@ -117,35 +121,82 @@ report_pi() const {
Groups::const_iterator gi;
for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
PaletteGroup *group = (*gi).second;
if (gi != _groups.begin()) {
cout << "\n";
}
cout << " " << group->get_name() << ": "
<< group->get_groups() << "\n";
group->write_image_info(cout, 4);
cout << "\n";
}
cout << "textures\n";
cout << "\ntextures\n";
for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
TextureImage *texture = (*ti).second;
texture->write_scale_info(cout, 2);
}
cout << "\nsurprises\n";
for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
TextureImage *texture = (*ti).second;
if (texture->is_surprise()) {
cout << " " << texture->get_name() << "\n";
}
}
for (ei = _egg_files.begin(); ei != _egg_files.end(); ++ei) {
EggFile *egg_file = (*ei).second;
if (egg_file->is_surprise()) {
cout << " " << egg_file->get_name() << "\n";
}
}
cout << "\n";
}
////////////////////////////////////////////////////////////////////
// Function: Palettizer::run
// Function: Palettizer::read_txa_file
// Access: Public
// Description:
// Description: Reads in the .txa file and keeps it ready for
// matching textures and egg files.
////////////////////////////////////////////////////////////////////
void Palettizer::
run(const TxaFile &txa_file) {
read_txa_file(const Filename &txa_filename) {
// Clear out the group dependencies, in preparation for reading them
// again from the .txa file.
Groups::iterator gi;
for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
PaletteGroup *group = (*gi).second;
group->clear_depends();
}
if (!_txa_file.read(txa_filename)) {
exit(1);
}
if (_color_type == (PNMFileType *)NULL) {
nout << "No valid output image file type available, cannot run.\n"
nout << "No valid output image file type available; cannot run.\n"
<< "Use :imagetype command in .txa file.\n";
exit(1);
}
set<TextureImage *> command_line_textures;
// Compute the correct dependency level for each group. This will
// help us when we assign the textures to their groups.
for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
PaletteGroup *group = (*gi).second;
group->set_dependency_level(1);
}
}
////////////////////////////////////////////////////////////////////
// Function: Palettizer::process_command_line_eggs
// Access: Public
// Description: Processes all the textures named in the
// _command_line_eggs, placing them on the appropriate
// palettes or whatever needs to be done with them.
////////////////////////////////////////////////////////////////////
void Palettizer::
process_command_line_eggs() {
_command_line_textures.clear();
// Start by scanning all the egg files we read up on the command
// line.
@ -156,23 +207,23 @@ run(const TxaFile &txa_file) {
EggFile *egg_file = (*ei);
egg_file->scan_textures();
egg_file->get_textures(command_line_textures);
txa_file.match_egg(egg_file);
egg_file->get_textures(_command_line_textures);
egg_file->pre_txa_file();
_txa_file.match_egg(egg_file);
egg_file->post_txa_file();
}
// Now match each of the textures mentioned in those egg files
// against a line in the .txa file.
set<TextureImage *>::iterator ti;
for (ti = command_line_textures.begin();
ti != command_line_textures.end();
CommandLineTextures::iterator ti;
for (ti = _command_line_textures.begin();
ti != _command_line_textures.end();
++ti) {
TextureImage *texture = *ti;
texture->pre_txa_file();
txa_file.match_texture(texture);
_txa_file.match_texture(texture);
texture->post_txa_file();
}
@ -185,8 +236,8 @@ run(const TxaFile &txa_file) {
// And now, assign each of the current set of textures to an
// appropriate group or groups.
for (ti = command_line_textures.begin();
ti != command_line_textures.end();
for (ti = _command_line_textures.begin();
ti != _command_line_textures.end();
++ti) {
TextureImage *texture = *ti;
texture->assign_groups();
@ -202,8 +253,8 @@ run(const TxaFile &txa_file) {
// Now that *that's* done, we need to make sure the various
// TexturePlacements require the right size for their textures.
for (ti = command_line_textures.begin();
ti != command_line_textures.end();
for (ti = _command_line_textures.begin();
ti != _command_line_textures.end();
++ti) {
TextureImage *texture = *ti;
texture->determine_placement_size();
@ -216,22 +267,160 @@ run(const TxaFile &txa_file) {
PaletteGroup *group = (*gi).second;
group->place_all();
}
}
// Finally, generate all the images.
////////////////////////////////////////////////////////////////////
// Function: Palettizer::process_all
// Access: Public
// Description: Reprocesses all textures known.
////////////////////////////////////////////////////////////////////
void Palettizer::
process_all() {
// If there *were* any egg files on the command line, deal with
// them.
CommandLineEggs::const_iterator ei;
for (ei = _command_line_eggs.begin();
ei != _command_line_eggs.end();
++ei) {
EggFile *egg_file = (*ei);
egg_file->scan_textures();
egg_file->get_textures(_command_line_textures);
}
// Then match up all the egg files we know about with the .txa file.
EggFiles::const_iterator efi;
for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
EggFile *egg_file = (*efi).second;
egg_file->pre_txa_file();
_txa_file.match_egg(egg_file);
egg_file->post_txa_file();
}
// Now match each of the textures in the world against a line in the
// .txa file.
Textures::iterator ti;
for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
TextureImage *texture = (*ti).second;
texture->pre_txa_file();
_txa_file.match_texture(texture);
texture->post_txa_file();
}
// Now that all of our data is read in, build in all the cross links
// and back pointers and stuff.
for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
(*efi).second->build_cross_links();
}
// And now, assign each texture to an appropriate group or groups.
for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
TextureImage *texture = (*ti).second;
texture->assign_groups();
}
// And then the egg files need to sign up for a particular
// TexturePlacement, so we can determine some more properties about
// how the textures are placed (for instance, how big the UV range
// is for a particular TexturePlacement).
for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
(*efi).second->choose_placements();
}
// Now that *that's* done, we need to make sure the various
// TexturePlacements require the right size for their textures.
for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
TextureImage *texture = (*ti).second;
texture->determine_placement_size();
}
// Now that each texture has been assigned to a suitable group,
// make sure the textures are placed on specific PaletteImages.
Groups::iterator gi;
for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
PaletteGroup *group = (*gi).second;
group->place_all();
}
}
////////////////////////////////////////////////////////////////////
// Function: Palettizer::generate_images
// Access: Public
// Description: Actually generates the appropriate palette and
// unplaced texture images into the map directories.
////////////////////////////////////////////////////////////////////
void Palettizer::
generate_images() {
Groups::iterator gi;
for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
PaletteGroup *group = (*gi).second;
group->update_images();
}
// And now we can adjust all the egg files.
for (ei = _command_line_eggs.begin();
ei != _command_line_eggs.end();
++ei) {
EggFile *egg_file = (*ei);
egg_file->update_egg();
Textures::iterator ti;
for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
TextureImage *texture = (*ti).second;
texture->copy_unplaced();
}
}
////////////////////////////////////////////////////////////////////
// Function: Palettizer::read_stale_eggs
// Access: Public
// Description: Reads in any egg file that is known to be stale, even
// if it was not listed on the command line, so that it
// may be updated and written out when write_eggs() is
// called. Returns true if successful, or false if
// there was some error.
////////////////////////////////////////////////////////////////////
bool Palettizer::
read_stale_eggs() {
bool okflag = true;
EggFiles::iterator ei;
for (ei = _egg_files.begin(); ei != _egg_files.end(); ++ei) {
EggFile *egg_file = (*ei).second;
if (!egg_file->has_data() && egg_file->is_stale()) {
if (!egg_file->read_egg()) {
okflag = false;
} else {
egg_file->scan_textures();
egg_file->choose_placements();
}
}
}
return okflag;
}
////////////////////////////////////////////////////////////////////
// Function: Palettizer::write_eggs
// Access: Public
// Description: Adjusts the egg files to reference the newly
// generated textures, and writes them out. Returns
// true if successful, or false if there was some error.
////////////////////////////////////////////////////////////////////
bool Palettizer::
write_eggs() {
bool okflag = true;
EggFiles::iterator ei;
for (ei = _egg_files.begin(); ei != _egg_files.end(); ++ei) {
EggFile *egg_file = (*ei).second;
if (egg_file->has_data()) {
egg_file->update_egg();
if (!egg_file->write_egg()) {
okflag = false;
}
}
}
return okflag;
}
////////////////////////////////////////////////////////////////////
// Function: Palettizer::get_egg_file
// Access: Public
@ -298,7 +487,11 @@ test_palette_group(const string &name) const {
////////////////////////////////////////////////////////////////////
PaletteGroup *Palettizer::
get_default_group() {
return get_palette_group(_default_groupname);
PaletteGroup *default_group = get_palette_group(_default_groupname);
if (!_default_groupdir.empty() && !default_group->has_dirname()) {
default_group->set_dirname(_default_groupdir);
}
return default_group;
}
////////////////////////////////////////////////////////////////////
@ -319,7 +512,7 @@ get_texture(const string &name) {
TextureImage *image = new TextureImage;
image->set_name(name);
image->set_filename(name);
// image->set_filename(name);
_textures.insert(Textures::value_type(name, image));
return image;
}
@ -358,9 +551,7 @@ void Palettizer::
write_datagram(BamWriter *writer, Datagram &datagram) {
datagram.add_int32(_pi_version);
datagram.add_string(_map_dirname);
datagram.add_string(_rel_dirname);
datagram.add_string(_default_groupname);
datagram.add_string(_default_groupdir);
datagram.add_string(FilenameUnifier::make_bam_filename(_rel_dirname));
datagram.add_int32(_pal_x_size);
datagram.add_int32(_pal_y_size);
datagram.add_int32(_margin);
@ -477,9 +668,8 @@ void Palettizer::
fillin(DatagramIterator &scan, BamReader *manager) {
_pi_version = scan.get_int32();
_map_dirname = scan.get_string();
_rel_dirname = scan.get_string();
_default_groupname = scan.get_string();
_default_groupdir = scan.get_string();
_rel_dirname = FilenameUnifier::get_bam_filename(scan.get_string());
FilenameUnifier::set_rel_dirname(_rel_dirname);
_pal_x_size = scan.get_int32();
_pal_y_size = scan.get_int32();
_margin = scan.get_int32();

View File

@ -13,6 +13,7 @@
#include <typedWriteable.h>
#include <vector>
#include <set>
#include <map>
class PNMFileType;
@ -33,7 +34,12 @@ public:
Palettizer();
void report_pi() const;
void run(const TxaFile &txa_file);
void read_txa_file(const Filename &txa_filename);
void process_command_line_eggs();
void process_all();
void generate_images();
bool read_stale_eggs();
bool write_eggs();
EggFile *get_egg_file(const string &name);
PaletteGroup *get_palette_group(const string &name);
@ -53,13 +59,17 @@ public:
RU_poly
};
// The following parameter values specifically relate to textures
// and palettes. These values are stored in the .pi file for future
// reference.
Filename _map_dirname;
Filename _rel_dirname;
// These values are not stored in the bam file, but are specific to
// each session.
TxaFile _txa_file;
string _default_groupname;
string _default_groupdir;
// The following parameter values specifically relate to textures
// and palettes. These values are stored in the bam file for future
// reference.
string _map_dirname;
Filename _rel_dirname;
int _pal_x_size, _pal_y_size;
int _margin;
double _repeat_threshold;
@ -79,6 +89,9 @@ private:
typedef vector<EggFile *> CommandLineEggs;
CommandLineEggs _command_line_eggs;
typedef set<TextureImage *> CommandLineTextures;
CommandLineTextures _command_line_textures;
typedef map<string, PaletteGroup *> Groups;
Groups _groups;

View File

@ -120,19 +120,6 @@ read_header() {
}
////////////////////////////////////////////////////////////////////
// Function: SourceTextureImage::output
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void SourceTextureImage::
output(ostream &out) const {
out << _filename;
if (!_alpha_filename.empty()) {
out << " (" << _alpha_filename << ")";
}
}
////////////////////////////////////////////////////////////////////
// Function: SourceTextureImage::register_with_read_factory
// Access: Public, Static

View File

@ -30,8 +30,6 @@ public:
bool get_size();
bool read_header();
void output(ostream &out) const;
private:
bool _read_header;
bool _successfully_read_header;
@ -67,7 +65,7 @@ private:
INLINE ostream &
operator << (ostream &out, const SourceTextureImage &source) {
source.output(out);
source.output_filename(out);
return out;
}

View File

@ -5,6 +5,7 @@
#include "textureImage.h"
#include "sourceTextureImage.h"
#include "destTextureImage.h"
#include "eggFile.h"
#include "paletteGroup.h"
#include "texturePlacement.h"
@ -26,6 +27,8 @@ TextureImage::
TextureImage() {
_preferred_source = (SourceTextureImage *)NULL;
_read_source_image = false;
_got_dest_image = false;
_is_surprise = true;
}
////////////////////////////////////////////////////////////////////
@ -38,7 +41,7 @@ TextureImage() {
////////////////////////////////////////////////////////////////////
void TextureImage::
note_egg_file(EggFile *egg_file) {
nassertv(!egg_file->get_groups().empty());
nassertv(!egg_file->get_complete_groups().empty());
_egg_files.insert(egg_file);
}
@ -73,7 +76,7 @@ assign_groups() {
EggFiles::const_iterator ei;
for (ei = _egg_files.begin(); ei != _egg_files.end(); ++ei) {
PaletteGroups intersect;
intersect.make_intersection(_explicitly_assigned_groups, (*ei)->get_groups());
intersect.make_intersection(_explicitly_assigned_groups, (*ei)->get_complete_groups());
if (!intersect.empty()) {
// This egg file is satisfied by one of the texture's explicit
// assignments.
@ -100,12 +103,13 @@ assign_groups() {
PaletteGroups total;
WorkingEggs::const_iterator ei;
for (ei = needed_eggs.begin(); ei != needed_eggs.end(); ++ei) {
total.make_union(total, (*ei)->get_groups());
total.make_union(total, (*ei)->get_complete_groups());
}
// Now, find the group that will satisfy the most egg files. If two
// groups satisfy the same number of egg files, choose the one that
// has the fewest egg files sharing it.
// Now, find the group that will satisfy the most egg files. If
// two groups satisfy the same number of egg files, choose (a) the
// most specific one, i.e. with the lowest dependency_level value,
// and (b) the one that has the fewest egg files sharing it.
nassertv(!total.empty());
PaletteGroups::iterator gi = total.begin();
PaletteGroup *best = (*gi);
@ -113,10 +117,22 @@ assign_groups() {
++gi;
while (gi != total.end()) {
PaletteGroup *group = (*gi);
// Do we prefer this group to our current 'best'?
bool prefer_group = false;
int group_egg_count = compute_egg_count(group, needed_eggs);
if (group_egg_count > best_egg_count ||
(group_egg_count == best_egg_count &&
group->get_egg_count() < best->get_egg_count())) {
if (group_egg_count != best_egg_count) {
prefer_group = (group_egg_count > best_egg_count);
} else if (group->get_dependency_level() != best->get_dependency_level()){
prefer_group =
(group->get_dependency_level() < best->get_dependency_level());
} else {
prefer_group = (group->get_egg_count() < best->get_egg_count());
}
if (prefer_group) {
best = group;
best_egg_count = group_egg_count;
}
@ -129,7 +145,7 @@ assign_groups() {
WorkingEggs next_needed_eggs;
for (ei = needed_eggs.begin(); ei != needed_eggs.end(); ++ei) {
if ((*ei)->get_groups().count(best) == 0) {
if ((*ei)->get_complete_groups().count(best) == 0) {
// This one wasn't eliminated.
next_needed_eggs.push_back(*ei);
}
@ -209,6 +225,7 @@ pre_txa_file() {
}
_request.pre_txa_file();
_is_surprise = true;
}
////////////////////////////////////////////////////////////////////
@ -332,6 +349,19 @@ get_margin() const {
return _request._margin;
}
////////////////////////////////////////////////////////////////////
// Function: TextureImage::is_surprise
// Access: Public
// Description: Returns true if this particular texture is a
// 'surprise', i.e. it wasn't matched by a line in the
// .txa file that didn't include the keyword 'cont'.
////////////////////////////////////////////////////////////////////
bool TextureImage::
is_surprise() const {
return _is_surprise;
}
////////////////////////////////////////////////////////////////////
// Function: TextureImage::get_source
@ -359,6 +389,7 @@ get_source(const Filename &filename, const Filename &alpha_filename) {
// next time someone asks.
_preferred_source = (SourceTextureImage *)NULL;
_read_source_image = false;
_got_dest_image = false;
return source;
}
@ -387,6 +418,62 @@ get_preferred_source() {
return _preferred_source;
}
////////////////////////////////////////////////////////////////////
// Function: TextureImage::copy_unplaced
// Access: Public
// Description: Copies the texture to whichever destination
// directories are appropriate for the groups in which
// it has been unplaced. Also removes the old filenames
// for previous sessions where it was unplaced, but is
// no longer.
////////////////////////////////////////////////////////////////////
void TextureImage::
copy_unplaced() {
// First, we need to build up the set of DestTextureImages that
// represents the files we need to generate.
Dests generate;
// Go through all the TexturePlacements and note the ones for which
// we're unplaced. We check get_omit_reason() and not is_placed(),
// because we want to consider solitary images to be unplaced in
// this case.
Placement::iterator pi;
for (pi = _placement.begin(); pi != _placement.end(); ++pi) {
TexturePlacement *placement = (*pi).second;
if (placement->get_omit_reason() != OR_none) {
DestTextureImage *dest = new DestTextureImage(placement);
Filename filename = dest->get_filename();
filename.make_canonical();
pair<Dests::iterator, bool> insert_result = generate.insert
(Dests::value_type(filename, dest));
if (!insert_result.second) {
// At least two DestTextureImages map to the same filename, no
// sweat.
delete dest;
dest = (*insert_result.first).second;
}
placement->set_dest(dest);
}
}
// Now remove the old files that we previously generated, but we
// don't need any more.
remove_old_dests(generate, _dests);
// And then copy in the new ones.
copy_new_dests(generate, _dests);
// Clean up the old set.
Dests::iterator di;
for (di = _dests.begin(); di != _dests.end(); ++di) {
delete (*di).second;
}
_dests.swap(generate);
}
////////////////////////////////////////////////////////////////////
// Function: TextureImage::read_source_image
// Access: Public
@ -406,6 +493,27 @@ read_source_image() {
return _source_image;
}
////////////////////////////////////////////////////////////////////
// Function: TextureImage::get_dest_image
// Access: Public
// Description: Returns the image appropriate for writing to the
// destination directory, having been resized and
// everything.
////////////////////////////////////////////////////////////////////
const PNMImage &TextureImage::
get_dest_image() {
if (!_got_dest_image) {
const PNMImage &source_image = read_source_image();
_dest_image.clear(get_x_size(), get_y_size(), get_num_channels(),
source_image.get_maxval());
_dest_image.quick_filter_from(source_image);
_got_dest_image = true;
}
return _dest_image;
}
////////////////////////////////////////////////////////////////////
// Function: TextureImage::write_source_pathnames
// Access: Public
@ -464,7 +572,7 @@ write_scale_info(ostream &out, int indent_level) {
double scale =
100.0 * (((double)get_x_size() / (double)source->get_x_size()) +
((double)get_y_size() / (double)source->get_y_size())) / 2.0;
out << " " << scale << "%";
out << " scale " << scale << "%";
}
out << "\n";
}
@ -483,7 +591,7 @@ compute_egg_count(PaletteGroup *group,
WorkingEggs::const_iterator ei;
for (ei = egg_files.begin(); ei != egg_files.end(); ++ei) {
if ((*ei)->get_groups().count(group) != 0) {
if ((*ei)->get_complete_groups().count(group) != 0) {
count++;
}
}
@ -589,6 +697,88 @@ consider_grayscale() {
_properties._num_channels -= 2;
}
////////////////////////////////////////////////////////////////////
// Function: TextureImage::remove_old_dests
// Access: Private
// Description: Removes all of the filenames named in b that are not
// also named in a.
////////////////////////////////////////////////////////////////////
void TextureImage::
remove_old_dests(const TextureImage::Dests &a, const TextureImage::Dests &b) {
Dests::const_iterator ai = a.begin();
Dests::const_iterator bi = b.begin();
while (ai != a.end() && bi != b.end()) {
const string &astr = (*ai).first;
const string &bstr = (*bi).first;
if (astr < bstr) {
// Here's a filename in a, not in b.
++ai;
} else if (bstr < astr) {
// Here's a filename in b, not in a.
(*bi).second->unlink();
++bi;
} else { // bstr == astr
// Here's a filename in both a and b.
++ai;
++bi;
}
}
while (bi != b.end()) {
// Here's a filename in b, not in a.
(*bi).second->unlink();
++bi;
}
while (ai != a.end()) {
++ai;
}
}
////////////////////////////////////////////////////////////////////
// Function: TextureImage::copy_new_dests
// Access: Private
// Description: Copies a resized texture into each filename named in
// a that is not also listed in b, or whose
// corresponding listing in b is out of date.
////////////////////////////////////////////////////////////////////
void TextureImage::
copy_new_dests(const TextureImage::Dests &a, const TextureImage::Dests &b) {
Dests::const_iterator ai = a.begin();
Dests::const_iterator bi = b.begin();
while (ai != a.end() && bi != b.end()) {
const string &astr = (*ai).first;
const string &bstr = (*bi).first;
if (astr < bstr) {
// Here's a filename in a, not in b.
(*ai).second->copy(this);
++ai;
} else if (bstr < astr) {
// Here's a filename in b, not in a.
++bi;
} else { // bstr == astr
// Here's a filename in both a and b.
(*ai).second->copy_if_stale((*bi).second, this);
++ai;
++bi;
}
}
while (ai != a.end()) {
// Here's a filename in a, not in b.
(*ai).second->copy(this);
++ai;
}
}
////////////////////////////////////////////////////////////////////
// Function: TextureImage::register_with_read_factory
// Access: Public, Static
@ -621,6 +811,8 @@ write_datagram(BamWriter *writer, Datagram &datagram) {
// We don't write out _preferred_source; this is redetermined each
// session.
datagram.add_bool(_is_surprise);
// We don't write out _explicitly_assigned_groups; this is re-read
// from the .txa file each time.
@ -641,8 +833,15 @@ write_datagram(BamWriter *writer, Datagram &datagram) {
writer->write_pointer(datagram, (*si).second);
}
// We don't write out _read_source_image or _source_image; this must
// be reread each session.
datagram.add_uint32(_dests.size());
Dests::const_iterator di;
for (di = _dests.begin(); di != _dests.end(); ++di) {
writer->write_pointer(datagram, (*di).second);
}
// We don't write out _read_source_image, _source_image,
// _got_dest_image, or _dest_image; these must be reread each
// session.
}
////////////////////////////////////////////////////////////////////
@ -656,7 +855,7 @@ write_datagram(BamWriter *writer, Datagram &datagram) {
////////////////////////////////////////////////////////////////////
int TextureImage::
complete_pointers(vector_typedWriteable &plist, BamReader *manager) {
nassertr((int)plist.size() >= _num_placement * 2 + _num_sources, 0);
nassertr((int)plist.size() >= _num_placement * 2 + _num_sources + _num_dests, 0);
int index = 0;
int i;
@ -680,6 +879,13 @@ complete_pointers(vector_typedWriteable &plist, BamReader *manager) {
index++;
}
for (i = 0; i < _num_dests; i++) {
DestTextureImage *dest;
DCAST_INTO_R(dest, plist[index], index);
_dests.insert(Dests::value_type(dest->get_filename(), dest));
index++;
}
return index;
}
@ -716,6 +922,8 @@ fillin(DatagramIterator &scan, BamReader *manager) {
ImageFile::fillin(scan, manager);
set_name(scan.get_string());
_is_surprise = scan.get_bool();
_actual_assigned_groups.fillin(scan, manager);
_num_placement = scan.get_uint32();
@ -723,4 +931,6 @@ fillin(DatagramIterator &scan, BamReader *manager) {
_num_sources = scan.get_uint32();
manager->read_pointers(scan, this, _num_sources);
_num_dests = scan.get_uint32();
manager->read_pointers(scan, this, _num_dests);
}

View File

@ -20,6 +20,7 @@
#include <set>
class SourceTextureImage;
class DestTextureImage;
class TexturePlacement;
class EggFile;
@ -55,15 +56,17 @@ public:
bool get_omit() const;
double get_repeat_threshold() const;
int get_margin() const;
bool is_surprise() const;
SourceTextureImage *get_source(const Filename &filename,
const Filename &alpha_filename);
SourceTextureImage *get_preferred_source();
bool get_size();
void copy_unplaced();
const PNMImage &read_source_image();
const PNMImage &get_dest_image();
void write_source_pathnames(ostream &out, int indent_level = 0) const;
void write_scale_info(ostream &out, int indent_level = 0);
@ -71,6 +74,8 @@ public:
private:
typedef set<EggFile *> EggFiles;
typedef vector<EggFile *> WorkingEggs;
typedef map<string, SourceTextureImage *> Sources;
typedef map<string, DestTextureImage *> Dests;
static int compute_egg_count(PaletteGroup *group,
const WorkingEggs &egg_files);
@ -78,9 +83,14 @@ private:
void assign_to_groups(const PaletteGroups &groups);
void consider_grayscale();
void remove_old_dests(const Dests &a, const Dests &b);
void copy_new_dests(const Dests &a, const Dests &b);
private:
TextureRequest _request;
TextureProperties _pre_txa_properties;
SourceTextureImage *_preferred_source;
bool _is_surprise;
PaletteGroups _explicitly_assigned_groups;
PaletteGroups _actual_assigned_groups;
@ -90,11 +100,13 @@ private:
typedef map<PaletteGroup *, TexturePlacement *> Placement;
Placement _placement;
typedef map<string, SourceTextureImage *> Sources;
Sources _sources;
Dests _dests;
bool _read_source_image;
PNMImage _source_image;
bool _got_dest_image;
PNMImage _dest_image;
// The TypedWriteable interface follows.
@ -113,6 +125,7 @@ private:
// don't use them otherwise.
int _num_placement;
int _num_sources;
int _num_dests;
public:
static TypeHandle get_class_type() {

View File

@ -9,6 +9,7 @@
#include "paletteGroup.h"
#include "paletteImage.h"
#include "palettizer.h"
#include "eggFile.h"
#include <indent.h>
#include <datagram.h>
@ -30,6 +31,7 @@ TexturePlacement() {
_texture = (TextureImage *)NULL;
_group = (PaletteGroup *)NULL;
_image = (PaletteImage *)NULL;
_dest = (DestTextureImage *)NULL;
_has_uvs = false;
_size_known = false;
_is_filled = true;
@ -55,6 +57,7 @@ TexturePlacement(TextureImage *texture, PaletteGroup *group) :
}
_image = (PaletteImage *)NULL;
_dest = (DestTextureImage *)NULL;
_has_uvs = false;
_size_known = false;
_is_filled = false;
@ -119,8 +122,11 @@ get_group() const {
////////////////////////////////////////////////////////////////////
void TexturePlacement::
add_egg(TextureReference *reference) {
reference->mark_egg_stale();
/*
_has_uvs = false;
_size_known = false;
*/
_references.insert(reference);
}
@ -132,11 +138,53 @@ add_egg(TextureReference *reference) {
////////////////////////////////////////////////////////////////////
void TexturePlacement::
remove_egg(TextureReference *reference) {
_has_uvs = false;
_size_known = false;
reference->mark_egg_stale();
/*
_has_uvs = false;
_size_known = false;
*/
_references.erase(reference);
}
////////////////////////////////////////////////////////////////////
// Function: TexturePlacement::mark_eggs_stale
// Access: Public
// Description: Marks all the egg files that reference this placement
// stale. Presumably this is called after moving the
// texture around in the palette or something.
////////////////////////////////////////////////////////////////////
void TexturePlacement::
mark_eggs_stale() {
References::iterator ri;
for (ri = _references.begin(); ri != _references.end(); ++ri) {
TextureReference *reference = (*ri);
reference->mark_egg_stale();
}
}
////////////////////////////////////////////////////////////////////
// Function: TexturePlacement::set_dest
// Access: Public
// Description: Sets the DestTextureImage that corresponds to this
// texture as it was copied to the install directory.
////////////////////////////////////////////////////////////////////
void TexturePlacement::
set_dest(DestTextureImage *dest) {
_dest = dest;
}
////////////////////////////////////////////////////////////////////
// Function: TexturePlacement::get_dest
// Access: Public
// Description: Returns the DestTextureImage that corresponds to this
// texture as it was copied to the install directory.
////////////////////////////////////////////////////////////////////
DestTextureImage *TexturePlacement::
get_dest() const {
return _dest;
}
////////////////////////////////////////////////////////////////////
// Function: TexturePlacement::determine_size
// Access: Public
@ -358,7 +406,9 @@ get_y_size() const {
////////////////////////////////////////////////////////////////////
double TexturePlacement::
get_uv_area() const {
nassertr(_has_uvs, 0.0);
if (!_has_uvs) {
return 0.0;
}
TexCoordd range = _position._max_uv - _position._min_uv;
return range[0] * range[1];
@ -462,8 +512,7 @@ get_placed_y_size() const {
////////////////////////////////////////////////////////////////////
double TexturePlacement::
get_placed_uv_area() const {
nassertr(_has_uvs, 0.0);
nassertr(is_placed(), 0);
TexCoordd range = _placed._max_uv - _placed._min_uv;
return range[0] * range[1];
}
@ -502,8 +551,9 @@ force_replace() {
if (_image != (PaletteImage *)NULL) {
_image->unplace(this);
_image = (PaletteImage *)NULL;
_omit_reason = OR_working;
}
_omit_reason = OR_working;
mark_eggs_stale();
}
////////////////////////////////////////////////////////////////////
@ -519,7 +569,10 @@ force_replace() {
void TexturePlacement::
omit_solitary() {
nassertv(is_placed());
_omit_reason = OR_solitary;
if (_omit_reason != OR_solitary) {
mark_eggs_stale();
_omit_reason = OR_solitary;
}
}
////////////////////////////////////////////////////////////////////
@ -531,7 +584,10 @@ omit_solitary() {
void TexturePlacement::
not_solitary() {
nassertv(is_placed());
_omit_reason = OR_none;
if (_omit_reason != OR_none) {
mark_eggs_stale();
_omit_reason = OR_none;
}
}
////////////////////////////////////////////////////////////////////
@ -807,6 +863,9 @@ write_datagram(BamWriter *writer, Datagram &datagram) {
writer->write_pointer(datagram, _texture);
writer->write_pointer(datagram, _group);
writer->write_pointer(datagram, _image);
// We don't write _dest. That can safely be redetermined each
// session.
datagram.add_bool(_has_uvs);
datagram.add_bool(_size_known);

View File

@ -16,8 +16,8 @@
#include <set>
class TextureImage;
class DestTextureImage;
class PaletteGroup;
class PaletteImage;
class PalettePage;
@ -47,6 +47,10 @@ public:
void add_egg(TextureReference *reference);
void remove_egg(TextureReference *reference);
void mark_eggs_stale();
void set_dest(DestTextureImage *dest);
DestTextureImage *get_dest() const;
bool determine_size();
OmitReason get_omit_reason() const;
@ -83,6 +87,7 @@ private:
TextureImage *_texture;
PaletteGroup *_group;
PaletteImage *_image;
DestTextureImage *_dest;
bool _has_uvs;
bool _size_known;

View File

@ -7,8 +7,10 @@
#include "textureImage.h"
#include "paletteImage.h"
#include "sourceTextureImage.h"
#include "destTextureImage.h"
#include "texturePlacement.h"
#include "palettizer.h"
#include "eggFile.h"
#include <indent.h>
#include <eggTexture.h>
@ -32,6 +34,7 @@ TypeHandle TextureReference::_type_handle;
////////////////////////////////////////////////////////////////////
TextureReference::
TextureReference() {
_egg_file = (EggFile *)NULL;
_egg_tex = (EggTexture *)NULL;
_tex_mat = LMatrix3d::ident_mat();
_inv_tex_mat = LMatrix3d::ident_mat();
@ -62,7 +65,8 @@ TextureReference::
// extracted from an egg file.
////////////////////////////////////////////////////////////////////
void TextureReference::
from_egg(EggData *data, EggTexture *egg_tex) {
from_egg(EggFile *egg_file, EggData *data, EggTexture *egg_tex) {
_egg_file = egg_file;
_egg_tex = egg_tex;
_egg_data = data;
@ -112,6 +116,16 @@ from_egg(EggData *data, EggTexture *egg_tex) {
_wrap_v = egg_tex->determine_wrap_v();
}
////////////////////////////////////////////////////////////////////
// Function: TextureReference::get_egg_file
// Access: Public
// Description: Returns the EggFile that references this texture.
////////////////////////////////////////////////////////////////////
EggFile *TextureReference::
get_egg_file() const {
return _egg_file;
}
////////////////////////////////////////////////////////////////////
// Function: TextureReference::get_source
// Access: Public
@ -237,6 +251,19 @@ get_placement() const {
return _placement;
}
////////////////////////////////////////////////////////////////////
// Function: TextureReference::mark_egg_stale
// Access: Public
// Description: Marks the egg file that shares this reference as
// stale.
////////////////////////////////////////////////////////////////////
void TextureReference::
mark_egg_stale() {
if (_egg_file != (EggFile *)NULL) {
_egg_file->mark_stale();
}
}
////////////////////////////////////////////////////////////////////
// Function: TextureReference::update_egg
// Access: Public
@ -261,9 +288,9 @@ update_egg() {
// The texture does not appear on a palette. This is the easy
// case; we simply have to update the texture reference to the new
// texture location.
TextureImage *texture = _placement->get_texture();
nassertv(texture != (TextureImage *)NULL);
texture->update_egg_tex(_egg_tex);
DestTextureImage *dest = _placement->get_dest();
nassertv(dest != (DestTextureImage *)NULL);
dest->update_egg_tex(_egg_tex);
return;
}
@ -601,6 +628,7 @@ write_datagram(BamWriter *writer, Datagram &datagram) {
// We don't write _egg_tex, _egg_data, or _tex_mat; that's specific
// to the session.
writer->write_pointer(datagram, _egg_file);
writer->write_pointer(datagram, _source_texture);
writer->write_pointer(datagram, _placement);
@ -626,9 +654,14 @@ write_datagram(BamWriter *writer, Datagram &datagram) {
////////////////////////////////////////////////////////////////////
int TextureReference::
complete_pointers(vector_typedWriteable &plist, BamReader *manager) {
nassertr((int)plist.size() >= 2, 0);
nassertr((int)plist.size() >= 3, 0);
int index = 0;
if (plist[index] != (TypedWriteable *)NULL) {
DCAST_INTO_R(_egg_file, plist[index], index);
}
index++;
if (plist[index] != (TypedWriteable *)NULL) {
DCAST_INTO_R(_source_texture, plist[index], index);
}
@ -672,6 +705,7 @@ make_TextureReference(const FactoryParams &params) {
////////////////////////////////////////////////////////////////////
void TextureReference::
fillin(DatagramIterator &scan, BamReader *manager) {
manager->read_pointer(scan, this); // _egg_file
manager->read_pointer(scan, this); // _source_texture
manager->read_pointer(scan, this); // _placement

View File

@ -16,6 +16,7 @@
class TextureImage;
class SourceTextureImage;
class Filename;
class EggFile;
class EggData;
class EggTexture;
class EggGroupNode;
@ -34,8 +35,9 @@ public:
TextureReference();
~TextureReference();
void from_egg(EggData *data, EggTexture *egg_tex);
void from_egg(EggFile *egg_file, EggData *data, EggTexture *egg_tex);
EggFile *get_egg_file() const;
SourceTextureImage *get_source() const;
TextureImage *get_texture() const;
@ -50,6 +52,7 @@ public:
void clear_placement();
TexturePlacement *get_placement() const;
void mark_egg_stale();
void update_egg();
void output(ostream &out) const;
@ -68,8 +71,10 @@ private:
static LVector2d translate_uv(const TexCoordd &min_uv,
const TexCoordd &max_uv);
EggFile *_egg_file;
EggTexture *_egg_tex;
EggData *_egg_data;
LMatrix3d _tex_mat, _inv_tex_mat;
SourceTextureImage *_source_texture;
TexturePlacement *_placement;

View File

@ -56,10 +56,21 @@ parse(const string &line) {
vector_string::iterator wi;
for (wi = words.begin(); wi != words.end(); ++wi) {
_patterns.push_back(GlobPattern(*wi));
const string &word = (*wi);
// If the pattern ends in the string ".egg", and only if it ends
// in this string, it is deemed an egg pattern and will only be
// tested against egg files. If it ends in anything else, it is
// deemed a texture pattern and will only be tested against
// textures.
if (word.length() > 4 && word.substr(word.length() - 4) == ".egg") {
_egg_patterns.push_back(GlobPattern(word));
} else {
_texture_patterns.push_back(GlobPattern(*wi));
}
}
if (_patterns.empty()) {
if (_egg_patterns.empty() && _texture_patterns.empty()) {
nout << "No texture or egg filenames given.\n";
return false;
}
@ -229,8 +240,8 @@ match_egg(EggFile *egg_file) const {
bool matched_any = false;
Patterns::const_iterator pi;
for (pi = _patterns.begin();
pi != _patterns.end() && !matched_any;
for (pi = _egg_patterns.begin();
pi != _egg_patterns.end() && !matched_any;
++pi) {
matched_any = (*pi).matches(name);
}
@ -259,8 +270,7 @@ match_egg(EggFile *egg_file) const {
}
}
egg_file->_assigned_groups.make_union
(egg_file->_assigned_groups, _palette_groups);
egg_file->match_txa_groups(_palette_groups);
if (got_cont) {
// If we have the "cont" keyword, we should keep scanning for
@ -270,6 +280,8 @@ match_egg(EggFile *egg_file) const {
// Otherwise, in the normal case, a match ends the search for
// matches.
egg_file->clear_surprise();
return true;
}
@ -290,8 +302,8 @@ match_texture(TextureImage *texture) const {
bool matched_any = false;
Patterns::const_iterator pi;
for (pi = _patterns.begin();
pi != _patterns.end() && !matched_any;
for (pi = _texture_patterns.begin();
pi != _texture_patterns.end() && !matched_any;
++pi) {
matched_any = (*pi).matches(name);
}
@ -387,6 +399,8 @@ match_texture(TextureImage *texture) const {
// Otherwise, in the normal case, a match ends the search for
// matches.
texture->_is_surprise = false;
return true;
}
@ -398,7 +412,10 @@ match_texture(TextureImage *texture) const {
void TxaLine::
output(ostream &out) const {
Patterns::const_iterator pi;
for (pi = _patterns.begin(); pi != _patterns.end(); ++pi) {
for (pi = _texture_patterns.begin(); pi != _texture_patterns.end(); ++pi) {
out << (*pi) << " ";
}
for (pi = _egg_patterns.begin(); pi != _egg_patterns.end(); ++pi) {
out << (*pi) << " ";
}
out << ":";

View File

@ -39,7 +39,8 @@ public:
private:
typedef vector<GlobPattern> Patterns;
Patterns _patterns;
Patterns _texture_patterns;
Patterns _egg_patterns;
enum SizeType {
ST_none,