*** empty log message ***

This commit is contained in:
David Rose 2000-12-05 15:15:21 +00:00
parent caddc5b207
commit c0d69295be
9 changed files with 1237 additions and 20 deletions

View File

@ -1,23 +1,22 @@
#begin bin_target // #begin bin_target
#define TARGET egg-palettize-new // #define TARGET egg-palettize-new
#define LOCAL_LIBS \ // #define LOCAL_LIBS \
eggbase progbase // eggbase progbase
#define OTHER_LIBS \ // #define OTHER_LIBS \
egg:c linmath:c putil:c express:c pnmimage:c pnmimagetypes:c \ // egg:c linmath:c putil:c express:c pnmimage:c pnmimagetypes:c \
pandaegg:m panda:m pandaexpress:m \ // pandaegg:m panda:m pandaexpress:m \
dtoolutil:c dconfig:c dtool:m pystub // dtoolutil:c dconfig:c dtool:m pystub
#define SOURCES \ // #define SOURCES \
attribFile.cxx attribFile.h config_egg_palettize.cxx \ // attribFile.cxx attribFile.h config_egg_palettize.cxx \
eggPalettize.cxx eggPalettize.h \ // eggPalettize.cxx eggPalettize.h \
palette.cxx palette.h paletteGroup.cxx \ // palette.cxx palette.h paletteGroup.cxx \
paletteGroup.h pTexture.cxx pTexture.h sourceEgg.cxx \ // paletteGroup.h pTexture.cxx pTexture.h sourceEgg.cxx \
sourceEgg.h string_utils.cxx string_utils.h \ // sourceEgg.h string_utils.cxx string_utils.h \
textureEggRef.cxx textureEggRef.h textureOmitReason.h \ // textureEggRef.cxx textureEggRef.h textureOmitReason.h \
texturePacking.cxx \ // texturePacking.cxx \
texturePacking.h userAttribLine.cxx userAttribLine.h // texturePacking.h userAttribLine.cxx userAttribLine.h
#define INSTALL_HEADERS // #define INSTALL_HEADERS
#end bin_target
// #end bin_target

View File

@ -0,0 +1,28 @@
#begin bin_target
#define TARGET egg-palettize
#define LOCAL_LIBS \
eggbase progbase
#define OTHER_LIBS \
egg:c loader:c linmath:c putil:c express:c pnmimage:c pnmimagetypes:c \
pandaegg:m panda:m pandaexpress:m \
dtoolutil:c dconfig:c dtool:m pystub
#define SOURCES \
config_egg_palettize.cxx config_egg_palettize.h \
eggFile.cxx eggFile.h eggPalettize.cxx eggPalettize.h \
imageFile.cxx imageFile.h omitReason.cxx omitReason.h \
paletteGroup.h paletteGroup.cxx \
paletteGroups.h paletteGroups.cxx paletteImage.h paletteImage.cxx \
palettePage.cxx palettePage.h \
palettizer.cxx palettizer.h \
sourceTextureImage.cxx sourceTextureImage.h string_utils.cxx \
string_utils.h textureImage.cxx textureImage.h \
texturePlacement.cxx texturePlacement.h \
texturePosition.cxx texturePosition.h \
textureProperties.cxx textureProperties.h textureReference.cxx \
textureReference.h textureRequest.h textureRequest.cxx \
txaFile.cxx txaFile.h \
txaLine.cxx txaLine.h
#end bin_target

View File

@ -0,0 +1,54 @@
// Filename: config_egg_palettize.cxx
// Created by: drose (01Dec00)
//
////////////////////////////////////////////////////////////////////
#include "config_egg_palettize.h"
#include "palettizer.h"
#include "eggFile.h"
#include "paletteGroup.h"
#include "paletteGroups.h"
#include "textureReference.h"
#include "textureProperties.h"
#include "imageFile.h"
#include "sourceTextureImage.h"
#include "textureImage.h"
#include "paletteImage.h"
#include "texturePlacement.h"
#include "texturePosition.h"
#include "palettePage.h"
#include <dconfig.h>
Configure(config_egg_palettize);
ConfigureFn(config_egg_palettize) {
Palettizer::init_type();
EggFile::init_type();
PaletteGroup::init_type();
PaletteGroups::init_type();
TextureReference::init_type();
TextureProperties::init_type();
ImageFile::init_type();
SourceTextureImage::init_type();
TextureImage::init_type();
PaletteImage::init_type();
TexturePlacement::init_type();
TexturePosition::init_type();
PalettePage::init_type();
// Registration of writeable object's creation functions with
// BamReader's factory
Palettizer::register_with_read_factory();
EggFile::register_with_read_factory();
PaletteGroup::register_with_read_factory();
PaletteGroups::register_with_read_factory();
TextureReference::register_with_read_factory();
TextureProperties::register_with_read_factory();
SourceTextureImage::register_with_read_factory();
TextureImage::register_with_read_factory();
PaletteImage::register_with_read_factory();
TexturePlacement::register_with_read_factory();
TexturePosition::register_with_read_factory();
PalettePage::register_with_read_factory();
}

View File

@ -0,0 +1,427 @@
// Filename: eggPalettize.cxx
// Created by: drose (28Nov00)
//
////////////////////////////////////////////////////////////////////
#include "eggPalettize.h"
#include "palettizer.h"
#include "eggFile.h"
#include "string_utils.h"
#include <pnmFileTypeRegistry.h>
#include <pnmFileType.h>
#include <eggData.h>
#include <bamFile.h>
#include <stdio.h>
////////////////////////////////////////////////////////////////////
// Function: EggPalettize::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
EggPalettize::
EggPalettize() : EggMultiFilter(true) {
set_program_description
("egg-palettize attempts to pack several texture maps from various models "
"together into one or more palette images, for improved rendering performance "
"and ease of texture management. It can also resize textures on the fly, "
"whether or not they are actually placed on a palette.\n\n"
"egg-palettize reads and writes an AttributesFile, which contains instructions "
"from the user about resizing particular textures, as well as the complete "
"information necessary to reconstruct the palettization from past runs, "
"including references to other egg files that may share this palette. This "
"is designed to allow multiple egg files to use the same palette, without "
"having to process them all at once.\n\n"
"Note that it is not even necessary to specify any egg files at all on the "
"command line; egg-palettize can be run on an existing AttributesFiles by "
"itself to freshen up a palette when necessary.");
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
("a", "filename", 0,
"Read the indicated file as the .txa file. The default is textures.txa.",
&EggPalettize::dispatch_filename, NULL, &_txa_filename);
add_option
("pi", "", 0,
"Do not process anything, but instead report the detailed palettization "
"information.",
&EggPalettize::dispatch_none, &_report_pi);
add_option
("s", "", 0,
"Do not process anything, but report statistics on palette "
"and texture itilization.",
&EggPalettize::dispatch_none, &_statistics_only);
// We redefine -d using add_option() instead of redescribe_option()
// so it gets listed along with these other options that relate.
add_option
("d", "dirname", 0,
"The directory in which to write the palettized egg files. This is "
"only necessary if more than one egg file is processed at the same "
"time; if it is included, each egg file will be processed and written "
"into the indicated directory.",
&EggPalettize::dispatch_filename, &_got_output_dirname, &_output_dirname);
add_option
("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, "
"this will be replaced with the \"dir\" string associated with a "
"palette group.",
&EggPalettize::dispatch_string, &_got_map_dirname, &_map_dirname);
add_option
("dr", "dirname", 0,
"The directory to make map filenames relative to when writing egg "
"files. If specified, this should be an initial substring of -dm.",
&EggPalettize::dispatch_filename, &_got_rel_dirname, &_rel_dirname);
add_option
("g", "group", 0,
"The default palette group that egg files will be assigned to if they "
"are not explicitly assigned to any other group.",
&EggPalettize::dispatch_string, &_got_default_groupname, &_default_groupname);
add_option
("gdir", "name", 0,
"The \"dir\" string to associate with the default palette group "
"specified with -g, if no other dir name is given in the .txa file.",
&EggPalettize::dispatch_string, &_got_default_groupdir, &_default_groupdir);
add_option
("f", "", 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 "
"to be rebuilt if necessary to optimize the packing, but this "
"may invalidate other egg files which share this palette.",
&EggPalettize::dispatch_none, &_force_optimal);
add_option
("F", "", 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);
add_option
("R", "", 0,
"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);
add_option
("C", "", 0,
"Aggressively keep the map directory clean by deleting unused "
"textures from previous passes. This will remain in effect across "
"future sessions until -offC is specified.",
&EggPalettize::dispatch_none, &_aggressively_clean_mapdir);
add_option
("offC", "", 0,
"Turn off the aggressive cleaning specified by a past -C.",
&EggPalettize::dispatch_none, &_off_aggressively_clean_mapdir);
add_option
("2", "", 0,
"Force textures that have been left out of the palette to a size "
"which is an integer power of 2. They will be scaled down to "
"achieve this. This will remain in effect across future sessions "
"until -off2 is specified.",
&EggPalettize::dispatch_none, &_force_power_2);
add_option
("off2", "", 0,
"Turn off the power-of-2 scaling specified by a past -2.",
&EggPalettize::dispatch_none, &_off_force_power_2);
add_option
("type", "imagetype[,alphatype]", 0,
"Specify the type of image file to output. All image files, whether "
"palettes or unplaced textures, will be converted to files of this "
"type. If the optional alpha type is specified, then an alpha channel, "
"if present, will be written as a separate file of the indicated "
"type--useful if the primary image type does not support alpha. "
"Use '-type list' to show the available image types.",
&EggPalettize::dispatch_string, &_got_image_type, &_image_type);
add_option
("m", "margin", 0,
"Specify the default margin size.",
&EggPalettize::dispatch_int, &_got_margin, &_margin);
add_option
("r", "percent", 0,
"A repeating texture may still be palettized if it does not repeat "
"very many times, by adding multiple adjacent copies of the "
"texture to the palette. This parameter specifies the cutoff "
"threshold for this. This is the maximum "
"percentage a texture will be expanded to palettize a repeating "
"texture. If this is set to 100, no repeating textures will be "
"palettized; if this is set to 200, a texture that repeats twice "
"will be palettized by adding it to the palette twice.",
&EggPalettize::dispatch_double, &_got_repeat_threshold, &_repeat_threshold);
add_option
("P", "x,y", 0,
"Specify the default palette size.",
&EggPalettize::dispatch_int_pair, &_got_palette_size, _pal_size);
add_option
("nolock", "", 0,
"Don't attempt to lock the .pi file before rewriting it. Use "
"with extreme caution, as multiple processes running on the same "
".pi file may overwrite each other. Use this only if the lock "
"cannot be achieved for some reason.",
&EggPalettize::dispatch_none, &_dont_lock_pi);
add_option
("H", "", 0,
"Describe the syntax of the attributes file.",
&EggPalettize::dispatch_none, &_describe_input_file);
_txa_filename = "textures.txa";
_color_type = (PNMFileType *)NULL;
_alpha_type = (PNMFileType *)NULL;
}
////////////////////////////////////////////////////////////////////
// Function: EggPalettize::handle_args
// Access: Protected, Virtual
// Description: Does something with the additional arguments on the
// command line (after all the -options have been
// parsed). Returns true if the arguments are good,
// false otherwise.
////////////////////////////////////////////////////////////////////
bool EggPalettize::
handle_args(ProgramBase::Args &args) {
if (_describe_input_file) {
describe_input_file();
exit(1);
}
if (_got_image_type) {
if (_image_type == "list" ||
!parse_image_type_request(_image_type, _color_type, _alpha_type)) {
nout << "\nKnown image types are:\n";
PNMFileTypeRegistry::get_ptr()->write_types(nout, 2);
nout << "\n";
exit(1);
}
}
return EggMultiFilter::handle_args(args);
}
////////////////////////////////////////////////////////////////////
// Function: EggPalettize::describe_input_file
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void EggPalettize::
describe_input_file() {
nout <<
"An attributes file consists mostly of lines describing desired sizes of "
"texture maps. The format resembles, but is not identical to, that of "
"the qtess input file. Examples:\n\n"
" texturename.rgb : 64 64\n"
" texture-a.rgb texture-b.rgb : 32 16 2\n"
" *.rgb : 50%\n"
" eyelids.rgb : 16 16 omit\n\n"
"In general, each line consists of one or more filenames (and can "
"contain shell globbing characters like '*' or '?'), and a colon "
"followed by a size request. For each texture appearing in an egg "
"file, the input list is scanned from the beginning and the first "
"line that matches the filename defines the size of the texture.\n\n"
"A size request may be either a pair of numbers, giving a specific x y "
"size of the texture, or it may be a scale factor in the form of a "
"percentage. It may also include an additional number, giving a margin "
"for this particular texture (otherwise the default margin is "
"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"
"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"
"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";
}
////////////////////////////////////////////////////////////////////
// Function: EggPalettize::run
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void EggPalettize::
run() {
if (!_txa_filename.exists()) {
nout << _txa_filename << " does not exist; cannot run.\n";
exit(1);
}
Filename pi_filename = _txa_filename;
pi_filename.set_extension("boo");
BamFile pi_file;
if (!pi_filename.exists()) {
nout << pi_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";
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";
exit(1);
}
if (!obj->is_of_type(Palettizer::get_class_type())) {
nout << pi_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();
pal = DCAST(Palettizer, obj);
}
if (_report_pi) {
pal->report_pi();
exit(0);
}
if (_got_image_type) {
pal->_color_type = _color_type;
pal->_alpha_type = _alpha_type;
}
if (_got_margin) {
pal->_margin = _margin;
}
if (_got_repeat_threshold) {
pal->_repeat_threshold = _repeat_threshold;
}
if (_got_palette_size) {
pal->_pal_x_size = _pal_size[0];
pal->_pal_y_size = _pal_size[1];
}
if (_force_power_2) {
pal->_force_power_2 = true;
}
if (_off_force_power_2) {
pal->_force_power_2 = false;
}
if (_aggressively_clean_mapdir) {
pal->_aggressively_clean_mapdir = true;
}
if (_off_aggressively_clean_mapdir) {
pal->_aggressively_clean_mapdir = false;
}
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);
}
Eggs::const_iterator ei;
for (ei = _eggs.begin(); ei != _eggs.end(); ++ei) {
EggData *egg_data = (*ei);
Filename source_filename = egg_data->get_egg_filename();
Filename dest_filename = get_output_filename(source_filename);
string name = source_filename.get_basename();
EggFile *egg_file = pal->get_egg_file(name);
egg_file->from_command_line(egg_data, source_filename, dest_filename);
pal->_command_line_eggs.push_back(egg_file);
}
pal->run(txa_file);
if (!pi_file.open_write(pi_filename) ||
!pi_file.write_object(pal)) {
nout << "Unable to write palettization information to " << pi_filename
<< "\n";
exit(1);
}
pi_file.close();
write_eggs();
}
int
main(int argc, char *argv[]) {
EggPalettize prog;
prog.parse_command_line(argc, argv);
prog.run();
return 0;
}

View File

@ -0,0 +1,78 @@
// Filename: eggPalettize.h
// Created by: drose (28Nov00)
//
////////////////////////////////////////////////////////////////////
#ifndef EGGPALETTIZE_H
#define EGGPALETTIZE_H
#include <pandatoolbase.h>
#include "txaFile.h"
#include <eggMultiFilter.h>
#include <vector>
class PNMFileType;
class EggFile;
class PaletteGroup;
class TextureImage;
////////////////////////////////////////////////////////////////////
// Class : EggPalettize
// Description : This is the program wrapper for egg-palettize, but it
// mainly serves to read in all the command-line
// parameters and then invoke the Palettizer.
////////////////////////////////////////////////////////////////////
class EggPalettize : public EggMultiFilter {
public:
EggPalettize();
virtual bool handle_args(Args &args);
void describe_input_file();
void run();
// The following parameter values specifically relate to textures
// and palettes. These values are copied to the Palettizer.
Filename _txa_filename;
string _map_dirname;
bool _got_map_dirname;
Filename _rel_dirname;
bool _got_rel_dirname;
string _default_groupname;
bool _got_default_groupname;
string _default_groupdir;
bool _got_default_groupdir;
int _pal_size[2];
bool _got_palette_size;
int _margin;
bool _got_margin;
double _repeat_threshold;
bool _got_repeat_threshold;
bool _force_power_2;
bool _off_force_power_2;
bool _aggressively_clean_mapdir;
bool _off_aggressively_clean_mapdir;
string _image_type;
bool _got_image_type;
PNMFileType *_color_type;
PNMFileType *_alpha_type;
private:
// The following values control behavior specific to this session.
// They're not saved for future sessions.
bool _report_pi;
bool _statistics_only;
bool _force_optimal;
bool _force_redo_all;
bool _optimal_resize;
bool _touch_eggs;
bool _dont_lock_pi;
bool _describe_input_file;
};
#endif

View File

@ -0,0 +1,378 @@
// Filename: paletteGroup.cxx
// Created by: drose (30Nov00)
//
////////////////////////////////////////////////////////////////////
#include "paletteGroup.h"
#include "palettePage.h"
#include "texturePlacement.h"
#include "textureImage.h"
#include <indent.h>
#include <datagram.h>
#include <datagramIterator.h>
#include <bamReader.h>
#include <bamWriter.h>
TypeHandle PaletteGroup::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
PaletteGroup::
PaletteGroup() {
_egg_count = 0;
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::set_dirname
// Access: Public
// Description: Sets the directory name associated with the palette
// group. This is an optional feature that can be used
// to place the maps for the different palette groups
// into different install directories.
////////////////////////////////////////////////////////////////////
void PaletteGroup::
set_dirname(const string &dirname) {
_dirname = dirname;
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::group_with
// Access: Public
// Description: Indicates a dependency of this group on some other
// group. This means that the textures assigned to this
// group may be considered successfully assigned if they
// are actually placed in the other group. In practice,
// this means that the textures associated with the
// other palette group will always be resident at
// runtime when textures from this palette group are
// required.
////////////////////////////////////////////////////////////////////
void PaletteGroup::
group_with(PaletteGroup *other) {
_dependent.insert(other);
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::get_groups
// Access: Public
// Description: Returns the set of groups this group depends on.
////////////////////////////////////////////////////////////////////
const PaletteGroups &PaletteGroup::
get_groups() const {
return _dependent;
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::increment_egg_count
// Access: Public
// Description: Increments by one the number of egg files that are
// known to reference this PaletteGroup. This is
// designed to aid the heuristics in texture placing;
// it's useful to know how many different egg files are
// sharing a particular PaletteGroup.
////////////////////////////////////////////////////////////////////
void PaletteGroup::
increment_egg_count() {
_egg_count++;
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::get_egg_count
// Access: Public
// Description: Returns the number of egg files that share this
// PaletteGroup.
////////////////////////////////////////////////////////////////////
int PaletteGroup::
get_egg_count() const {
return _egg_count;
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::get_page
// Access: Public
// Description: Returns the page associated with the indicated
// properties. If no page object has yet been created,
// creates one.
////////////////////////////////////////////////////////////////////
PalettePage *PaletteGroup::
get_page(const TextureProperties &properties) {
Pages::iterator pi = _pages.find(properties);
if (pi != _pages.end()) {
return (*pi).second;
}
PalettePage *page = new PalettePage(this, properties);
bool inserted = _pages.insert(Pages::value_type(properties, page)).second;
nassertr(inserted, page);
return page;
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::prepare
// Access: Public
// Description: Marks the indicated Texture as ready for placing
// somewhere within this group, and returns a
// placeholder TexturePlacement object. The texture is
// not placed immediately, but may be placed later when
// place_all() is called; at this time, the
// TexturePlacement fields will be filled in as
// appropriate.
////////////////////////////////////////////////////////////////////
TexturePlacement *PaletteGroup::
prepare(TextureImage *texture) {
TexturePlacement *placement = new TexturePlacement(texture, this);
_placements.insert(placement);
return placement;
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::unplace
// Access: Public
// Description: Removes the texture from its position on a
// PaletteImage, if it has been so placed.
////////////////////////////////////////////////////////////////////
void PaletteGroup::
unplace(TexturePlacement *placement) {
nassertv(placement->get_group() == this);
Placements::iterator pi;
pi = _placements.find(placement);
if (pi != _placements.end()) {
_placements.erase(pi);
if (placement->is_placed()) {
placement->get_page()->unplace(placement);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::place_all
// Access: Public
// Description: Once all the textures have been assigned to this
// group, try to place them all onto suitable
// PaletteImages.
////////////////////////////////////////////////////////////////////
void PaletteGroup::
place_all() {
// First, go through our prepared textures and assign each unplaced
// one to an appropriate page.
Placements::iterator pli;
for (pli = _placements.begin(); pli != _placements.end(); ++pli) {
TexturePlacement *placement = (*pli);
if (placement->get_omit_reason() == OR_working) {
PalettePage *page = get_page(placement->get_properties());
page->assign(placement);
}
}
// Then, go through the pages and actually do the placing.
Pages::iterator pai;
for (pai = _pages.begin(); pai != _pages.end(); ++pai) {
PalettePage *page = (*pai).second;
page->place_all();
}
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::write_image_info
// Access: Public
// Description: Writes a list of the PaletteImages associated with
// this group, and all of their textures, to the
// indicated output stream.
////////////////////////////////////////////////////////////////////
void PaletteGroup::
write_image_info(ostream &out, int indent_level) const {
Pages::const_iterator pai;
for (pai = _pages.begin(); pai != _pages.end(); ++pai) {
PalettePage *page = (*pai).second;
page->write_image_info(out, indent_level);
}
Placements::iterator pli;
for (pli = _placements.begin(); pli != _placements.end(); ++pli) {
TexturePlacement *placement = (*pli);
if (placement->get_omit_reason() != OR_none) {
indent(out, indent_level)
<< placement->get_texture()->get_name()
<< " unplaced because ";
switch (placement->get_omit_reason()) {
case OR_repeats:
out << "repeats ("
<< floor(placement->get_uv_area() * 10000.0 + 0.5) / 100.0
<< "%)";
break;
case OR_size:
out << "size (" << placement->get_x_size() << " "
<< placement->get_y_size() << ")";
break;
default:
out << placement->get_omit_reason();
}
out << "\n";
}
}
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::update_images
// Access: Public
// Description: Regenerates each PaletteImage on this group that needs
// it.
////////////////////////////////////////////////////////////////////
void PaletteGroup::
update_images() {
Pages::iterator pai;
for (pai = _pages.begin(); pai != _pages.end(); ++pai) {
PalettePage *page = (*pai).second;
page->update_images();
}
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::register_with_read_factory
// Access: Public, Static
// Description: Registers the current object as something that can be
// read from a Bam file.
////////////////////////////////////////////////////////////////////
void PaletteGroup::
register_with_read_factory() {
BamReader::get_factory()->
register_factory(get_class_type(), make_PaletteGroup);
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::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 PaletteGroup::
write_datagram(BamWriter *writer, Datagram &datagram) {
datagram.add_string(get_name());
datagram.add_string(_dirname);
_dependent.write_datagram(writer, datagram);
datagram.add_uint32(_placements.size());
Placements::const_iterator pli;
for (pli = _placements.begin(); pli != _placements.end(); ++pli) {
writer->write_pointer(datagram, (*pli));
}
datagram.add_uint32(_pages.size());
Pages::const_iterator pai;
for (pai = _pages.begin(); pai != _pages.end(); ++pai) {
writer->write_pointer(datagram, (*pai).second);
}
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::complete_pointers
// Access: Public, Virtual
// Description: Called after the object is otherwise completely read
// from a Bam file, this function's job is to store the
// pointers that were retrieved from the Bam file for
// each pointer object written. The return value is the
// number of pointers processed from the list.
////////////////////////////////////////////////////////////////////
int PaletteGroup::
complete_pointers(vector_typedWriteable &plist, BamReader *manager) {
nassertr((int)plist.size() >= _num_placements + _num_pages, 0);
int index = 0;
int i;
for (i = 0; i < _num_placements; i++) {
TexturePlacement *placement;
DCAST_INTO_R(placement, plist[index], index);
index++;
bool inserted = _placements.insert(placement).second;
nassertr(inserted, index);
}
// We must store the list of pages in a temporary vector first. We
// can't put them directly into the map because the map requires
// that all the pointers in the page's get_properties() member have
// been filled in, which may not have happened yet.
_load_pages.reserve(_num_pages);
for (i = 0; i < _num_pages; i++) {
PalettePage *page;
DCAST_INTO_R(page, plist[index], index);
index++;
_load_pages.push_back(page);
}
return index;
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::finalize
// Access: Public, Virtual
// Description: This method is called by the BamReader after all
// pointers everywhere in the world have been completely
// read in. It's a hook at which the object can do
// whatever final setup it requires that depends on
// other pointers being valid.
////////////////////////////////////////////////////////////////////
void PaletteGroup::
finalize() {
// Now we can copy the pages into the actual map.
vector<PalettePage *>::const_iterator pi;
for (pi = _load_pages.begin(); pi != _load_pages.end(); ++pi) {
PalettePage *page = (*pi);
bool inserted = _pages.
insert(Pages::value_type(page->get_properties(), page)).second;
nassertv(inserted);
}
_load_pages.clear();
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::make_PaletteGroup
// Access: Protected, Static
// 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 *PaletteGroup::
make_PaletteGroup(const FactoryParams &params) {
PaletteGroup *me = new PaletteGroup;
BamReader *manager;
Datagram packet;
parse_params(params, manager, packet);
DatagramIterator scan(packet);
me->fillin(scan, manager);
manager->register_finalize(me);
return me;
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::fillin
// Access: Protected
// Description: Reads the binary data from the given datagram
// iterator, which was written by a previous call to
// write_datagram().
////////////////////////////////////////////////////////////////////
void PaletteGroup::
fillin(DatagramIterator &scan, BamReader *manager) {
set_name(scan.get_string());
_dirname = scan.get_string();
_dependent.fillin(scan, manager);
_num_placements = scan.get_uint32();
manager->read_pointers(scan, this, _num_placements);
_num_pages = scan.get_uint32();
manager->read_pointers(scan, this, _num_pages);
}

View File

@ -0,0 +1,111 @@
// Filename: paletteGroup.h
// Created by: drose (28Nov00)
//
////////////////////////////////////////////////////////////////////
#ifndef PALETTEGROUP_H
#define PALETTEGROUP_H
#include <pandatoolbase.h>
#include "paletteGroups.h"
#include "textureProperties.h"
#include <namable.h>
#include <typedWriteable.h>
#include <set>
class EggFile;
class TexturePlacement;
class PalettePage;
class TextureImage;
////////////////////////////////////////////////////////////////////
// Class : PaletteGroup
// Description : This is the highest level of grouping for
// TextureImages. Textures are assigned to one or
// several PaletteGroups based on the information in the
// .txa file; each PaletteGroup is conceptually a
// collection of textures that are to be moved around
// (into texture memory, downloaded, etc.) in one big
// chunk. It is the set of all textures that may be
// displayed together at any given time.
////////////////////////////////////////////////////////////////////
class PaletteGroup : public TypedWriteable, public Namable {
public:
PaletteGroup();
void set_dirname(const string &dirname);
void group_with(PaletteGroup *other);
const PaletteGroups &get_groups() const;
void increment_egg_count();
int get_egg_count() const;
PalettePage *get_page(const TextureProperties &properties);
TexturePlacement *prepare(TextureImage *texture);
void unplace(TexturePlacement *placement);
void place_all();
void write_image_info(ostream &out, int indent_level = 0) const;
void update_images();
private:
string _dirname;
int _egg_count;
PaletteGroups _dependent;
typedef set<TexturePlacement *> Placements;
Placements _placements;
typedef map<TextureProperties, PalettePage *> Pages;
Pages _pages;
// The TypedWriteable interface follows.
public:
static void register_with_read_factory();
virtual void write_datagram(BamWriter *writer, Datagram &datagram);
virtual int complete_pointers(vector_typedWriteable &plist,
BamReader *manager);
virtual void finalize();
protected:
static TypedWriteable *make_PaletteGroup(const FactoryParams &params);
void fillin(DatagramIterator &scan, BamReader *manager);
private:
// These values are only filled in while reading from the bam file;
// don't use them otherwise.
int _num_placements;
int _num_pages;
vector<PalettePage *> _load_pages;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
TypedWriteable::init_type();
Namable::init_type();
register_type(_type_handle, "PaletteGroup",
TypedWriteable::get_class_type(),
Namable::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
private:
static TypeHandle _type_handle;
friend class PaletteGroups;
};
#endif

View File

@ -0,0 +1,118 @@
// Filename: string_utils.cxx
// Created by: drose (30Nov00)
//
////////////////////////////////////////////////////////////////////
#include "string_utils.h"
#include <pnmFileType.h>
#include <pnmFileTypeRegistry.h>
string
trim_left(const string &str) {
size_t begin = 0;
while (begin < str.size() && isspace(str[begin])) {
begin++;
}
return str.substr(begin);
}
string
trim_right(const string &str) {
size_t begin = 0;
size_t end = str.size();
while (end > begin && isspace(str[end - 1])) {
end--;
}
return str.substr(begin, end - begin);
}
void
extract_words(const string &str, vector_string &words) {
size_t pos = 0;
while (pos < str.length() && isspace(str[pos])) {
pos++;
}
while (pos < str.length()) {
size_t word_start = pos;
while (pos < str.length() && !isspace(str[pos])) {
pos++;
}
words.push_back(str.substr(word_start, pos - word_start));
while (pos < str.length() && isspace(str[pos])) {
pos++;
}
}
}
// Extracts the first word of the string into param, and the remainder
// of the line into value.
void
extract_param_value(const string &str, string &param, string &value) {
size_t i = 0;
// First, skip all whitespace at the beginning.
while (i < str.length() && isspace(str[i])) {
i++;
}
size_t start = i;
// Now skip to the end of the whitespace.
while (i < str.length() && !isspace(str[i])) {
i++;
}
size_t end = i;
param = str.substr(start, end - start);
// Skip a little bit further to the start of the value.
while (i < str.length() && isspace(str[i])) {
i++;
}
value = trim_right(str.substr(i));
}
bool
parse_image_type_request(const string &word, PNMFileType *&color_type,
PNMFileType *&alpha_type) {
PNMFileTypeRegistry *registry = PNMFileTypeRegistry::get_ptr();
color_type = (PNMFileType *)NULL;
alpha_type = (PNMFileType *)NULL;
string color_name = word;
string alpha_name;
size_t comma = word.find(',');
if (comma != string::npos) {
// If we have a comma in the image_type, it's two types: a color
// type and an alpha type.
color_name = word.substr(0, comma);
alpha_name = word.substr(comma + 1);
}
if (!color_name.empty()) {
color_type = registry->get_type_from_extension(color_name);
if (color_type == (PNMFileType *)NULL) {
nout << "Image file type '" << color_name << "' is unknown.\n";
return false;
}
}
if (!alpha_name.empty()) {
alpha_type = registry->get_type_from_extension(alpha_name);
if (alpha_type == (PNMFileType *)NULL) {
nout << "Image file type '" << alpha_name << "' is unknown.\n";
return false;
}
}
return true;
}

View File

@ -0,0 +1,24 @@
// Filename: string_utils.h
// Created by: drose (30Nov00)
//
////////////////////////////////////////////////////////////////////
#ifndef STRING_UTILS_H
#define STRING_UTILS_H
#include <pandatoolbase.h>
#include <vector_string.h>
class PNMFileType;
string trim_left(const string &str);
string trim_right(const string &str);
void extract_words(const string &str, vector_string &words);
void extract_param_value(const string &str, string &param, string &value);
bool parse_image_type_request(const string &word, PNMFileType *&color_type,
PNMFileType *&alpha_type);
#endif