EG/pandatool/src/eggbase/eggBase.cxx

406 lines
12 KiB
C++

/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file eggBase.cxx
* @author drose
* @date 2000-02-14
*/
#include "eggBase.h"
#include "eggGroupNode.h"
#include "eggTexture.h"
#include "eggFilenameNode.h"
#include "eggComment.h"
#include "dcast.h"
#include "string_utils.h"
using std::string;
/**
*
*/
EggBase::
EggBase() {
add_option
("cs", "coordinate-system", 80,
"Specify the coordinate system to operate in. This may be one of "
"'y-up', 'z-up', 'y-up-left', or 'z-up-left'.",
&EggBase::dispatch_coordinate_system,
&_got_coordinate_system, &_coordinate_system);
_normals_mode = NM_preserve;
_normals_threshold = 0.0;
_got_tbnall = false;
_got_tbnauto = false;
_make_points = false;
_got_transform = false;
_transform = LMatrix4d::ident_mat();
_got_coordinate_system = false;
_coordinate_system = CS_yup_right;
_noabs = false;
}
/**
* Adds -no, -np, etc. as valid options for this program. If the user
* specifies one of the options on the command line, the normals will be
* adjusted when the egg file is written out.
*/
void EggBase::
add_normals_options() {
static NormalsMode strip = NM_strip;
static NormalsMode polygon = NM_polygon;
static NormalsMode vertex = NM_vertex;
static NormalsMode preserve = NM_preserve;
add_option
("no", "", 48,
"Strip all normals.",
&EggBase::dispatch_normals, nullptr, &strip);
add_option
("np", "", 48,
"Strip existing normals and redefine polygon normals.",
&EggBase::dispatch_normals, nullptr, &polygon);
add_option
("nv", "threshold", 48,
"Strip existing normals and redefine vertex normals. Consider an edge "
"between adjacent polygons to be smooth if the angle between them "
"is less than threshold degrees.",
&EggBase::dispatch_normals, nullptr, &vertex);
add_option
("nn", "", 48,
"Preserve normals exactly as they are. This is the default.",
&EggBase::dispatch_normals, nullptr, &preserve);
add_option
("tbn", "name", 48,
"Compute tangent and binormal for the named texture coordinate "
"set(s). The name may include wildcard characters such as * and ?. "
"The normal must already exist or have been computed via one of the "
"above options. The tangent and binormal are used to implement "
"bump mapping and related texture-based lighting effects. This option "
"may be repeated as necessary to name multiple texture coordinate sets.",
&EggBase::dispatch_vector_string, nullptr, &_tbn_names);
add_option
("tbnall", "", 48,
"Compute tangent and binormal for all texture coordinate "
"sets. This is equivalent to -tbn \"*\".",
&EggBase::dispatch_none, &_got_tbnall);
add_option
("tbnauto", "", 48,
"Compute tangent and binormal for all normal maps. ",
&EggBase::dispatch_none, &_got_tbnauto);
}
/**
* Adds -points as a valid option for this program.
*/
void EggBase::
add_points_options() {
add_option
("points", "", 46,
"Construct <PointLight> entries for any unreferenced vertices, to make them visible.",
&EggBase::dispatch_none, &_make_points);
}
/**
* Adds -TS, -TT, etc. as valid options for this program. If the user
* specifies one of the options on the command line, the data will be
* transformed when the egg file is written out.
*/
void EggBase::
add_transform_options() {
add_option
("TS", "sx[,sy,sz]", 49,
"Scale the model uniformly by the given factor (if only one number "
"is given) or in each axis by sx, sy, sz (if three numbers are given).",
&EggBase::dispatch_scale, &_got_transform, &_transform);
add_option
("TR", "x,y,z", 49,
"Rotate the model x degrees about the x axis, then y degrees about the "
"y axis, and then z degrees about the z axis.",
&EggBase::dispatch_rotate_xyz, &_got_transform, &_transform);
add_option
("TA", "angle,x,y,z", 49,
"Rotate the model angle degrees counterclockwise about the given "
"axis.",
&EggBase::dispatch_rotate_axis, &_got_transform, &_transform);
add_option
("TT", "x,y,z", 49,
"Translate the model by the indicated amount.\n\n"
"All transformation options (-TS, -TR, -TA, -TT) are cumulative and are "
"applied in the order they are encountered on the command line.",
&EggBase::dispatch_translate, &_got_transform, &_transform);
}
/**
* Recursively walks the egg hierarchy. Any filenames encountered are
* replaced according to the indicated PathReplace.
*/
void EggBase::
convert_paths(EggNode *node, PathReplace *path_replace,
const DSearchPath &additional_path) {
if (node->is_of_type(EggTexture::get_class_type())) {
EggTexture *egg_tex = DCAST(EggTexture, node);
Filename fullpath, outpath;
path_replace->full_convert_path(egg_tex->get_filename(), additional_path,
fullpath, outpath);
egg_tex->set_filename(outpath);
egg_tex->set_fullpath(fullpath);
if (egg_tex->has_alpha_filename()) {
Filename alpha_fullpath, alpha_outpath;
path_replace->full_convert_path(egg_tex->get_alpha_filename(), additional_path,
alpha_fullpath, alpha_outpath);
egg_tex->set_alpha_filename(alpha_outpath);
egg_tex->set_alpha_fullpath(alpha_fullpath);
}
} else if (node->is_of_type(EggFilenameNode::get_class_type())) {
EggFilenameNode *egg_fnode = DCAST(EggFilenameNode, node);
Filename fullpath, outpath;
path_replace->full_convert_path(egg_fnode->get_filename(), additional_path,
fullpath, outpath);
egg_fnode->set_filename(outpath);
egg_fnode->set_fullpath(fullpath);
} else if (node->is_of_type(EggGroupNode::get_class_type())) {
EggGroupNode *egg_group = DCAST(EggGroupNode, node);
EggGroupNode::const_iterator ci;
for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
convert_paths(*ci, path_replace, additional_path);
}
}
}
/**
* Inserts a comment into the beginning of the indicated egg file
* corresponding to the command line that invoked this program.
*
* Normally this function is called automatically when appropriate by
* EggWriter, and it's not necessary to call it explicitly.
*/
void EggBase::
append_command_comment(EggData *data) {
append_command_comment(data, get_exec_command());
}
/**
* Inserts a comment into the beginning of the indicated egg file
* corresponding to the command line that invoked this program.
*
* Normally this function is called automatically when appropriate by
* EggWriter, and it's not necessary to call it explicitly.
*/
void EggBase::
append_command_comment(EggData *data, const string &comment) {
data->insert(data->begin(), new EggComment("", comment));
}
/**
* Accepts one of -no, -np, etc. and sets _normals_mode as indicated. The
* void * argument is a pointer to a NormalsMode variable that indicates which
* switch was passed.
*/
bool EggBase::
dispatch_normals(ProgramBase *self, const string &opt, const string &arg, void *mode) {
EggBase *base = (EggBase *)self;
return base->ns_dispatch_normals(opt, arg, mode);
}
/**
* Accepts one of -no, -np, etc. and sets _normals_mode as indicated. The
* void * argument is a pointer to a NormalsMode variable that indicates which
* switch was passed.
*/
bool EggBase::
ns_dispatch_normals(const string &opt, const string &arg, void *mode) {
_normals_mode = *(NormalsMode *)mode;
if (_normals_mode == NM_vertex) {
if (!string_to_double(arg, _normals_threshold)) {
nout << "Invalid numeric parameter for -" << opt << ": "
<< arg << "\n";
return false;
}
}
return true;
}
/**
* Handles -TS, which specifies a scale transform. Var is an LMatrix4d.
*/
bool EggBase::
dispatch_scale(const string &opt, const string &arg, void *var) {
LMatrix4d *transform = (LMatrix4d *)var;
vector_string words;
tokenize(arg, words, ",");
double sx, sy, sz;
bool okflag = false;
if (words.size() == 3) {
okflag =
string_to_double(words[0], sx) &&
string_to_double(words[1], sy) &&
string_to_double(words[2], sz);
} else if (words.size() == 1) {
okflag =
string_to_double(words[0], sx);
sy = sz = sx;
}
if (!okflag) {
nout << "-" << opt
<< " requires one or three numbers separated by commas.\n";
return false;
}
*transform = (*transform) * LMatrix4d::scale_mat(sx, sy, sz);
return true;
}
/**
* Handles -TR, which specifies a rotate transform about the three cardinal
* axes. Var is an LMatrix4d.
*/
bool EggBase::
dispatch_rotate_xyz(ProgramBase *self, const string &opt, const string &arg, void *var) {
EggBase *base = (EggBase *)self;
return base->ns_dispatch_rotate_xyz(opt, arg, var);
}
/**
* Handles -TR, which specifies a rotate transform about the three cardinal
* axes. Var is an LMatrix4d.
*/
bool EggBase::
ns_dispatch_rotate_xyz(const string &opt, const string &arg, void *var) {
LMatrix4d *transform = (LMatrix4d *)var;
vector_string words;
tokenize(arg, words, ",");
LVecBase3d xyz;
bool okflag = false;
if (words.size() == 3) {
okflag =
string_to_double(words[0], xyz[0]) &&
string_to_double(words[1], xyz[1]) &&
string_to_double(words[2], xyz[2]);
}
if (!okflag) {
nout << "-" << opt
<< " requires three numbers separated by commas.\n";
return false;
}
LMatrix4d mat =
LMatrix4d::rotate_mat(xyz[0], LVector3d(1.0, 0.0, 0.0), _coordinate_system) *
LMatrix4d::rotate_mat(xyz[1], LVector3d(0.0, 1.0, 0.0), _coordinate_system) *
LMatrix4d::rotate_mat(xyz[2], LVector3d(0.0, 0.0, 1.0), _coordinate_system);
*transform = (*transform) * mat;
return true;
}
/**
* Handles -TA, which specifies a rotate transform about an arbitrary axis.
* Var is an LMatrix4d.
*/
bool EggBase::
dispatch_rotate_axis(ProgramBase *self, const string &opt, const string &arg, void *var) {
EggBase *base = (EggBase *)self;
return base->ns_dispatch_rotate_axis(opt, arg, var);
}
/**
* Handles -TA, which specifies a rotate transform about an arbitrary axis.
* Var is an LMatrix4d.
*/
bool EggBase::
ns_dispatch_rotate_axis(const string &opt, const string &arg, void *var) {
LMatrix4d *transform = (LMatrix4d *)var;
vector_string words;
tokenize(arg, words, ",");
double angle;
LVecBase3d axis;
bool okflag = false;
if (words.size() == 4) {
okflag =
string_to_double(words[0], angle) &&
string_to_double(words[1], axis[0]) &&
string_to_double(words[2], axis[1]) &&
string_to_double(words[3], axis[2]);
}
if (!okflag) {
nout << "-" << opt
<< " requires four numbers separated by commas.\n";
return false;
}
*transform = (*transform) * LMatrix4d::rotate_mat(angle, axis, _coordinate_system);
return true;
}
/**
* Handles -TT, which specifies a translate transform. Var is an LMatrix4d.
*/
bool EggBase::
dispatch_translate(const string &opt, const string &arg, void *var) {
LMatrix4d *transform = (LMatrix4d *)var;
vector_string words;
tokenize(arg, words, ",");
LVector3d trans;
bool okflag = false;
if (words.size() == 3) {
okflag =
string_to_double(words[0], trans[0]) &&
string_to_double(words[1], trans[1]) &&
string_to_double(words[2], trans[2]);
}
if (!okflag) {
nout << "-" << opt
<< " requires three numbers separated by commas.\n";
return false;
}
*transform = (*transform) * LMatrix4d::translate_mat(trans);
return true;
}