open_toontown_panda3d/pandatool/src/egg-qtess/qtessInputFile.cxx

350 lines
11 KiB
C++

// Filename: qtessInputFile.cxx
// Created by: drose (13Oct03)
//
////////////////////////////////////////////////////////////////////
//
// 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 "qtessInputFile.h"
#include "config_egg_qtess.h"
#include "string_utils.h"
////////////////////////////////////////////////////////////////////
// Function: QtessInputFile::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
QtessInputFile::
QtessInputFile() {
}
////////////////////////////////////////////////////////////////////
// Function: QtessInputFile::read
// Access: Public
// Description: reads the input file.
////////////////////////////////////////////////////////////////////
bool QtessInputFile::
read(const Filename &filename) {
_filename = Filename::text_filename(filename);
_entries.clear();
ifstream input;
if (!_filename.open_read(input)) {
qtess_cat.error()
<< "Unable to open input file " << _filename << "\n";
return false;
}
string complete_line;
int line_number = 0;
string line;
while (getline(input, line)) {
line_number++;
// Eliminate comments. We have to scan the line repeatedly until
// we find the first hash mark that's preceded by whitespace.
size_t comment = line.find('#');
while (comment != string::npos) {
if (comment == 0 || isspace(line[comment - 1])) {
line = line.substr(0, comment);
comment = string::npos;
} else {
comment = line.find('#', comment + 1);
}
}
// Check for a trailing backslash: continuation character.
line = trim_right(line);
if (!line.empty() && line[line.size() - 1] == '\\') {
// We have a continuation character; go back and read some more.
complete_line += line.substr(0, line.size() - 1);
} else {
// It's a complete line. Begin parsing.
line = trim(complete_line + line);
complete_line = string();
if (!line.empty()) {
QtessInputEntry entry;
// Scan for the first colon followed by whitespace.
size_t colon = line.find(": ");
if (colon == string::npos) {
qtess_cat.error()
<< _filename << ": line " << line_number
<< " has no colon followed by whitespace.\n";
return false;
}
if (colon == 0) {
qtess_cat.error()
<< _filename << ": line " << line_number
<< " has no nodes.\n";
return false;
}
// Split the line into two groups of words at the colon: names
// before the colon, and params following it.
vector_string names, params;
extract_words(line.substr(0, colon), names);
extract_words(line.substr(colon + 1), params);
vector_string::const_iterator ni;
for (ni = names.begin(); ni != names.end(); ++ni) {
entry.add_node_name(*ni);
}
// Scan for things like ap, ad, ar, and pull them out of the
// stream.
vector_string::iterator ci, cnext;
ci = params.begin();
while (ci != params.end()) {
cnext = ci;
++cnext;
string param = *ci;
bool invert = false;
if (param[0] == '!' && param.size() > 1) {
invert = true;
param = param.substr(1);
}
if (tolower(param[0]) == 'a' && param.size() > 1) {
switch (tolower(param[1])) {
case 'p':
entry._auto_place = !invert;
break;
case 'd':
entry._auto_distribute = !invert;
break;
case 'r':
if (!string_to_double(param.substr(2), entry._curvature_ratio)) {
qtess_cat.error()
<< _filename << ": line " << line_number
<< " - invalid field " << param << "\n";
return false;
}
break;
default:
qtess_cat.error()
<< _filename << ": invalid parameters at line "
<< line_number << ".\n";
return false;
}
params.erase(ci);
} else {
ci = cnext;
}
}
if (!params.empty()) {
bool okflag = true;
if (cmp_nocase(params[0], "omit")==0) {
entry.set_omit();
} else if (cmp_nocase(params[0], "matchuu")==0) {
entry.set_match_uu();
if (params.size() > 1 && cmp_nocase(params[1], "matchvv")==0) {
entry.set_match_vv();
}
} else if (cmp_nocase(params[0], "matchvv")==0) {
entry.set_match_vv();
if (params.size() > 1 && cmp_nocase(params[1], "matchuu")==0) {
entry.set_match_uu();
}
} else if (cmp_nocase(params[0], "matchuv")==0) {
entry.set_match_uv();
if (params.size() > 1 && cmp_nocase(params[1], "matchvu")==0) {
entry.set_match_vu();
}
} else if (cmp_nocase(params[0], "matchvu")==0) {
entry.set_match_vu();
if (params.size() > 1 && cmp_nocase(params[1], "matchuv")==0) {
entry.set_match_uv();
}
} else if (cmp_nocase(params[0], "minu")==0) {
// minu #: minimum tesselation in U.
if (params.size() < 2) {
okflag = false;
} else {
int value = 0;
okflag = string_to_int(params[1], value);
entry.set_min_u(value);
}
} else if (cmp_nocase(params[0], "minv")==0) {
// minu #: minimum tesselation in V.
if (params.size() < 2) {
okflag = false;
} else {
int value = 0;
okflag = string_to_int(params[1], value);
entry.set_min_v(value);
}
} else if (tolower(params[0][0]) == 'i') {
// "i#": per-isoparam tesselation.
int value = 0;
okflag = string_to_int(params[0].substr(1), value);
entry.set_per_isoparam(value);
} else if (params[0][params[0].length() - 1] == '%') {
double value = 0.0;
okflag = string_to_double(params[0].substr(0, params[0].length() - 1), value);
entry.set_importance(value / 100.0);
} else if (params.size() == 1) {
// One numeric parameter: the number of triangles.
int value = 0;
okflag = string_to_int(params[0], value);
entry.set_num_tris(value);
} else if (params.size() >= 2) {
// Two or more numeric parameters: the number of u by v quads,
// followed by an optional list of specific isoparams.
int u = 0, v = 0;
okflag = string_to_int(params[0], u) && string_to_int(params[1], v);
entry.set_uv(u, v, &params[2], params.size() - 2);
} else {
okflag = false;
}
if (!okflag) {
qtess_cat.error()
<< _filename << ": invalid parameters at line "
<< line_number << ".\n";
return false;
}
}
_entries.push_back(entry);
}
}
}
if (qtess_cat.is_info()) {
qtess_cat.info()
<< "read qtess parameter file " << _filename << ".\n";
if (qtess_cat.is_debug()) {
write(qtess_cat.debug(false));
}
}
add_default_entry();
return true;
}
////////////////////////////////////////////////////////////////////
// Function: QtessInputFile::get_default_entry
// Access: Public
// Description: Returns a reference to the last entry on the list,
// which is the "default" entry that will match any
// surface that does not get explicitly named in the
// input file.
////////////////////////////////////////////////////////////////////
QtessInputEntry &QtessInputFile::
get_default_entry() {
if (_entries.empty()) {
// No entries; create one.
add_default_entry();
}
return _entries.back();
}
////////////////////////////////////////////////////////////////////
// Function: QtessInputFile::match
// Access: Public
// Description: Attempts to find a match for the given surface in the
// user input entries. Searches in the order in which
// the entries were defined, and chooses the first
// match.
//
// When a match is found, the surface is added to the
// entry's set of matched surfaces. Returns the type of
// the matching node if a match is found, or T_undefined
// otherwise.
////////////////////////////////////////////////////////////////////
QtessInputEntry::Type QtessInputFile::
match(QtessSurface *surface) {
QtessInputEntry::Type type;
if (_entries.empty()) {
// No entries; create one.
add_default_entry();
}
Entries::iterator ei;
for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
type = (*ei).match(surface);
if (type != QtessInputEntry::T_undefined) {
return type;
}
}
return QtessInputEntry::T_undefined;
}
////////////////////////////////////////////////////////////////////
// Function: QtessInputFile::count_tris
// Access: Public
// Description: Determines the tesselation u,v amounts of each
// attached surface, and stores this information in the
// surface pointer. Returns the total number of tris
// that will be produced.
////////////////////////////////////////////////////////////////////
int QtessInputFile::
count_tris() {
int total_tris = 0;
Entries::iterator ei;
for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
total_tris += (*ei).count_tris();
}
return total_tris;
}
////////////////////////////////////////////////////////////////////
// Function: QtessInputFile::write
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void QtessInputFile::
write(ostream &out, int indent_level) const {
Entries::const_iterator ei;
for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
(*ei).write(out, indent_level);
}
}
////////////////////////////////////////////////////////////////////
// Function: QtessInputFile::add_default_entry
// Access: Private
// Description: Adds one more entry to the end of the list, to catch
// all of the surfaces that didn't get explicitly named.
////////////////////////////////////////////////////////////////////
void QtessInputFile::
add_default_entry() {
QtessInputEntry entry("*");
entry.set_omit();
_entries.push_back(entry);
}