Panda3D
Loading...
Searching...
No Matches
eggPalettize.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file eggPalettize.cxx
10 * @author drose
11 * @date 2000-11-28
12 */
13
14#include "eggPalettize.h"
15#include "palettizer.h"
16#include "eggFile.h"
17#include "pal_string_utils.h"
18#include "filenameUnifier.h"
19
20#include "dcast.h"
21#include "eggData.h"
22#include "bamFile.h"
23#include "pnotify.h"
24#include "notifyCategory.h"
25#include "notifySeverity.h"
26
27#include <stdio.h>
28
29/**
30 *
31 */
32EggPalettize::
33EggPalettize() : EggMultiFilter(true) {
34 set_program_brief("pack textures from various .egg models into palette images");
35 set_program_description
36 ("egg-palettize attempts to pack several texture maps from various models "
37 "together into one or more palette images, for improved rendering performance "
38 "and ease of texture management. It can also resize textures and convert "
39 "them to another image file format, whether or not they are actually "
40 "placed on a palette, and can manage some "
41 "simple texture properties, like mipmapping and rendering "
42 "format.\n\n"
43
44 "egg-palettize reads a texture attributes file, usually named "
45 "textures.txa, which contains instructions from the user about "
46 "resizing particular textures. Type egg-palettize -H for an "
47 "introduction to the syntax of this file.\n\n"
48
49 "The palettization information from previous runs is recorded in a file "
50 "named textures.boo (assuming the attributes file is named "
51 "textures.txa); a complete record of every egg file and every texture "
52 "that has been referenced is kept here. This allows the program "
53 "to intelligently manage the multiple egg files that may reference "
54 "the textures in question.");
55
56
57 clear_runlines();
58 add_runline("[opts] file.egg [file.egg ...]");
59
60 // We always have EggMultiBase's -f on: force complete load. In fact, we
61 // use -f for our own purposes, below.
62 remove_option("f");
63 _force_complete = true;
64
65 add_option
66 ("af", "filename", 0,
67 "Read the indicated file as the .txa file. The default is textures.txa.",
68 &EggPalettize::dispatch_filename, &_got_txa_filename, &_txa_filename);
69
70 add_option
71 ("a", "filename", 0,
72 "Deprecated option. This is the same as -af.",
73 &EggPalettize::dispatch_filename, &_got_txa_filename, &_txa_filename);
74
75 add_option
76 ("as", "script", 0,
77 "Accept the script specified on the command line as the contents of the "
78 ".txa file, instead of reading a file on disk. This implies -nodb and "
79 "-opt.",
80 &EggPalettize::dispatch_string, &_got_txa_script, &_txa_script);
81
82 add_option
83 ("nodb", "", 0,
84 "Don't read or record the state information to a .boo file. By default, "
85 "the palettization information is recorded so it can be preserved "
86 "between multiple invocations of egg-palettize. If you specify this "
87 "parameter, all the egg files to be palettized together must be "
88 "named at the same time. This also implies -opt, since there's no point "
89 "in not making an optimal packing if you won't be preserving the "
90 "state for future adjustments.",
91 &EggPalettize::dispatch_none, &_nodb);
92
93 add_option
94 ("tn", "pattern", 0,
95 "Specify the name to generate for each palette image. The string should "
96 "contain %g for the group name, %p for the page name, and %i for the "
97 "index within the page. The extension is inferred from the image "
98 "type. The default is '%g_palette_%p_%i'.",
99 &EggPalettize::dispatch_string, &_got_generated_image_pattern,
100 &_generated_image_pattern);
101
102 add_option
103 ("pi", "", 0,
104 "Do not process anything, but instead report the detailed palettization "
105 "information written in the state file.",
106 &EggPalettize::dispatch_none, &_report_pi);
107
108 add_option
109 ("s", "", 0,
110 "Do not process anything, but report statistics on palette "
111 "and texture utilization from the state file.",
112 &EggPalettize::dispatch_none, &_report_statistics);
113
114 add_option
115 ("R", "", 0,
116 "Remove the named egg files from the previously-generated state data "
117 "file.",
118 &EggPalettize::dispatch_none, &_remove_eggs);
119
120 // We redefine -d using add_option() instead of redescribe_option() so it
121 // gets listed along with these other options that relate.
122 add_option
123 ("d", "dirname", 0,
124 "The directory in which to write the palettized egg files. This is "
125 "only necessary if more than one egg file is processed at the same "
126 "time; if it is included, each egg file will be processed and written "
127 "into the indicated directory.",
128 &EggPalettize::dispatch_filename, &_got_output_dirname, &_output_dirname);
129 add_option
130 ("dm", "dirname", 0,
131 "The directory in which to place all maps: generated palettes, "
132 "as well as images which were not placed on palettes "
133 "(but may have been resized). If this contains the string %g, "
134 "this will be replaced with the 'dir' string associated with a "
135 "palette group; see egg-palettize -H.",
136 &EggPalettize::dispatch_string, &_got_map_dirname, &_map_dirname);
137 add_option
138 ("ds", "dirname", 0,
139 "The directory to write palette shadow images to. These are working "
140 "copies of the palette images, useful when the palette image type is "
141 "a lossy-compression type like JPEG; you can avoid generational loss "
142 "of quality on the palette images with each pass through the palettes "
143 "by storing these extra shadow images in a lossless image type. This "
144 "directory is only used if the :shadowtype keyword appears in the .txa "
145 "file.",
146 &EggPalettize::dispatch_filename, &_got_shadow_dirname, &_shadow_dirname);
147 add_option
148 ("dr", "dirname", 0,
149 "The directory to make map filenames relative to when writing egg "
150 "files. If specified, this should be an initial substring of -dm.",
151 &EggPalettize::dispatch_filename, &_got_rel_dirname, &_rel_dirname);
152 add_option
153 ("g", "group", 0,
154 "The default palette group that egg files will be assigned to if they "
155 "are not explicitly assigned to any other group.",
156 &EggPalettize::dispatch_string, &_got_default_groupname, &_default_groupname);
157 add_option
158 ("gdir", "name", 0,
159 "The \"dir\" string to associate with the default palette group "
160 "specified with -g, if no other dir name is given in the .txa file.",
161 &EggPalettize::dispatch_string, &_got_default_groupdir, &_default_groupdir);
162
163 add_option
164 ("all", "", 0,
165 "Consider all the textures referenced in all egg files that have "
166 "ever been palettized, not just the egg files that appear on "
167 "the command line.",
168 &EggPalettize::dispatch_none, &_all_textures);
169 add_option
170 ("egg", "", 0,
171 "Regenerate all egg files that need modification, even those that "
172 "aren't named on the command line.",
173 &EggPalettize::dispatch_none, &_redo_eggs);
174 add_option
175 ("redo", "", 0,
176 "Force a regeneration of each image from its original source(s). "
177 "When used in conjunction with -egg, this also forces each egg file to "
178 "be regenerated.",
179 &EggPalettize::dispatch_none, &_redo_all);
180 add_option
181 ("opt", "", 0,
182 "Force an optimal packing. By default, textures are added to "
183 "existing palettes without disturbing them, which can lead to "
184 "suboptimal packing. Including this switch forces the palettes "
185 "to be rebuilt if necessary to optimize the packing, but this "
186 "may invalidate other egg files which share this palette.",
187 &EggPalettize::dispatch_none, &_optimal);
188 add_option
189 ("omitall", "", 0,
190 "Re-enables the flag to omit all textures. This flag is normally on "
191 "by default, causing nothing actually to be palettized, until the "
192 "first time egg-palettize is run with the -opt flag, which turns off "
193 "the omitall flag and thenceforth allows textures to be combined "
194 "into palettes. Specifying this flag restores the original behavior "
195 "of keeping every texture as a separate image (which is convenient for "
196 "development).",
197 &EggPalettize::dispatch_none, &_omitall);
198
199 // This isn't even implemented yet. Presently, we never lock anyway.
200 // Dangerous, but hard to implement reliable file locking across NFSSamba
201 // and between multiple OS's.
202 /*
203 add_option
204 ("nolock", "", 0,
205 "Don't attempt to grab a file lock on the .txa file. Use "
206 "with extreme caution, as multiple processes running on the same "
207 ".txa file may overwrite each other. Use this only if the lock "
208 "cannot be achieved for some reason.",
209 &EggPalettize::dispatch_none, &_dont_lock_txa);
210 */
211
212 add_option
213 ("H", "", 0,
214 "Describe the syntax of the attributes file.",
215 &EggPalettize::dispatch_none, &_describe_input_file);
216
217 _txa_filename = "textures.txa";
218}
219
220
221/**
222 * Does something with the additional arguments on the command line (after all
223 * the -options have been parsed). Returns true if the arguments are good,
224 * false otherwise.
225 */
228 if (_describe_input_file) {
229 describe_input_file();
230 exit(1);
231 }
232
233 if (_remove_eggs) {
234 // If we're removing these egg files from the database, we don't want to
235 // try to load them up. Instead, just save the filenames.
236 _remove_egg_list = args;
237 return true;
238 }
239
240 // Otherwise, load the named egg files up normally.
241 return EggMultiFilter::handle_args(args);
242}
243
244/**
245 *
246 */
247void EggPalettize::
248describe_input_file() {
249 nout <<
250 "An attributes file consists mostly of lines describing desired sizes of "
251 "texture maps. The format resembles, but is not identical to, that of "
252 "the qtess input file. Examples:\n\n"
253
254 " texturename.rgb : 64 64\n"
255 " texture-a.rgb texture-b.rgb : 32 16 margin 2\n"
256 " *.rgb : 50% cont\n"
257 " eyelids.rgb : 16 16 omit\n\n"
258
259 "In general, each line consists of one or more filenames (and can "
260 "contain shell globbing characters like '*' or '?'), and a colon "
261 "followed by a size request. For each texture appearing in an egg "
262 "file, the input list is scanned from the beginning and the first "
263 "line that matches the filename defines the size of the texture, as "
264 "well as other properties associated with the texture.\n\n"
265
266 "A size request is most often a pair of numbers, giving a specific x y "
267 "size of the texture. A third number may also be supplied, giving a "
268 "specific number of channels to convert to (for instance, to force an "
269 "image to a 64x64 grayscale image, set its size to 64 64 1). "
270 "Alternatively, a percentage scaling may be specified, e.g. 30%. The "
271 "requested size need not be a power of 2.\n\n"
272
273 "Other valid keywords that may be specified on the same line with the "
274 "texture are:\n\n";
275
276 show_text(" omit", 10,
277 "This indicates that the texture should not be placed on any "
278 "palette image. It may still be resized, and it will in any "
279 "case be copied into the install directory.\n\n");
280
281 show_text(" margin i", 10,
282 "This specifies the number of pixels that should be written "
283 "around the border of the texture when it is placed in a "
284 "palette image; i is the integer number of pixels. The "
285 "use of a margin helps cut down on color bleed "
286 "from neighboring images. If the texture does "
287 "not end up placed in a palette image, the "
288 "margin is not used. If not specified, the default margin is "
289 "used, which is specified by the :margin command (see below).\n\n");
290
291 show_text(" coverage f", 10,
292 "This parameter specifies the maximum coverage to allow for this "
293 "particular texture before rejecting it "
294 "from the palette. If not specified, the default is "
295 "specified by the :coverage command (see below).\n\n");
296
297 nout << " nearest\n"
298 << " linear\n";
299 show_text(" mipmap", 10,
300 "One of these options may be used to force the texture to use "
301 "a particular minfilter/magfilter sampling mode. If this is not "
302 "specified, the sampling mode specified in the egg file is "
303 "used. Textures that use different sampling modes cannot "
304 "be placed together on the same palette images.\n\n");
305
306 show_text(" rgba", 10,
307 "This specifies format 'rgba' should be in effect for this "
308 "particular texture. Any valid egg texture format, such as "
309 "rgba, rgba12, rgba8, rgb5, luminance, etc. may be specified. "
310 "If nothing is specified, the format specified in the egg file "
311 "is used. The format will automatically be downgraded to match "
312 "the number of channels in the texture image; e.g. rgba will "
313 "automatically be converted to rgb for a three-channel image. "
314 "As with the filter modes above, textures that use different "
315 "formats cannot be placed together on the same palette "
316 "images.\n\n");
317
318 show_text(" force-rgba", 10,
319 "This specifies a particular format, as above, that should be "
320 "in effect for this texture, but it will not be downgraded to "
321 "match the number of channels. As above, any valid egg texture "
322 "format may be used, e.g. force-rgba12, force-rgb5, etc.\n\n");
323
324 show_text(" keep-format", 10,
325 "This specifies that the image format requested by an egg file "
326 "should be exactly preserved, without attempting to optimize "
327 "it by, for instance, automatically downgrading.\n\n");
328
329 show_text(" generic", 10,
330 "Specifies that any image format requested by an egg file "
331 "that requests a particular bitdepth should be replaced by "
332 "its generic equivalent, e.g. rgba8 should become rgba.\n\n");
333
334 show_text(" (alpha mode)", 10,
335 "A particular alpha mode may be applied to a texture by naming "
336 "the alpha mode. This may be any valid egg alpha mode, e.g. "
337 "blend, binary, ms, or dual.\n\n");
338
339 show_text(" repeat_u, repeat_v, clamp_u, clamp_v", 10,
340 "Explcitly specify whether the source texture should repeat or "
341 "clamp in each direction. Although palette images are always "
342 "clamped, this will affect the pixels that are painted into "
343 "the palette image.\n\n");
344
345 show_text(" (image type)", 10,
346 "A texture may be converted to a particular image type, for "
347 "instance jpg or rgb, by naming the type. If present, this "
348 "overrides the :imagetype command, described below. As with "
349 ":imagetype, you may also specify two type names separated "
350 "by a comma, to indicate that a different file should be written "
351 "for the color and alpha components.\n\n");
352
353 show_text(" (group name)", 10,
354 "A texture may also be assigned to a specific group by naming "
355 "the group. The groups are defined using the :group command "
356 "(see below). Normally, textures are not assigned directly "
357 "to groups; instead, it is more useful to assign the egg files "
358 "they are referenced in to groups; see below.\n\n");
359
360 show_text(" cont", 10,
361 "Normally, a texture file (or egg file) scans the lines in the "
362 "attributes file from the top, and stops on the first line that "
363 "matches its name. If the keyword 'cont' is included on the "
364 "line, however, the texture will apply the properties given "
365 "on the line, and then continue scanning. This trick may be "
366 "used to specify general parameters for all files while still "
367 "allowing the texture to match a more specific line below.\n\n");
368
369 nout <<
370 "The attributes file may also assign egg files to various "
371 "named palette groups. The syntax is similar to the above:\n\n"
372
373 " car-blue.egg : main\n"
374 " road.egg house.egg : main\n"
375 " plane.egg : phase_2 main\n"
376 " *.egg : phase_2\n\n"
377
378 "Any number of egg files may be named on one line, and the set of "
379 "named egg files may be simultaneously assigned to one or more groups. "
380 "Each group must have been previously defined using the :group command "
381 "(see below). Each texture that is referenced by a given "
382 "egg file will be palettized "
383 "into at least one of the groups assigned to the egg file.\n\n"
384
385 "Finally, there are a number of special commands that may appear in the "
386 "attributes file; some of these have been alluded to in the above "
387 "comments. These commands typically specify global parameters or "
388 "palettization options. The command names begin with a colon to "
389 "distinguish them from other kinds of lines. Each command must "
390 "appear on a line by itself. The commands are:\n\n";
391
392 show_text(" :palette xsize ysize", 10,
393 "This specifies the size of the palette images to be "
394 "created. The default is 512 by 512.\n\n");
395
396 show_text(" :margin msize", 10,
397 "This specifies the amount of default margin to apply to all "
398 "textures that are placed within a palette image. The margin "
399 "is a number of additional pixels that are written around the "
400 "texture image to help prevent color bleeding between "
401 "neighboring images within the same palette. The default "
402 "is 2.\n\n");
403
404 show_text(" :background r g b a", 10,
405 "Specifies the background color of the generated palette "
406 "images. Normally, this is black, and it doesn't matter much "
407 "since the background color is, by definition, the color "
408 "of the palette images where nothing is used.\n\n");
409
410 show_text(" :coverage area", 10,
411 "The 'coverage' of a texture refers to the fraction of "
412 "the area in the texture image that is actually used, according "
413 "to the UV's that appear in the various egg files. If a texture's "
414 "coverage is less than 1, only some of the texture image is used "
415 "(and only this part will be written to the palette). If the "
416 "coverage is greater than 1, the texture repeats that number of "
417 "times. A repeating texture may still be palettized by writing "
418 "the required number of copies into the palette image, according "
419 "to the coverage area.\n\n"
420
421 "This command specifies the maximum coverage to allow for any "
422 "texture before rejecting it from the palette. It may be any "
423 "floating-point number greater than zero. Set this to 1 "
424 "to avoid palettizing repeating textures altogether. This may "
425 "also be overridden for a particular texture using the 'coverage' "
426 "keyword on the texture line.\n\n");
427
428 show_text(" :powertwo flag", 10,
429 "Specifies whether textures should be forced to a power of two "
430 "size when they are not placed within a palette. Use 1 for true, "
431 "to force textures to a power of two; or 0 to leave them exactly "
432 "the size they are specified. The default is true.\n\n");
433
434 show_text(" :round fraction fuzz", 10,
435 "When the coverage area is computed, it may optionally be "
436 "rounded up to the next sizeable unit before placing the "
437 "texture within the palette. This helps reduce constant "
438 "repalettization caused by slight differences in coverage "
439 "between egg files. For instance, say file a.egg references a "
440 "texture with a coverage of 0.91, and then later file b.egg "
441 "is discovered to reference the same texture with a coverage of "
442 "0.92. If the texture was already palettized with the original "
443 "coverage of 0.91, it must now be moved in the palette.\n\n"
444
445 "Rounding the coverage area up to some fixed unit reduces this "
446 "problem. For instance, if you specified a value 0.5 for "
447 "fraction in the above command, it would round both of these "
448 "values up to the next half-unit, or 1.0.\n\n"
449
450 "The second number is a fuzz factor, and should be a small "
451 "number; if the coverage area is just slightly larger than "
452 "the last unit (within the fuzz factor), it is rounded down "
453 "instead of up. This is intended to prevent UV coordinates "
454 "that are just slightly out of the range [0, 1] (which happens "
455 "fairly often) from forcing the palettization area all the "
456 "way up to the next stop.\n\n"
457
458 "The default if this is unspecified is 0.1 0.01. That is, "
459 "round up to the next tenth, unless within a hundredth of the "
460 "last tenth. To disable rounding, specify ':round no'. "
461 "Rounding is implicitly disabled when you run with the -opt "
462 "command line option.\n\n");
463
464 show_text(" :remap (never | group | poly)", 10,
465 "Sometimes two different parts of an egg file may reference "
466 "different regions of a repeating texture. For instance, "
467 "group A may reference UV coordinate values ranging from (0,5) "
468 "to (1,6), for a coverage of 1.0, while group B references "
469 "values ranging from (0,2) to (1,4), for a coverage of 2.0. "
470 "The maximum coverage used is only 2.0, and thus the texture "
471 "only needs to appear in the palette twice, but the total range "
472 "of UV's is from (0,2) to (1,6), causing an apparent coverage "
473 "of 4.0.\n\n"
474
475 "It's possible for egg-palettize to reduce this kind of mistake "
476 "by remapping both groups of UV's so that they overlap. This "
477 "parameter specifies how this operation should be done. If "
478 "the option is 'never', remapping will not be performed; if "
479 "'group', entire groups will be remapped as a unit, if 'poly', "
480 "individual polygons within a group may be remapped. This last "
481 "option provides the greatest minimization of UV coverage, "
482 "but possibly at the expense of triangle strips in the resulting "
483 "model (since some vertices can no longer be shared).\n\n"
484
485 "Sometimes, it may be necessary to be more restrictive on "
486 "character geometry than on non-character geometry, because "
487 "the cost of adding additional vertices on characters is "
488 "greater. You can specify a different kind of remapping for "
489 "characters only, by using the keyword 'char' on the same line, "
490 "e.g. ':remap group char never'.\n\n"
491
492 "The default remap mode for all geometry, character or otherwise, "
493 "if no remap mode is specified is 'poly'.\n\n");
494
495 show_text(" :imagetype type[,alpha_type]", 10,
496 "This specifies the default type of image file that should be "
497 "generated for each palette image and for each unplaced texture "
498 "copied into the install directory. This may be overridden for "
499 "a particular texture by specifying the image type on the "
500 "texture line.\n\n"
501
502 "If two image type names separate by a comma are given, it means "
503 "to generate a second file of the second type for the alpha "
504 "channel, for images that require an alpha channel. This allows "
505 "support for image file formats that do not support alpha "
506 "(for instance, JPEG).\n\n");
507
508 show_text(" :shadowtype type[,alpha_type]", 10,
509 "When generating palette images, egg-palettize sometimes has to "
510 "read and write the same palette image repeatedly. If the "
511 "palette image is stored in a lossy file format (like JPEG, see "
512 ":imagetype), this can eventually lead to degradation of the "
513 "palette images. As a workaround, egg-palettize can store "
514 "its working copies of the palette images in lossless shadow "
515 "images. Specify this to enable this feature; give it the "
516 "name of a lossless image file format. The shadow images will "
517 "be written to the directory specified by -ds on the command "
518 "line.\n\n");
519
520 show_text(" :group groupname [dir dirname] [on group1 group2 ...] [includes group1 group2 ...]", 10,
521 "This defines a palette group, a logical division of textures. "
522 "Each texture is assigned to one or more palette groups before "
523 "being placed in any palette image; the palette images are "
524 "tied to the groups.\n\n"
525
526 "The optional parameter 'dir' specifies a directory name to "
527 "associate with this group. This name is substituted in for "
528 "the string '%g' when it appears in the map directory name "
529 "specified on the command line with -dm; this may be used to "
530 "install textures and palettes into different directories based "
531 "on the groups they are assigned to.\n\n"
532
533 "Palette groups can also be hierarchically related. The "
534 "keyword 'on' specifies any number of groups that this "
535 "palette group depends on; if a texture has already been "
536 "assigned to one of this group's dependent groups, it will "
537 "not need to be assigned to this group. This also implicitly "
538 "specifies a dir if one has not already been specified.\n\n"
539
540 "The keyword 'includes' names one or more groups that depend "
541 "on this group.\n\n");
542
543 show_text(" :textureswap groupname texturename0 texturename1 [texturename2 ...]", 10,
544 "This option builds a set of matching, interchangeable palette images. "
545 "All palette images in the set share the same internal texture layout. "
546 "The intention is to be able to swap palette images out at runtime, "
547 "to replace entire sets of textures on a model in one operation. "
548 "The textures named by this option indicate the texture images "
549 "which are similar to each other, and which all should be assigned "
550 "to the same placement on the different palette images: "
551 "texturename0 will be assigned to palette image 0, "
552 "texturename1 to the same position on palette image 1, "
553 "texturename2 to the same position on palette image 2, and so on. "
554 "To define a complete palette image, you must repeat this option "
555 "several times to associate all of the similar texture images.\n\n");
556
557 nout <<
558 "Comments may appear freely throughout the file, and are set off by a "
559 "hash mark (#).\n\n";
560}
561
562
563/**
564 *
565 */
566void EggPalettize::
567run() {
568 // Fiddle with the loader severity, so we don't confuse the user with
569 // spurious "reading" and "writing" messages about the state file. If the
570 // severity is currently NS_info (the default), set it to NS_warning
571 // instead.
572 Notify *notify = Notify::ptr();
573 NotifyCategory *loader_cat = notify->get_category(":loader");
574 if (loader_cat != nullptr &&
575 loader_cat->get_severity() == NS_info) {
576 loader_cat->set_severity(NS_warning);
577 }
578
579 Filename state_filename;
580 BamFile state_file;
581
582 if (_got_txa_script) {
583 // If we got a command-line script instead of a .txa file, we won't be
584 // encoding a .boo file either.
585 _nodb = true;
586
587 } else {
588 // Look for the .txa file.
589 if (!_txa_filename.exists() && !_got_txa_filename) {
590 // If we did not specify a filename, and the default filename of
591 // "textures.txa" doesn't exist, try looking in srcmaps, as another
592 // likely possibility.
593 Filename maybe = _txa_filename;
594 maybe.set_dirname("src/maps");
595 if (maybe.exists()) {
596 _txa_filename = maybe;
597 }
598 }
599
600 if (!_txa_filename.exists()) {
601 nout << FilenameUnifier::make_user_filename(_txa_filename)
602 << " does not exist; cannot run.\n";
603 exit(1);
604 }
605
607
608 state_filename = _txa_filename;
609 state_filename.set_extension("boo");
610 }
611
612 if (_nodb) {
613 // -nodb means don't attempt to read textures.boo; in fact, don't even
614 // bother reporting this absence to the user.
615 pal = new Palettizer;
616
617 // And -nodb implies -opt.
618 _optimal = true;
619
620 } else if (!state_filename.exists()) {
621 nout << FilenameUnifier::make_user_filename(state_filename)
622 << " does not exist; starting palettization from scratch.\n";
623 pal = new Palettizer;
624
625 // By default, the -omitall flag is true from the beginning.
626 pal->_omit_everything = true;
627
628 } else {
629 // Read the Palettizer object from the Bam file written previously. This
630 // will recover all of the state saved from the past session.
631 nout << "Reading " << FilenameUnifier::make_user_filename(state_filename)
632 << "\n";
633
634 if (!state_file.open_read(state_filename)) {
635 nout << FilenameUnifier::make_user_filename(state_filename)
636 << " exists, but cannot be read. Perhaps you should "
637 << "remove it so a new one can be created.\n";
638 exit(1);
639 }
640
641 TypedWritable *obj = state_file.read_object();
642 if (obj == nullptr || !state_file.resolve()) {
643 nout << FilenameUnifier::make_user_filename(state_filename)
644 << " exists, but appears to be corrupt. Perhaps you "
645 << "should remove it so a new one can be created.\n";
646 exit(1);
647 }
648
649 if (!obj->is_of_type(Palettizer::get_class_type())) {
650 nout << FilenameUnifier::make_user_filename(state_filename)
651 << " exists, but does not appear to be "
652 << "an egg-palettize output file. Perhaps you "
653 << "should remove it so a new one can be created.\n";
654 exit(1);
655 }
656
657 state_file.close();
658
659 pal = DCAST(Palettizer, obj);
660
661 if (pal->_read_pi_version > pal->_pi_version) {
662 nout << FilenameUnifier::make_user_filename(state_filename)
663 << " was written by a more recent version of egg-palettize "
664 << "than this one. You will need to update your egg-palettize.\n";
665 exit(1);
666 }
667
668 if (pal->_read_pi_version < pal->_min_pi_version) {
669 nout << FilenameUnifier::make_user_filename(state_filename)
670 << " was written by an old version of egg-palettize.\n\n"
671 << "You will need to make undo-pal (or simply remove the file "
672 << FilenameUnifier::make_user_filename(state_filename)
673 << " and try again).\n\n";
674 exit(1);
675 }
676
677 if (!pal->is_valid()) {
678 nout << FilenameUnifier::make_user_filename(state_filename)
679 << " could not be properly read. You will need to remove it.\n";
680 exit(1);
681 }
682 }
683
684 pal->set_noabs(_noabs);
685
686 if (_report_pi) {
687 pal->report_pi();
688 exit(0);
689 }
690
691 if (_report_statistics) {
692 pal->report_statistics();
693 exit(0);
694 }
695
696 bool okflag = true;
697
698 if (_got_txa_script) {
699 std::istringstream txa_script(_txa_script);
700 pal->read_txa_file(txa_script, "command line");
701
702 } else {
703 _txa_filename.set_text();
704 std::ifstream txa_file;
705 if (!_txa_filename.open_read(txa_file)) {
706 nout << "Unable to open " << _txa_filename << "\n";
707 exit(1);
708 }
709 pal->read_txa_file(txa_file, _txa_filename);
710 }
711
712 if (_got_generated_image_pattern) {
713 pal->_generated_image_pattern = _generated_image_pattern;
714 }
715
716 if (_got_default_groupname) {
717 pal->_default_groupname = _default_groupname;
718 } else {
719 pal->_default_groupname = _txa_filename.get_basename_wo_extension();
720 }
721
722 if (_got_default_groupdir) {
723 pal->_default_groupdir = _default_groupdir;
724 }
725
726 if (_got_map_dirname) {
727 pal->_map_dirname = _map_dirname;
728 }
729 if (_got_shadow_dirname) {
730 pal->_shadow_dirname = _shadow_dirname;
731 }
732 if (_got_rel_dirname) {
733 pal->_rel_dirname = _rel_dirname;
735 }
736
737 // We only omit solitary textures from palettes if we're running in optimal
738 // mode. Otherwise, we're likely to invalidate old egg files by changing a
739 // texture from solitary to nonsolitary state or vice-versa.
740 pal->_omit_solitary = _optimal;
741
742 if (_omitall) {
743 pal->_omit_everything = true;
744 } else if (_optimal) {
745 pal->_omit_everything = false;
746 }
747
748 pal->all_params_set();
749
750 // Remove any files named for removal.
751 Args::const_iterator ai;
752 for (ai = _remove_egg_list.begin(); ai != _remove_egg_list.end(); ++ai) {
753 Filename filename = (*ai);
754 pal->remove_egg_file(filename.get_basename());
755 }
756
757 // And process the egg files named for addition.
758 bool all_eggs_valid = true;
759
760 std::string egg_comment = get_exec_command();
761 Eggs::const_iterator ei;
762 for (ei = _eggs.begin(); ei != _eggs.end(); ++ei) {
763 EggData *egg_data = (*ei);
764 Filename source_filename = egg_data->get_egg_filename();
765 Filename dest_filename = get_output_filename(source_filename);
766 std::string name = source_filename.get_basename();
767
768 EggFile *egg_file = pal->get_egg_file(name);
769 if (!egg_file->from_command_line(egg_data, source_filename, dest_filename,
770 egg_comment)) {
771 all_eggs_valid = false;
772
773 } else {
774 pal->add_command_line_egg(egg_file);
775 }
776 }
777
778 if (!all_eggs_valid) {
779 nout << "Errors reading egg file(s).\n";
780 exit(1);
781 }
782
783 if (_optimal) {
784 // If we're asking for an optimal packing, throw away the old packing and
785 // start fresh.
786 pal->reset_images();
787 _all_textures = true;
788
789 /* Asad: I disagree: unless :round is set to no from textures.txa, we
790 should always leave the _round_uvs to default.
791 // Also turn off the rounding-up of UV's for this purpose.
792 pal->_round_uvs = false;
793 */
794 }
795
796 if (_all_textures) {
797 pal->process_all(_redo_all, state_filename);
798 } else {
799 pal->process_command_line_eggs(_redo_all, state_filename);
800 }
801
802 if (_optimal) {
803 // If we're asking for optimal packing, this also implies we want to
804 // resize the big empty palette images down.
805 pal->optimal_resize();
806 }
807
808 if (_redo_eggs) {
809 if (!pal->read_stale_eggs(_redo_all)) {
810 okflag = false;
811 }
812 }
813
814 if (okflag) {
815 pal->generate_images(_redo_all);
816
817 if (_redo_eggs) {
818 // generate_images() might have made a few more stale egg files
819 // (particularly if a texture palette changed filenames).
820 if (!pal->read_stale_eggs(false)) {
821 okflag = false;
822 }
823 }
824 }
825
826 if (okflag) {
827 if (!pal->write_eggs()) {
828 okflag = false;
829 }
830 }
831
832 if (!_nodb) {
833 // Make up a temporary filename to write the state file to, then move the
834 // state file into place. We do this in case the user interrupts us (or
835 // we core dump) before we're done; that way we won't leave the state file
836 // incompletely written.
837 std::string dirname = state_filename.get_dirname();
838 if (dirname.empty()) {
839 dirname = ".";
840 }
841 Filename temp_filename = Filename::temporary(dirname, "pi");
842
843 if (!state_file.open_write(temp_filename) ||
844 !state_file.write_object(pal)) {
845 nout << "Unable to write palettization information to "
847 << "\n";
848 exit(1);
849 }
850
851 state_file.close();
852 state_filename.unlink();
853 if (!temp_filename.rename_to(state_filename)) {
854 nout << "Unable to rename temporary file "
855 << FilenameUnifier::make_user_filename(temp_filename) << " to "
856 << FilenameUnifier::make_user_filename(state_filename) << "\n";
857 exit(1);
858 }
859 }
860
861 if (!okflag) {
862 exit(1);
863 }
864}
865
866int
867main(int argc, char *argv[]) {
868 EggPalettize prog;
869 prog.parse_command_line(argc, argv);
870 prog.run();
871 return 0;
872}
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The principle public interface to reading and writing Bam disk files.
Definition bamFile.h:41
void close()
Closes the input or output stream.
Definition bamFile.cxx:243
bool open_write(const Filename &bam_filename, bool report_errors=true)
Attempts to open the indicated file for writing.
Definition bamFile.cxx:190
TypedWritable * read_object()
Reads and returns the next object from the Bam file, or NULL if the end of the file has been reached,...
Definition bamFile.cxx:85
bool open_read(const Filename &bam_filename, bool report_errors=true)
Attempts to open the indicated filename for reading.
Definition bamFile.cxx:51
bool resolve()
This must be called after one or more objects have been read via calls to read_object() in order to r...
Definition bamFile.cxx:110
bool write_object(const TypedWritable *object)
Writes the indicated object to the Bam file.
Definition bamFile.cxx:226
This is the primary interface into all the egg data, and the root of the egg file structure.
Definition eggData.h:37
get_egg_filename
Returns the directory in which the egg file is considered to reside.
Definition eggData.h:74
This represents a single egg file known to the palettizer.
Definition eggFile.h:36
bool from_command_line(EggData *data, const Filename &source_filename, const Filename &dest_filename, const std::string &egg_comment)
Accepts the information about the egg file as supplied from the command line.
Definition eggFile.cxx:57
This is a base class for a program that reads in a number of egg files, operates on them,...
This is the program wrapper for egg-palettize, but it mainly serves to read in all the command-line p...
virtual bool handle_args(Args &args)
Does something with the additional arguments on the command line (after all the -options have been pa...
static void set_txa_filename(const Filename &txa_filename)
Notes the filename the .txa file was found in.
static void set_rel_dirname(const Filename &rel_dirname)
Sets the name of the directory that texture filenames will be written relative to,...
static Filename make_user_filename(Filename filename)
Returns a new filename that's made relative to the current directory, suitable for reporting to the u...
The name of a file, such as a texture file or an Egg file.
Definition filename.h:44
std::string get_basename() const
Returns the basename part of the filename.
Definition filename.I:367
bool open_read(std::ifstream &stream) const
Opens the indicated ifstream for reading the file, if possible.
bool rename_to(const Filename &other) const
Renames the file to the indicated new filename.
bool unlink() const
Permanently deletes the file associated with the filename, if possible.
void set_dirname(const std::string &s)
Replaces the directory part of the filename.
Definition filename.cxx:704
void set_text()
Indicates that the filename represents a text file.
Definition filename.I:424
static Filename temporary(const std::string &dirname, const std::string &prefix, const std::string &suffix=std::string(), Type type=T_general)
Generates a temporary filename within the indicated directory, using the indicated prefix.
Definition filename.cxx:424
void set_extension(const std::string &s)
Replaces the file extension.
Definition filename.cxx:804
std::string get_basename_wo_extension() const
Returns the basename part of the filename, without the file extension.
Definition filename.I:386
std::string get_dirname() const
Returns the directory part of the filename.
Definition filename.I:358
bool exists() const
Returns true if the filename exists on the physical disk, false otherwise.
A particular category of error messages.
set_severity
Sets the severity level of messages that will be reported from this Category.
An object that handles general error reporting to the user.
Definition pnotify.h:33
NotifyCategory * get_category(const std::string &basename, NotifyCategory *parent_category)
Finds or creates a new Category given the basename of the category and its parent in the category hie...
Definition notify.cxx:183
static Notify * ptr()
Returns the pointer to the global Notify object.
Definition notify.cxx:293
This is the main engine behind egg-palettize.
Definition palettizer.h:39
void set_noabs(bool noabs)
Changes the current setting of the noabs flag.
void process_all(bool force_texture_read, const Filename &state_filename)
Reprocesses all textures known.
bool remove_egg_file(const std::string &name)
Removes the named egg file from the database, if it exists.
void process_command_line_eggs(bool force_texture_read, const Filename &state_filename)
Processes all the textures named in the _command_line_eggs, placing them on the appropriate palettes ...
void optimal_resize()
Attempts to resize each PalettteImage down to its smallest possible size.
void all_params_set()
Called after all command line parameters have been set up, this is a hook to do whatever initializati...
EggFile * get_egg_file(const std::string &name)
Returns the EggFile with the given name.
void add_command_line_egg(EggFile *egg_file)
Adds the indicated EggFile to the list of eggs that are considered to have been read on the command l...
bool write_eggs()
Adjusts the egg files to reference the newly generated textures, and writes them out.
bool is_valid() const
Returns true if the palette information file was read correctly, or false if there was some error and...
void report_pi() const
Output a verbose description of all the palettization information to standard output,...
void reset_images()
Throws away all of the current PaletteImages, so that new ones may be created (and the packing made m...
void read_txa_file(std::istream &txa_file, const std::string &txa_filename)
Reads in the .txa file and keeps it ready for matching textures and egg files.
void report_statistics() const
Output a report of the palettization effectiveness, texture memory utilization, and so on.
bool read_stale_eggs(bool redo_all)
Reads in any egg file that is known to be stale, even if it was not listed on the command line,...
void generate_images(bool redo_all)
Actually generates the appropriate palette and unplaced texture images into the map directories.
std::string get_exec_command() const
Returns the command that invoked this program, as a shell-friendly string, suitable for pasting into ...
void show_text(const std::string &text)
Formats the indicated text to stderr with the known _terminal_width.
Definition programBase.I:18
virtual void parse_command_line(int argc, char **argv)
Dispatches on each of the options on the command line, and passes the remaining parameters to handle_...
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition typedObject.I:28
Base class for objects that can be written to and read from Bam files.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.