Panda3D

eggTextureCards.cxx

00001 // Filename: eggTextureCards.cxx
00002 // Created by:  drose (21Feb01)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "eggTextureCards.h"
00016 
00017 #include "eggGroup.h"
00018 #include "eggVertexPool.h"
00019 #include "eggVertex.h"
00020 #include "eggTexture.h"
00021 #include "eggPolygon.h"
00022 #include "pnmImageHeader.h"
00023 #include "pystub.h"
00024 
00025 #include <algorithm>
00026 
00027 ////////////////////////////////////////////////////////////////////
00028 //     Function: EggTextureCards::Constructor
00029 //       Access: Public
00030 //  Description:
00031 ////////////////////////////////////////////////////////////////////
00032 EggTextureCards::
00033 EggTextureCards() : EggWriter(true, true) {
00034   set_program_description
00035     ("egg-texture-cards generates an egg file consisting of several "
00036      "square polygons, one for each texture name that appears on the "
00037      "command line.\n\n"
00038 
00039      "This is a handy thing to have for importing texture images through "
00040      "egg-palettize, even when those textures do not appear on any real "
00041      "geometry; it can also be used for creating a lot of simple polygons "
00042      "for rendering click buttons and similar interfaces.");
00043 
00044   clear_runlines();
00045   add_runline("[opts] texture [texture ...] output.egg");
00046   add_runline("[opts] -o output.egg texture [texture ...]");
00047   add_runline("[opts] texture [texture ...] >output.egg");
00048 
00049   add_option
00050     ("g", "left,right,bottom,top", 0,
00051      "Specifies the geometry of each polygon.  The default is a unit polygon "
00052      "centered on the origin: -0.5,0.5,-0.5,0.5.  Polygons are always created "
00053      "on the X-Y plane.  If -p is not also specified, all polygons will be "
00054      "the same size and shape.",
00055      &EggTextureCards::dispatch_double_quad, NULL, &_polygon_geometry[0]);
00056 
00057   add_option
00058     ("p", "xpixels,ypixels", 0,
00059      "Indicates that polygons should be sized in proportion to the pixel "
00060      "size of the texture image.  This will potentially create a "
00061      "different size and shape polygon for each texture.  The coordinate "
00062      "pair represents the image size in "
00063      "pixels that will exactly fill up the polygon described with -g (or the "
00064      "default polygon if -g is not specified); smaller images will be "
00065      "given proportionately smaller polygons, and larger images will be "
00066      "given proportionately larger polygons.",
00067      &EggTextureCards::dispatch_double_pair, &_got_pixel_scale, &_pixel_scale[0]);
00068 
00069   add_option
00070     ("suffix", "string", 0,
00071      "Normally, each polygon is given a name based on the basename of its "
00072      "corresponding texture's filename (without the filename extension).  "
00073      "This option specifies an ignorable suffix in the texture filename(s); "
00074      "if this suffix is present, it is not included in the polygon's name.  "
00075      "This option may be repeated multiple times.",
00076      &EggTextureCards::dispatch_vector_string, NULL, &_suffixes);
00077 
00078   add_option
00079     ("c", "r,g,b[,a]", 0,
00080      "Specifies the color of each polygon.  The default is white: 1,1,1,1.",
00081      &EggTextureCards::dispatch_color, NULL, &_polygon_color[0]);
00082 
00083   add_option
00084     ("wm", "wrap", 0,
00085      "Indicates the wrap mode of the texture: \"repeat\", \"clamp\", "
00086      "or any of the other modes supported by egg syntax.  "
00087      "The default is to leave this unspecified.",
00088      &EggTextureCards::dispatch_wrap_mode, NULL, &_wrap_mode);
00089 
00090   add_option
00091     ("wmu", "wrap_u", 0,
00092      "Indicates the wrap mode of the texture in the U direction.  This "
00093      "overrides -wm, if specified.",
00094      &EggTextureCards::dispatch_wrap_mode, NULL, &_wrap_u);
00095 
00096   add_option
00097     ("wmv", "wrap_v", 0,
00098      "Indicates the wrap mode of the texture in the V direction.  This "
00099      "overrides -wm, if specified.",
00100      &EggTextureCards::dispatch_wrap_mode, NULL, &_wrap_v);
00101 
00102   add_option
00103     ("minf", "filter", 0,
00104      "Indicates the minfilter mode of the texture: \"linear\", \"mipmap\", "
00105      "or any of the other modes supported by egg syntax.  "
00106      "The default is to leave this unspecified.",
00107      &EggTextureCards::dispatch_filter_type, NULL, &_minfilter);
00108 
00109   add_option
00110     ("magf", "filter", 0,
00111      "Indicates the magfilter mode of the texture: \"linear\" or \"nearest\".  "
00112      "The default is to leave this unspecified.",
00113      &EggTextureCards::dispatch_filter_type, NULL, &_magfilter);
00114 
00115   add_option
00116     ("aniso", "degree", 0,
00117      "Indicates the anisotropic degree of the texture.  "
00118      "The default is to leave this unspecified.",
00119      &EggTextureCards::dispatch_int, &_got_aniso_degree, &_aniso_degree);
00120 
00121   add_option
00122     ("ql", "[default | fastest | normal | best]", 0,
00123      "Specifies the quality level of the texture.  This mainly affects "
00124      "the tinydisplay software renderer.",
00125      &EggTextureCards::dispatch_quality_level, NULL, &_quality_level);
00126 
00127   add_option
00128     ("f", "format", 0,
00129      "Indicates the format for all textures: typical choices are \"rgba12\" "
00130      "or \"rgb5\" or \"alpha\".  The default is to leave this unspecified.",
00131      &EggTextureCards::dispatch_format, NULL, &_format);
00132 
00133   add_option
00134     ("f1", "format", 0,
00135      "Indicates the format for one-channel textures only.  If specified, this "
00136      "overrides the format specified by -f.",
00137      &EggTextureCards::dispatch_format, NULL, &_format_1);
00138 
00139   add_option
00140     ("f2", "format", 0,
00141      "Indicates the format for two-channel textures only.  If specified, this "
00142      "overrides the format specified by -f.",
00143      &EggTextureCards::dispatch_format, NULL, &_format_2);
00144 
00145   add_option
00146     ("f3", "format", 0,
00147      "Indicates the format for three-channel textures only.  If specified, this "
00148      "overrides the format specified by -f.",
00149      &EggTextureCards::dispatch_format, NULL, &_format_3);
00150 
00151   add_option
00152     ("f4", "format", 0,
00153      "Indicates the format for four-channel textures only.  If specified, this "
00154      "overrides the format specified by -f.",
00155      &EggTextureCards::dispatch_format, NULL, &_format_4);
00156 
00157   add_option
00158     ("b", "", 0,
00159      "Make the textured polygons backfaced (two-sided).",
00160      &EggTextureCards::dispatch_none, &_apply_bface);
00161 
00162   add_option
00163     ("fps", "frame-rate", 0,
00164      "Normally, all of the texture cards are created as a series of nodes "
00165      "beneath a SequenceNode.  This allows all of the cards to be viewed, "
00166      "one at a time, if the output file is loaded in pview.  It also has the "
00167      "nice side-effect of creating an automatic texture flip that can be "
00168      "used directly by applications; use this parameter to specify the "
00169      "frame rate of that texture flip.",
00170      &EggTextureCards::dispatch_double, NULL, &_frame_rate);
00171 
00172   add_option
00173     ("noexist", "", 0,
00174      "Don't treat it as an error if the input file references pathnames "
00175      "(e.g. textures) that don't exist.  Normally, this will be flagged as "
00176      "an error and the command aborted; with this option, an egg file will "
00177      "be generated anyway, referencing pathnames that do not exist.",
00178      &EggTextureCards::dispatch_none, &_noexist);
00179 
00180   _polygon_geometry.set(-0.5, 0.5, -0.5, 0.5);
00181   _polygon_color.set(1.0, 1.0, 1.0, 1.0);
00182   _wrap_mode = EggTexture::WM_unspecified;
00183   _wrap_u = EggTexture::WM_unspecified;
00184   _wrap_v = EggTexture::WM_unspecified;
00185   _minfilter = EggTexture::FT_unspecified;
00186   _magfilter = EggTexture::FT_unspecified;
00187   _aniso_degree = 0;
00188   _quality_level = EggTexture::QL_unspecified;
00189   _format = EggTexture::F_unspecified;
00190   _format_1 = EggTexture::F_unspecified;
00191   _format_2 = EggTexture::F_unspecified;
00192   _format_3 = EggTexture::F_unspecified;
00193   _format_4 = EggTexture::F_unspecified;
00194   _frame_rate = 2.0;
00195 }
00196 
00197 ////////////////////////////////////////////////////////////////////
00198 //     Function: EggTextureCards::handle_args
00199 //       Access: Protected, Virtual
00200 //  Description: Does something with the additional arguments on the
00201 //               command line (after all the -options have been
00202 //               parsed).  Returns true if the arguments are good,
00203 //               false otherwise.
00204 ////////////////////////////////////////////////////////////////////
00205 bool EggTextureCards::
00206 handle_args(ProgramBase::Args &args) {
00207   if (!check_last_arg(args, 0)) {
00208     return false;
00209   }
00210 
00211   if (args.empty()) {
00212     nout << "No texture names specified on the command line.\n";
00213     return false;
00214   }
00215 
00216   ProgramBase::Args::iterator ai;
00217   for (ai = args.begin(); ai != args.end(); ++ai) {
00218     _texture_names.push_back(Filename::from_os_specific(*ai));
00219   }
00220 
00221   return true;
00222 }
00223 
00224 ////////////////////////////////////////////////////////////////////
00225 //     Function: EggTextureCards::dispatch_wrap_mode
00226 //       Access: Protected, Static
00227 //  Description: Standard dispatch function for an option that takes
00228 //               one parameter, which is to be interpreted as a
00229 //               WrapMode string.  The data pointer is to a WrapMode
00230 //               enum variable.
00231 ////////////////////////////////////////////////////////////////////
00232 bool EggTextureCards::
00233 dispatch_wrap_mode(const string &opt, const string &arg, void *var) {
00234   EggTexture::WrapMode *wmp = (EggTexture::WrapMode *)var;
00235 
00236   *wmp = EggTexture::string_wrap_mode(arg);
00237   if (*wmp == EggTexture::WM_unspecified) {
00238     // An unknown string.  Let's check for our special cases.
00239     if (arg == "r") {
00240       *wmp = EggTexture::WM_repeat;
00241     } else if (arg == "c") {
00242       *wmp = EggTexture::WM_clamp;
00243     } else {
00244       nout << "Invalid wrap mode parameter for -" << opt << ": "
00245            << arg << "\n";
00246       return false;
00247     }
00248   }
00249 
00250   return true;
00251 }
00252 
00253 ////////////////////////////////////////////////////////////////////
00254 //     Function: EggTextureCards::dispatch_filter_type
00255 //       Access: Protected, Static
00256 //  Description: Standard dispatch function for an option that takes
00257 //               one parameter, which is to be interpreted as a
00258 //               FilterType string.  The data pointer is to a
00259 //               FilterType enum variable.
00260 ////////////////////////////////////////////////////////////////////
00261 bool EggTextureCards::
00262 dispatch_filter_type(const string &opt, const string &arg, void *var) {
00263   EggTexture::FilterType *ftp = (EggTexture::FilterType *)var;
00264 
00265   *ftp = EggTexture::string_filter_type(arg);
00266   if (*ftp == EggTexture::FT_unspecified) {
00267     // An unknown string.
00268     nout << "Invalid filter type parameter for -" << opt << ": "
00269          << arg << "\n";
00270     return false;
00271   }
00272 
00273   return true;
00274 }
00275 
00276 ////////////////////////////////////////////////////////////////////
00277 //     Function: EggTextureCards::dispatch_quality_level
00278 //       Access: Protected, Static
00279 //  Description: Standard dispatch function for an option that takes
00280 //               one parameter, which is to be interpreted as a
00281 //               QualityLevel string.  The data pointer is to a
00282 //               QualityLevel enum variable.
00283 ////////////////////////////////////////////////////////////////////
00284 bool EggTextureCards::
00285 dispatch_quality_level(const string &opt, const string &arg, void *var) {
00286   EggTexture::QualityLevel *qlp = (EggTexture::QualityLevel *)var;
00287 
00288   *qlp = EggTexture::string_quality_level(arg);
00289   if (*qlp == EggTexture::QL_unspecified) {
00290     nout << "Invalid quality level parameter for -" << opt << ": "
00291          << arg << "\n";
00292     return false;
00293   }
00294 
00295   return true;
00296 }
00297 
00298 ////////////////////////////////////////////////////////////////////
00299 //     Function: EggTextureCards::dispatch_format
00300 //       Access: Protected, Static
00301 //  Description: Standard dispatch function for an option that takes
00302 //               one parameter, which is to be interpreted as a
00303 //               Format string.  The data pointer is to a Format
00304 //               enum variable.
00305 ////////////////////////////////////////////////////////////////////
00306 bool EggTextureCards::
00307 dispatch_format(const string &opt, const string &arg, void *var) {
00308   EggTexture::Format *fp = (EggTexture::Format *)var;
00309 
00310   *fp = EggTexture::string_format(arg);
00311   if (*fp == EggTexture::F_unspecified) {
00312     nout << "Invalid format parameter for -" << opt << ": "
00313          << arg << "\n";
00314     return false;
00315   }
00316 
00317   return true;
00318 }
00319 
00320 
00321 ////////////////////////////////////////////////////////////////////
00322 //     Function: EggTextureCards::scan_texture
00323 //       Access: Private
00324 //  Description: Reads the texture image header to determine its size,
00325 //               and based on this size, computes the appropriate
00326 //               left,right,bottom,top geometry of the card that
00327 //               correspond to this texture.
00328 //
00329 //               Returns true if successful, or false if the texture
00330 //               cannot be read.
00331 ////////////////////////////////////////////////////////////////////
00332 bool EggTextureCards::
00333 scan_texture(const Filename &filename, LVecBase4d &geometry,
00334              int &num_channels) {
00335   PNMImageHeader header;
00336   if (!header.read_header(filename)) {
00337     nout << "Unable to read image " << filename << "\n";
00338     return false;
00339   }
00340 
00341   num_channels = header.get_num_channels();
00342 
00343   double xscale = header.get_x_size() / _pixel_scale[0];
00344   double yscale = header.get_y_size() / _pixel_scale[1];
00345 
00346   geometry.set(_polygon_geometry[0] * xscale,
00347                _polygon_geometry[1] * xscale,
00348                _polygon_geometry[2] * yscale,
00349                _polygon_geometry[3] * yscale);
00350   return true;
00351 }
00352 
00353 ////////////////////////////////////////////////////////////////////
00354 //     Function: EggTextureCards::make_vertices
00355 //       Access: Private
00356 //  Description: Creates a set of four vertices for the polygon
00357 //               according to the left,right,bottom,top geometry.
00358 ////////////////////////////////////////////////////////////////////
00359 void EggTextureCards::
00360 make_vertices(const LPoint4d &geometry, EggVertexPool *vpool,
00361               EggVertex *&v1, EggVertex *&v2, EggVertex *&v3, EggVertex *&v4) {
00362   //
00363   //   1     4
00364   //
00365   //
00366   //   2     3
00367   //
00368 
00369   v1 = vpool->make_new_vertex
00370     (LPoint3d(geometry[0], geometry[3], 0.0));
00371   v2 = vpool->make_new_vertex
00372     (LPoint3d(geometry[0], geometry[2], 0.0));
00373   v3 = vpool->make_new_vertex
00374     (LPoint3d(geometry[1], geometry[2], 0.0));
00375   v4 = vpool->make_new_vertex
00376     (LPoint3d(geometry[1], geometry[3], 0.0));
00377 
00378   v1->set_uv(LTexCoordd(0.0, 1.0));
00379   v2->set_uv(LTexCoordd(0.0, 0.0));
00380   v3->set_uv(LTexCoordd(1.0, 0.0));
00381   v4->set_uv(LTexCoordd(1.0, 1.0));
00382 }
00383 
00384 ////////////////////////////////////////////////////////////////////
00385 //     Function: EggTextureCards::run
00386 //       Access: Public
00387 //  Description:
00388 ////////////////////////////////////////////////////////////////////
00389 void EggTextureCards::
00390 run() {
00391   // First, create an enclosing group and a vertex pool with four
00392   // vertices.  We can use the same four vertices on all polygons.
00393   bool all_ok = true;
00394 
00395   EggGroup *group = new EggGroup();
00396   _data->add_child(group);
00397 
00398   // If we have more than one tile, make the group a sequence, as a
00399   // convenience.  If we view the egg file directly we can see all the
00400   // tiles one at a time.
00401   if (_texture_names.size() > 1) {
00402     group->set_switch_flag(true);
00403     group->set_switch_fps(_frame_rate);
00404   }
00405 
00406   EggVertexPool *vpool = new EggVertexPool("vpool");
00407   group->add_child(vpool);
00408 
00409   EggVertex *v1, *v2, *v3, *v4;
00410 
00411   if (!_got_pixel_scale) {
00412     // If we don't have a per-texture pixel scale, all the polygons
00413     // will be the same size, and hence may all share the same four
00414     // vertices.
00415     make_vertices(_polygon_geometry, vpool, v1, v2, v3, v4);
00416   }
00417 
00418   // Now, create a texture reference and a polygon for each texture.
00419 
00420   vector_string::const_iterator ti;
00421   for (ti = _texture_names.begin(); ti != _texture_names.end(); ++ti) {
00422     Filename filename = (*ti);
00423     string name = filename.get_basename_wo_extension();
00424 
00425     // Strip off any suffixes from the name.
00426     vector_string::const_iterator si;
00427     for (si = _suffixes.begin(); si != _suffixes.end(); ++si) {
00428       const string &suffix = (*si);
00429       int prefix = (int)name.length() - (int)suffix.length();
00430       if (prefix > 0 && name.substr(prefix) == suffix) {
00431         name = name.substr(0, prefix);
00432       }
00433     }
00434 
00435     // Read in the texture header and determine its size.
00436     LVecBase4d geometry;
00437     int num_channels;
00438     bool texture_ok = scan_texture(filename, geometry, num_channels);
00439     if (!texture_ok) {
00440       all_ok = false;
00441     }
00442 
00443     if (_got_pixel_scale) {
00444       if (texture_ok) {
00445         make_vertices(geometry, vpool, v1, v2, v3, v4);
00446       } else {
00447         make_vertices(_polygon_geometry, vpool, v1, v2, v3, v4);
00448       }
00449     }
00450 
00451     EggTexture *tref = new EggTexture(name, filename);
00452     tref->set_wrap_mode(_wrap_mode);
00453     tref->set_wrap_u(_wrap_u);
00454     tref->set_wrap_v(_wrap_v);
00455     tref->set_minfilter(_minfilter);
00456     tref->set_magfilter(_magfilter);
00457     if (_got_aniso_degree) {
00458       tref->set_anisotropic_degree(_aniso_degree);
00459     }
00460     tref->set_quality_level(_quality_level);
00461 
00462     if (texture_ok) {
00463       switch (num_channels) {
00464       case 1:
00465         tref->set_format(_format_1);
00466         break;
00467 
00468       case 2:
00469         tref->set_format(_format_2);
00470         break;
00471 
00472       case 3:
00473         tref->set_format(_format_3);
00474         break;
00475 
00476       case 4:
00477         tref->set_format(_format_4);
00478         break;
00479       }
00480     }
00481 
00482     if (tref->get_format() == EggTexture::F_unspecified) {
00483       tref->set_format(_format);
00484     }
00485 
00486     group->add_child(tref);
00487 
00488     // Each polygon gets placed in its own sub-group.  This will make
00489     // pulling them out by name at runtime possible.
00490     EggGroup *sub_group = new EggGroup(name);
00491     group->add_child(sub_group);
00492     EggPolygon *poly = new EggPolygon();
00493     sub_group->add_child(poly);
00494     poly->set_texture(tref);
00495     poly->set_color(_polygon_color);
00496     if (_apply_bface){
00497       poly->set_bface_flag(1);
00498     }
00499 
00500     poly->add_vertex(v1);
00501     poly->add_vertex(v2);
00502     poly->add_vertex(v3);
00503     poly->add_vertex(v4);
00504   }
00505 
00506   // Done!
00507   if (all_ok || _noexist) {
00508     write_egg_file();
00509   } else {
00510     nout << "Some textures not found; not generating egg file.\n";
00511     exit(1);
00512   }
00513 }
00514 
00515 
00516 int main(int argc, char *argv[]) {
00517   // A call to pystub() to force libpystub.so to be linked in.
00518   pystub();
00519 
00520   EggTextureCards prog;
00521   prog.parse_command_line(argc, argv);
00522   prog.run();
00523   return 0;
00524 }
 All Classes Functions Variables Enumerations