From c0d69295bee352600a27e7b3050e35454e1ea710 Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 5 Dec 2000 15:15:21 +0000 Subject: [PATCH] *** empty log message *** --- pandatool/src/egg-palettize-old/Sources.pp | 39 +- pandatool/src/egg-palettize/Sources.pp | 28 ++ .../egg-palettize/config_egg_palettize.cxx | 54 +++ pandatool/src/egg-palettize/eggPalettize.cxx | 427 ++++++++++++++++++ pandatool/src/egg-palettize/eggPalettize.h | 78 ++++ pandatool/src/egg-palettize/paletteGroup.cxx | 378 ++++++++++++++++ pandatool/src/egg-palettize/paletteGroup.h | 111 +++++ pandatool/src/egg-palettize/string_utils.cxx | 118 +++++ pandatool/src/egg-palettize/string_utils.h | 24 + 9 files changed, 1237 insertions(+), 20 deletions(-) create mode 100644 pandatool/src/egg-palettize/Sources.pp create mode 100644 pandatool/src/egg-palettize/config_egg_palettize.cxx create mode 100644 pandatool/src/egg-palettize/eggPalettize.cxx create mode 100644 pandatool/src/egg-palettize/eggPalettize.h create mode 100644 pandatool/src/egg-palettize/paletteGroup.cxx create mode 100644 pandatool/src/egg-palettize/paletteGroup.h create mode 100644 pandatool/src/egg-palettize/string_utils.cxx create mode 100644 pandatool/src/egg-palettize/string_utils.h diff --git a/pandatool/src/egg-palettize-old/Sources.pp b/pandatool/src/egg-palettize-old/Sources.pp index a836acbbd5..54a0035cf6 100644 --- a/pandatool/src/egg-palettize-old/Sources.pp +++ b/pandatool/src/egg-palettize-old/Sources.pp @@ -1,23 +1,22 @@ -#begin bin_target - #define TARGET egg-palettize-new - #define LOCAL_LIBS \ - eggbase progbase - #define OTHER_LIBS \ - egg:c linmath:c putil:c express:c pnmimage:c pnmimagetypes:c \ - pandaegg:m panda:m pandaexpress:m \ - dtoolutil:c dconfig:c dtool:m pystub +// #begin bin_target +// #define TARGET egg-palettize-new +// #define LOCAL_LIBS \ +// eggbase progbase +// #define OTHER_LIBS \ +// egg: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 \ - attribFile.cxx attribFile.h config_egg_palettize.cxx \ - eggPalettize.cxx eggPalettize.h \ - palette.cxx palette.h paletteGroup.cxx \ - paletteGroup.h pTexture.cxx pTexture.h sourceEgg.cxx \ - sourceEgg.h string_utils.cxx string_utils.h \ - textureEggRef.cxx textureEggRef.h textureOmitReason.h \ - texturePacking.cxx \ - texturePacking.h userAttribLine.cxx userAttribLine.h +// #define SOURCES \ +// attribFile.cxx attribFile.h config_egg_palettize.cxx \ +// eggPalettize.cxx eggPalettize.h \ +// palette.cxx palette.h paletteGroup.cxx \ +// paletteGroup.h pTexture.cxx pTexture.h sourceEgg.cxx \ +// sourceEgg.h string_utils.cxx string_utils.h \ +// textureEggRef.cxx textureEggRef.h textureOmitReason.h \ +// texturePacking.cxx \ +// texturePacking.h userAttribLine.cxx userAttribLine.h - #define INSTALL_HEADERS - -#end bin_target +// #define INSTALL_HEADERS +// #end bin_target diff --git a/pandatool/src/egg-palettize/Sources.pp b/pandatool/src/egg-palettize/Sources.pp new file mode 100644 index 0000000000..2a80bfe315 --- /dev/null +++ b/pandatool/src/egg-palettize/Sources.pp @@ -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 + diff --git a/pandatool/src/egg-palettize/config_egg_palettize.cxx b/pandatool/src/egg-palettize/config_egg_palettize.cxx new file mode 100644 index 0000000000..88fe73eb32 --- /dev/null +++ b/pandatool/src/egg-palettize/config_egg_palettize.cxx @@ -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 + +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(); +} diff --git a/pandatool/src/egg-palettize/eggPalettize.cxx b/pandatool/src/egg-palettize/eggPalettize.cxx new file mode 100644 index 0000000000..8539facf4d --- /dev/null +++ b/pandatool/src/egg-palettize/eggPalettize.cxx @@ -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 +#include +#include +#include + +#include + +//////////////////////////////////////////////////////////////////// +// 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; +} + + diff --git a/pandatool/src/egg-palettize/eggPalettize.h b/pandatool/src/egg-palettize/eggPalettize.h new file mode 100644 index 0000000000..791a68f6c2 --- /dev/null +++ b/pandatool/src/egg-palettize/eggPalettize.h @@ -0,0 +1,78 @@ +// Filename: eggPalettize.h +// Created by: drose (28Nov00) +// +//////////////////////////////////////////////////////////////////// + +#ifndef EGGPALETTIZE_H +#define EGGPALETTIZE_H + +#include + +#include "txaFile.h" + +#include + +#include + +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 diff --git a/pandatool/src/egg-palettize/paletteGroup.cxx b/pandatool/src/egg-palettize/paletteGroup.cxx new file mode 100644 index 0000000000..481b093dd7 --- /dev/null +++ b/pandatool/src/egg-palettize/paletteGroup.cxx @@ -0,0 +1,378 @@ +// Filename: paletteGroup.cxx +// Created by: drose (30Nov00) +// +//////////////////////////////////////////////////////////////////// + +#include "paletteGroup.h" +#include "palettePage.h" +#include "texturePlacement.h" +#include "textureImage.h" + +#include +#include +#include +#include +#include + +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::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 ¶ms) { + 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); +} diff --git a/pandatool/src/egg-palettize/paletteGroup.h b/pandatool/src/egg-palettize/paletteGroup.h new file mode 100644 index 0000000000..5f9181e778 --- /dev/null +++ b/pandatool/src/egg-palettize/paletteGroup.h @@ -0,0 +1,111 @@ +// Filename: paletteGroup.h +// Created by: drose (28Nov00) +// +//////////////////////////////////////////////////////////////////// + +#ifndef PALETTEGROUP_H +#define PALETTEGROUP_H + +#include + +#include "paletteGroups.h" +#include "textureProperties.h" + +#include +#include + +#include + +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 Placements; + Placements _placements; + + typedef map 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 ¶ms); + 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 _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 + diff --git a/pandatool/src/egg-palettize/string_utils.cxx b/pandatool/src/egg-palettize/string_utils.cxx new file mode 100644 index 0000000000..ad4fdb6971 --- /dev/null +++ b/pandatool/src/egg-palettize/string_utils.cxx @@ -0,0 +1,118 @@ +// Filename: string_utils.cxx +// Created by: drose (30Nov00) +// +//////////////////////////////////////////////////////////////////// + +#include "string_utils.h" + +#include +#include + + +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 ¶m, 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; +} + + diff --git a/pandatool/src/egg-palettize/string_utils.h b/pandatool/src/egg-palettize/string_utils.h new file mode 100644 index 0000000000..af6e24da45 --- /dev/null +++ b/pandatool/src/egg-palettize/string_utils.h @@ -0,0 +1,24 @@ +// Filename: string_utils.h +// Created by: drose (30Nov00) +// +//////////////////////////////////////////////////////////////////// + +#ifndef STRING_UTILS_H +#define STRING_UTILS_H + +#include +#include + +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 ¶m, string &value); + +bool parse_image_type_request(const string &word, PNMFileType *&color_type, + PNMFileType *&alpha_type); + +#endif +