2005-08-08 01:57:40 +00:00

428 lines
15 KiB
C++

// Filename: eggBase.cxx
// Created by: drose (14Feb00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "eggBase.h"
#include "eggGroupNode.h"
#include "eggTexture.h"
#include "eggFilenameNode.h"
#include "eggComment.h"
#include "dcast.h"
#include "string_utils.h"
////////////////////////////////////////////////////////////////////
// Function: EggBase::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
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_transform = false;
_transform = LMatrix4d::ident_mat();
_got_coordinate_system = false;
_coordinate_system = CS_yup_right;
_noabs = false;
}
////////////////////////////////////////////////////////////////////
// Function: EggBase::add_normals_options
// Access: Public
// Description: 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, NULL, &strip);
add_option
("np", "", 48,
"Strip existing normals and redefine polygon normals.",
&EggBase::dispatch_normals, NULL, &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, NULL, &vertex);
add_option
("nn", "", 48,
"Preserve normals exactly as they are. This is the default.",
&EggBase::dispatch_normals, NULL, &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, NULL, &_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);
}
////////////////////////////////////////////////////////////////////
// Function: EggBase::add_transform_options
// Access: Public
// Description: 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);
}
////////////////////////////////////////////////////////////////////
// Function: EggBase::convert_paths
// Access: Public, Static
// Description: 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);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: EggBase::append_command_comment
// Access: Protected
// Description: 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());
}
////////////////////////////////////////////////////////////////////
// Function: EggBase::append_command_comment
// Access: Protected, Static
// Description: 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));
}
////////////////////////////////////////////////////////////////////
// Function: EggBase::dispatch_normals
// Access: Protected, Static
// Description: 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);
}
////////////////////////////////////////////////////////////////////
// Function: EggBase::ns_dispatch_normals
// Access: Protected
// Description: 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;
}
////////////////////////////////////////////////////////////////////
// Function: EggBase::dispatch_scale
// Access: Protected, Static
// Description: 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;
}
////////////////////////////////////////////////////////////////////
// Function: EggBase::dispatch_rotate_xyz
// Access: Protected, Static
// Description: 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);
}
////////////////////////////////////////////////////////////////////
// Function: EggBase::ns_dispatch_rotate_xyz
// Access: Protected
// Description: 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;
}
////////////////////////////////////////////////////////////////////
// Function: EggBase::dispatch_rotate_axis
// Access: Protected, Static
// Description: 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);
}
////////////////////////////////////////////////////////////////////
// Function: EggBase::ns_dispatch_rotate_axis
// Access: Protected
// Description: 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;
}
////////////////////////////////////////////////////////////////////
// Function: EggBase::dispatch_translate
// Access: Protected, Static
// Description: 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;
}