Panda3D
eggTextureCards.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 eggTextureCards.cxx
10  * @author drose
11  * @date 2001-02-21
12  */
13 
14 #include "eggTextureCards.h"
15 
16 #include "eggGroup.h"
17 #include "eggVertexPool.h"
18 #include "eggVertex.h"
19 #include "eggTexture.h"
20 #include "eggPolygon.h"
21 #include "pnmImageHeader.h"
22 
23 #include <algorithm>
24 
25 using std::string;
26 
27 /**
28  *
29  */
30 EggTextureCards::
31 EggTextureCards() : EggWriter(true, true) {
32  set_program_brief("generate an .egg file containing texture cards");
33  set_program_description
34  ("egg-texture-cards generates an egg file consisting of several "
35  "square polygons, one for each texture name that appears on the "
36  "command line.\n\n"
37 
38  "This is a handy thing to have for importing texture images through "
39  "egg-palettize, even when those textures do not appear on any real "
40  "geometry; it can also be used for creating a lot of simple polygons "
41  "for rendering click buttons and similar interfaces.");
42 
43  clear_runlines();
44  add_runline("[opts] texture [texture ...] output.egg");
45  add_runline("[opts] -o output.egg texture [texture ...]");
46  add_runline("[opts] texture [texture ...] >output.egg");
47 
48  add_option
49  ("g", "left,right,bottom,top", 0,
50  "Specifies the geometry of each polygon. The default is a unit polygon "
51  "centered on the origin: -0.5,0.5,-0.5,0.5. Polygons are always created "
52  "on the X-Y plane. If -p is not also specified, all polygons will be "
53  "the same size and shape.",
54  &EggTextureCards::dispatch_double_quad, nullptr, &_polygon_geometry[0]);
55 
56  add_option
57  ("p", "xpixels,ypixels", 0,
58  "Indicates that polygons should be sized in proportion to the pixel "
59  "size of the texture image. This will potentially create a "
60  "different size and shape polygon for each texture. The coordinate "
61  "pair represents the image size in "
62  "pixels that will exactly fill up the polygon described with -g (or the "
63  "default polygon if -g is not specified); smaller images will be "
64  "given proportionately smaller polygons, and larger images will be "
65  "given proportionately larger polygons.",
66  &EggTextureCards::dispatch_double_pair, &_got_pixel_scale, &_pixel_scale[0]);
67 
68  add_option
69  ("suffix", "string", 0,
70  "Normally, each polygon is given a name based on the basename of its "
71  "corresponding texture's filename (without the filename extension). "
72  "This option specifies an ignorable suffix in the texture filename(s); "
73  "if this suffix is present, it is not included in the polygon's name. "
74  "This option may be repeated multiple times.",
75  &EggTextureCards::dispatch_vector_string, nullptr, &_suffixes);
76 
77  add_option
78  ("c", "r,g,b[,a]", 0,
79  "Specifies the color of each polygon. The default is white: 1,1,1,1.",
80  &EggTextureCards::dispatch_color, nullptr, &_polygon_color[0]);
81 
82  add_option
83  ("wm", "wrap", 0,
84  "Indicates the wrap mode of the texture: \"repeat\", \"clamp\", "
85  "or any of the other modes supported by egg syntax. "
86  "The default is to leave this unspecified.",
87  &EggTextureCards::dispatch_wrap_mode, nullptr, &_wrap_mode);
88 
89  add_option
90  ("wmu", "wrap_u", 0,
91  "Indicates the wrap mode of the texture in the U direction. This "
92  "overrides -wm, if specified.",
93  &EggTextureCards::dispatch_wrap_mode, nullptr, &_wrap_u);
94 
95  add_option
96  ("wmv", "wrap_v", 0,
97  "Indicates the wrap mode of the texture in the V direction. This "
98  "overrides -wm, if specified.",
99  &EggTextureCards::dispatch_wrap_mode, nullptr, &_wrap_v);
100 
101  add_option
102  ("minf", "filter", 0,
103  "Indicates the minfilter mode of the texture: \"linear\", \"mipmap\", "
104  "or any of the other modes supported by egg syntax. "
105  "The default is to leave this unspecified.",
106  &EggTextureCards::dispatch_filter_type, nullptr, &_minfilter);
107 
108  add_option
109  ("magf", "filter", 0,
110  "Indicates the magfilter mode of the texture: \"linear\" or \"nearest\". "
111  "The default is to leave this unspecified.",
112  &EggTextureCards::dispatch_filter_type, nullptr, &_magfilter);
113 
114  add_option
115  ("aniso", "degree", 0,
116  "Indicates the anisotropic degree of the texture. "
117  "The default is to leave this unspecified.",
118  &EggTextureCards::dispatch_int, &_got_aniso_degree, &_aniso_degree);
119 
120  add_option
121  ("ql", "[default | fastest | normal | best]", 0,
122  "Specifies the quality level of the texture. This mainly affects "
123  "the tinydisplay software renderer.",
124  &EggTextureCards::dispatch_quality_level, nullptr, &_quality_level);
125 
126  add_option
127  ("f", "format", 0,
128  "Indicates the format for all textures: typical choices are \"rgba12\" "
129  "or \"rgb5\" or \"alpha\". The default is to leave this unspecified.",
130  &EggTextureCards::dispatch_format, nullptr, &_format);
131 
132  add_option
133  ("f1", "format", 0,
134  "Indicates the format for one-channel textures only. If specified, this "
135  "overrides the format specified by -f.",
136  &EggTextureCards::dispatch_format, nullptr, &_format_1);
137 
138  add_option
139  ("f2", "format", 0,
140  "Indicates the format for two-channel textures only. If specified, this "
141  "overrides the format specified by -f.",
142  &EggTextureCards::dispatch_format, nullptr, &_format_2);
143 
144  add_option
145  ("f3", "format", 0,
146  "Indicates the format for three-channel textures only. If specified, this "
147  "overrides the format specified by -f.",
148  &EggTextureCards::dispatch_format, nullptr, &_format_3);
149 
150  add_option
151  ("f4", "format", 0,
152  "Indicates the format for four-channel textures only. If specified, this "
153  "overrides the format specified by -f.",
154  &EggTextureCards::dispatch_format, nullptr, &_format_4);
155 
156  add_option
157  ("b", "", 0,
158  "Make the textured polygons backfaced (two-sided).",
159  &EggTextureCards::dispatch_none, &_apply_bface);
160 
161  add_option
162  ("fps", "frame-rate", 0,
163  "Normally, all of the texture cards are created as a series of nodes "
164  "beneath a SequenceNode. This allows all of the cards to be viewed, "
165  "one at a time, if the output file is loaded in pview. It also has the "
166  "nice side-effect of creating an automatic texture flip that can be "
167  "used directly by applications; use this parameter to specify the "
168  "frame rate of that texture flip.",
169  &EggTextureCards::dispatch_double, nullptr, &_frame_rate);
170 
171  add_option
172  ("noexist", "", 0,
173  "Don't treat it as an error if the input file references pathnames "
174  "(e.g. textures) that don't exist. Normally, this will be flagged as "
175  "an error and the command aborted; with this option, an egg file will "
176  "be generated anyway, referencing pathnames that do not exist.",
177  &EggTextureCards::dispatch_none, &_noexist);
178 
179  _polygon_geometry.set(-0.5, 0.5, -0.5, 0.5);
180  _polygon_color.set(1.0, 1.0, 1.0, 1.0);
181  _wrap_mode = EggTexture::WM_unspecified;
182  _wrap_u = EggTexture::WM_unspecified;
183  _wrap_v = EggTexture::WM_unspecified;
184  _minfilter = EggTexture::FT_unspecified;
185  _magfilter = EggTexture::FT_unspecified;
186  _aniso_degree = 0;
187  _quality_level = EggTexture::QL_unspecified;
188  _format = EggTexture::F_unspecified;
189  _format_1 = EggTexture::F_unspecified;
190  _format_2 = EggTexture::F_unspecified;
191  _format_3 = EggTexture::F_unspecified;
192  _format_4 = EggTexture::F_unspecified;
193  _frame_rate = 2.0;
194 }
195 
196 /**
197  * Does something with the additional arguments on the command line (after all
198  * the -options have been parsed). Returns true if the arguments are good,
199  * false otherwise.
200  */
201 bool EggTextureCards::
202 handle_args(ProgramBase::Args &args) {
203  if (!check_last_arg(args, 0)) {
204  return false;
205  }
206 
207  if (args.empty()) {
208  nout << "No texture names specified on the command line.\n";
209  return false;
210  }
211 
212  ProgramBase::Args::iterator ai;
213  for (ai = args.begin(); ai != args.end(); ++ai) {
214  _texture_names.push_back(Filename::from_os_specific(*ai));
215  }
216 
217  return true;
218 }
219 
220 /**
221  * Standard dispatch function for an option that takes one parameter, which is
222  * to be interpreted as a WrapMode string. The data pointer is to a WrapMode
223  * enum variable.
224  */
225 bool EggTextureCards::
226 dispatch_wrap_mode(const string &opt, const string &arg, void *var) {
227  EggTexture::WrapMode *wmp = (EggTexture::WrapMode *)var;
228 
229  *wmp = EggTexture::string_wrap_mode(arg);
230  if (*wmp == EggTexture::WM_unspecified) {
231  // An unknown string. Let's check for our special cases.
232  if (arg == "r") {
233  *wmp = EggTexture::WM_repeat;
234  } else if (arg == "c") {
235  *wmp = EggTexture::WM_clamp;
236  } else {
237  nout << "Invalid wrap mode parameter for -" << opt << ": "
238  << arg << "\n";
239  return false;
240  }
241  }
242 
243  return true;
244 }
245 
246 /**
247  * Standard dispatch function for an option that takes one parameter, which is
248  * to be interpreted as a FilterType string. The data pointer is to a
249  * FilterType enum variable.
250  */
251 bool EggTextureCards::
252 dispatch_filter_type(const string &opt, const string &arg, void *var) {
253  EggTexture::FilterType *ftp = (EggTexture::FilterType *)var;
254 
255  *ftp = EggTexture::string_filter_type(arg);
256  if (*ftp == EggTexture::FT_unspecified) {
257  // An unknown string.
258  nout << "Invalid filter type parameter for -" << opt << ": "
259  << arg << "\n";
260  return false;
261  }
262 
263  return true;
264 }
265 
266 /**
267  * Standard dispatch function for an option that takes one parameter, which is
268  * to be interpreted as a QualityLevel string. The data pointer is to a
269  * QualityLevel enum variable.
270  */
271 bool EggTextureCards::
272 dispatch_quality_level(const string &opt, const string &arg, void *var) {
273  EggTexture::QualityLevel *qlp = (EggTexture::QualityLevel *)var;
274 
276  if (*qlp == EggTexture::QL_unspecified) {
277  nout << "Invalid quality level parameter for -" << opt << ": "
278  << arg << "\n";
279  return false;
280  }
281 
282  return true;
283 }
284 
285 /**
286  * Standard dispatch function for an option that takes one parameter, which is
287  * to be interpreted as a Format string. The data pointer is to a Format enum
288  * variable.
289  */
290 bool EggTextureCards::
291 dispatch_format(const string &opt, const string &arg, void *var) {
292  EggTexture::Format *fp = (EggTexture::Format *)var;
293 
294  *fp = EggTexture::string_format(arg);
295  if (*fp == EggTexture::F_unspecified) {
296  nout << "Invalid format parameter for -" << opt << ": "
297  << arg << "\n";
298  return false;
299  }
300 
301  return true;
302 }
303 
304 
305 /**
306  * Reads the texture image header to determine its size, and based on this
307  * size, computes the appropriate left,right,bottom,top geometry of the card
308  * that correspond to this texture.
309  *
310  * Returns true if successful, or false if the texture cannot be read.
311  */
312 bool EggTextureCards::
313 scan_texture(const Filename &filename, LVecBase4d &geometry,
314  int &num_channels) {
315  PNMImageHeader header;
316  if (!header.read_header(filename)) {
317  nout << "Unable to read image " << filename << "\n";
318  return false;
319  }
320 
321  num_channels = header.get_num_channels();
322 
323  double xscale = header.get_x_size() / _pixel_scale[0];
324  double yscale = header.get_y_size() / _pixel_scale[1];
325 
326  geometry.set(_polygon_geometry[0] * xscale,
327  _polygon_geometry[1] * xscale,
328  _polygon_geometry[2] * yscale,
329  _polygon_geometry[3] * yscale);
330  return true;
331 }
332 
333 /**
334  * Creates a set of four vertices for the polygon according to the
335  * left,right,bottom,top geometry.
336  */
337 void EggTextureCards::
338 make_vertices(const LPoint4d &geometry, EggVertexPool *vpool,
339  EggVertex *&v1, EggVertex *&v2, EggVertex *&v3, EggVertex *&v4) {
340  // 1 4 2 3
341 
342  v1 = vpool->make_new_vertex
343  (LPoint3d(geometry[0], geometry[3], 0.0));
344  v2 = vpool->make_new_vertex
345  (LPoint3d(geometry[0], geometry[2], 0.0));
346  v3 = vpool->make_new_vertex
347  (LPoint3d(geometry[1], geometry[2], 0.0));
348  v4 = vpool->make_new_vertex
349  (LPoint3d(geometry[1], geometry[3], 0.0));
350 
351  v1->set_uv(LTexCoordd(0.0, 1.0));
352  v2->set_uv(LTexCoordd(0.0, 0.0));
353  v3->set_uv(LTexCoordd(1.0, 0.0));
354  v4->set_uv(LTexCoordd(1.0, 1.0));
355 }
356 
357 /**
358  *
359  */
360 void EggTextureCards::
361 run() {
362  // First, create an enclosing group and a vertex pool with four vertices.
363  // We can use the same four vertices on all polygons.
364  bool all_ok = true;
365 
366  EggGroup *group = new EggGroup();
367  _data->add_child(group);
368 
369  // If we have more than one tile, make the group a sequence, as a
370  // convenience. If we view the egg file directly we can see all the tiles
371  // one at a time.
372  if (_texture_names.size() > 1) {
373  group->set_switch_flag(true);
374  group->set_switch_fps(_frame_rate);
375  }
376 
377  EggVertexPool *vpool = new EggVertexPool("vpool");
378  group->add_child(vpool);
379 
380  EggVertex *v1, *v2, *v3, *v4;
381 
382  if (!_got_pixel_scale) {
383  // If we don't have a per-texture pixel scale, all the polygons will be
384  // the same size, and hence may all share the same four vertices.
385  make_vertices(_polygon_geometry, vpool, v1, v2, v3, v4);
386  }
387 
388  // Now, create a texture reference and a polygon for each texture.
389 
390  vector_string::const_iterator ti;
391  for (ti = _texture_names.begin(); ti != _texture_names.end(); ++ti) {
392  Filename filename = (*ti);
393  string name = filename.get_basename_wo_extension();
394 
395  // Strip off any suffixes from the name.
396  vector_string::const_iterator si;
397  for (si = _suffixes.begin(); si != _suffixes.end(); ++si) {
398  const string &suffix = (*si);
399  int prefix = (int)name.length() - (int)suffix.length();
400  if (prefix > 0 && name.substr(prefix) == suffix) {
401  name = name.substr(0, prefix);
402  }
403  }
404 
405  // Read in the texture header and determine its size.
406  LVecBase4d geometry;
407  int num_channels;
408  bool texture_ok = scan_texture(filename, geometry, num_channels);
409  if (!texture_ok) {
410  all_ok = false;
411  }
412 
413  if (_got_pixel_scale) {
414  if (texture_ok) {
415  make_vertices(geometry, vpool, v1, v2, v3, v4);
416  } else {
417  make_vertices(_polygon_geometry, vpool, v1, v2, v3, v4);
418  }
419  }
420 
421  EggTexture *tref = new EggTexture(name, filename);
422  tref->set_wrap_mode(_wrap_mode);
423  tref->set_wrap_u(_wrap_u);
424  tref->set_wrap_v(_wrap_v);
425  tref->set_minfilter(_minfilter);
426  tref->set_magfilter(_magfilter);
427  if (_got_aniso_degree) {
428  tref->set_anisotropic_degree(_aniso_degree);
429  }
430  tref->set_quality_level(_quality_level);
431 
432  if (texture_ok) {
433  switch (num_channels) {
434  case 1:
435  tref->set_format(_format_1);
436  break;
437 
438  case 2:
439  tref->set_format(_format_2);
440  break;
441 
442  case 3:
443  tref->set_format(_format_3);
444  break;
445 
446  case 4:
447  tref->set_format(_format_4);
448  break;
449  }
450  }
451 
452  if (tref->get_format() == EggTexture::F_unspecified) {
453  tref->set_format(_format);
454  }
455 
456  group->add_child(tref);
457 
458  // Each polygon gets placed in its own sub-group. This will make pulling
459  // them out by name at runtime possible.
460  EggGroup *sub_group = new EggGroup(name);
461  group->add_child(sub_group);
462  EggPolygon *poly = new EggPolygon();
463  sub_group->add_child(poly);
464  poly->set_texture(tref);
465  poly->set_color(_polygon_color);
466  if (_apply_bface){
467  poly->set_bface_flag(1);
468  }
469 
470  poly->add_vertex(v1);
471  poly->add_vertex(v2);
472  poly->add_vertex(v3);
473  poly->add_vertex(v4);
474  }
475 
476  // Done!
477  if (all_ok || _noexist) {
478  write_egg_file();
479  } else {
480  nout << "Some textures not found; not generating egg file.\n";
481  exit(1);
482  }
483 }
484 
485 
486 int main(int argc, char *argv[]) {
487  EggTextureCards prog;
488  prog.parse_command_line(argc, argv);
489  prog.run();
490  return 0;
491 }
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition: eggGroup.h:34
A single polygon.
Definition: eggPolygon.h:24
set_bface_flag
Sets the backfacing flag of the polygon.
Definition: eggPrimitive.h:116
void set_texture(EggTexture *texture)
Replaces the current list of textures with the indicated texture.
Definition: eggPrimitive.I:116
EggVertex * add_vertex(EggVertex *vertex)
Adds the indicated vertex to the end of the primitive's list of vertices, and returns it.
Generates an egg file featuring a number of polygons, one for each named texture.
Defines a texture map that may be applied to geometry.
Definition: eggTexture.h:30
static Format string_format(const std::string &string)
Returns the Format value associated with the given string representation, or F_unspecified if the str...
Definition: eggTexture.cxx:693
static QualityLevel string_quality_level(const std::string &string)
Returns the TexGen value associated with the given string representation, or ET_unspecified if the st...
set_anisotropic_degree
Sets the degree of anisotropic filtering for this texture.
Definition: eggTexture.h:327
static FilterType string_filter_type(const std::string &string)
Returns the FilterType value associated with the given string representation, or FT_unspecified if th...
Definition: eggTexture.cxx:795
static WrapMode string_wrap_mode(const std::string &string)
Returns the WrapMode value associated with the given string representation, or WM_unspecified if the ...
Definition: eggTexture.cxx:773
A collection of vertices.
Definition: eggVertexPool.h:41
EggVertex * make_new_vertex()
Allocates and returns a new vertex from the pool.
Definition: eggVertexPool.I:37
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal.
Definition: eggVertex.h:39
void set_uv(const LTexCoordd &texCoord)
Replaces the unnamed UV coordinate pair on the vertex with the indicated value.
Definition: eggVertex.I:193
This is the base class for a program that generates an egg file output, but doesn't read any for inpu...
Definition: eggWriter.h:28
void write_egg_file()
Writes out the egg file as the normal result of the program.
Definition: eggWriter.cxx:177
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
static Filename from_os_specific(const std::string &os_specific, Type type=T_general)
This named constructor returns a Panda-style filename (that is, using forward slashes,...
Definition: filename.cxx:328
std::string get_basename_wo_extension() const
Returns the basename part of the filename, without the file extension.
Definition: filename.I:386
This is the base class of PNMImage, PNMReader, and PNMWriter.
bool read_header(const Filename &filename, PNMFileType *type=nullptr, bool report_unknown_type=true)
Opens up the image file and tries to read its header information to determine its size,...
int get_x_size() const
Returns the number of pixels in the X direction.
get_num_channels
Returns the number of channels in the image.
int get_y_size() const
Returns the number of pixels in the Y direction.
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_...
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.