350 lines
11 KiB
C++
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, ¶ms[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);
|
|
}
|