00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
00029
00030
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
00199
00200
00201
00202
00203
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
00226
00227
00228
00229
00230
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
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
00255
00256
00257
00258
00259
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
00268 nout << "Invalid filter type parameter for -" << opt << ": "
00269 << arg << "\n";
00270 return false;
00271 }
00272
00273 return true;
00274 }
00275
00276
00277
00278
00279
00280
00281
00282
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
00300
00301
00302
00303
00304
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
00323
00324
00325
00326
00327
00328
00329
00330
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
00355
00356
00357
00358
00359 void EggTextureCards::
00360 make_vertices(const LPoint4d &geometry, EggVertexPool *vpool,
00361 EggVertex *&v1, EggVertex *&v2, EggVertex *&v3, EggVertex *&v4) {
00362
00363
00364
00365
00366
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
00386
00387
00388
00389 void EggTextureCards::
00390 run() {
00391
00392
00393 bool all_ok = true;
00394
00395 EggGroup *group = new EggGroup();
00396 _data->add_child(group);
00397
00398
00399
00400
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
00413
00414
00415 make_vertices(_polygon_geometry, vpool, v1, v2, v3, v4);
00416 }
00417
00418
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
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
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
00489
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
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
00518 pystub();
00519
00520 EggTextureCards prog;
00521 prog.parse_command_line(argc, argv);
00522 prog.run();
00523 return 0;
00524 }