bare-bones obj2egg in C++

This commit is contained in:
David Rose 2010-12-07 22:22:11 +00:00
parent dd652284a4
commit 70d9503dd0
10 changed files with 708 additions and 0 deletions

23
pandatool/src/objegg/Sources.pp Executable file
View File

@ -0,0 +1,23 @@
#begin ss_lib_target
#define TARGET objegg
#define LOCAL_LIBS converter pandatoolbase
#define OTHER_LIBS \
egg:c pandaegg:m \
pipeline:c event:c pstatclient:c panda:m \
pandabase:c pnmimage:c mathutil:c linmath:c putil:c express:c \
interrogatedb:c prc:c dconfig:c dtoolconfig:m \
dtoolutil:c dtoolbase:c dtool:m \
$[if $[WANT_NATIVE_NET],nativenet:c] \
$[if $[and $[HAVE_NET],$[WANT_NATIVE_NET]],net:c downloader:c]
#define UNIX_SYS_LIBS \
m
#define SOURCES \
config_objegg.cxx config_objegg.h \
objToEggConverter.cxx objToEggConverter.h
#define INSTALL_HEADERS \
objToEggConverter.h
#end ss_lib_target

View File

@ -0,0 +1,41 @@
// Filename: config_objegg.cxx
// Created by: drose (07Dec10)
//
////////////////////////////////////////////////////////////////////
//
// 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."
//
////////////////////////////////////////////////////////////////////
#include "config_objegg.h"
#include "dconfig.h"
Configure(config_objegg);
NotifyCategoryDef(objegg, "");
ConfigureFn(config_objegg) {
init_libobjegg();
}
////////////////////////////////////////////////////////////////////
// Function: init_libobjegg
// Description: Initializes the library. This must be called at
// least once before any of the functions or classes in
// this library can be used. Normally it will be
// called by the static initializers and need not be
// called explicitly, but special cases exist.
////////////////////////////////////////////////////////////////////
void
init_libobjegg() {
static bool initialized = false;
if (initialized) {
return;
}
initialized = true;
}

View File

@ -0,0 +1,25 @@
// Filename: config_objegg.h
// Created by: drose (07Dec10)
//
////////////////////////////////////////////////////////////////////
//
// 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."
//
////////////////////////////////////////////////////////////////////
#ifndef CONFIG_OBJEGG_H
#define CONFIG_OBJEGG_H
#include "pandatoolbase.h"
#include "notifyCategoryProxy.h"
NotifyCategoryDeclNoExport(objegg);
extern void init_libobjegg();
#endif

View File

@ -0,0 +1,417 @@
// Filename: objToEggConverter.cxx
// Created by: drose (07Dec10)
//
////////////////////////////////////////////////////////////////////
//
// 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."
//
////////////////////////////////////////////////////////////////////
#include "objToEggConverter.h"
#include "config_objegg.h"
#include "eggData.h"
#include "string_utils.h"
#include "streamReader.h"
#include "virtualFileSystem.h"
#include "eggPolygon.h"
////////////////////////////////////////////////////////////////////
// Function: ObjToEggConverter::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
ObjToEggConverter::
ObjToEggConverter() {
}
////////////////////////////////////////////////////////////////////
// Function: ObjToEggConverter::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
ObjToEggConverter::
ObjToEggConverter(const ObjToEggConverter &copy) :
SomethingToEggConverter(copy)
{
}
////////////////////////////////////////////////////////////////////
// Function: ObjToEggConverter::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
ObjToEggConverter::
~ObjToEggConverter() {
}
////////////////////////////////////////////////////////////////////
// Function: ObjToEggConverter::make_copy
// Access: Public, Virtual
// Description: Allocates and returns a new copy of the converter.
////////////////////////////////////////////////////////////////////
SomethingToEggConverter *ObjToEggConverter::
make_copy() {
return new ObjToEggConverter(*this);
}
////////////////////////////////////////////////////////////////////
// Function: ObjToEggConverter::get_name
// Access: Public, Virtual
// Description: Returns the English name of the file type this
// converter supports.
////////////////////////////////////////////////////////////////////
string ObjToEggConverter::
get_name() const {
return "obj";
}
////////////////////////////////////////////////////////////////////
// Function: ObjToEggConverter::get_extension
// Access: Public, Virtual
// Description: Returns the common extension of the file type this
// converter supports.
////////////////////////////////////////////////////////////////////
string ObjToEggConverter::
get_extension() const {
return "obj";
}
////////////////////////////////////////////////////////////////////
// Function: ObjToEggConverter::supports_compressed
// Access: Published, Virtual
// Description: Returns true if this file type can transparently load
// compressed files (with a .pz extension), false
// otherwise.
////////////////////////////////////////////////////////////////////
bool ObjToEggConverter::
supports_compressed() const {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: ObjToEggConverter::convert_file
// Access: Public, Virtual
// Description: Handles the reading of the input file and converting
// it to egg. Returns true if successful, false
// otherwise.
////////////////////////////////////////////////////////////////////
bool ObjToEggConverter::
convert_file(const Filename &filename) {
clear_error();
if (_egg_data->get_coordinate_system() == CS_default) {
_egg_data->set_coordinate_system(CS_zup_right);
}
if (!process(filename)) {
_error = true;
}
return !had_error();
}
////////////////////////////////////////////////////////////////////
// Function: ObjToEggConverter::process
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
bool ObjToEggConverter::
process(const Filename &filename) {
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
istream *strm = vfs->open_read_file(filename, true);
if (strm == NULL) {
objegg_cat.error()
<< "Couldn't read " << filename << "\n";
return false;
}
_vi = 0;
_vti = 0;
_vni = 0;
_vpool = new EggVertexPool("vpool");
_egg_data->add_child(_vpool);
StreamReader sr(strm, true);
string line = sr.readline();
_line_number = 1;
while (!line.empty()) {
line = trim(line);
if (line.empty()) {
continue;
}
if (line[0] == '#') {
continue;
}
if (!process_line(line)) {
return false;
}
line = sr.readline();
++_line_number;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: ObjToEggConverter::process_line
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
bool ObjToEggConverter::
process_line(const string &line) {
vector_string words;
tokenize(line, words, " \t", true);
nassertr(!words.empty(), false);
string tag = words[0];
if (tag == "v") {
return process_v(words);
} else if (tag == "vt") {
return process_vt(words);
} else if (tag == "vn") {
return process_vn(words);
} else if (tag == "f") {
return process_f(words);
} else {
bool inserted = _ignored_tags.insert(tag).second;
if (!inserted) {
objegg_cat.info()
<< "Ignoring tag " << tag << "\n";
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: ObjToEggConverter::process_v
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
bool ObjToEggConverter::
process_v(vector_string &words) {
if (words.size() != 4) {
objegg_cat.error()
<< "Wrong number of tokens at line " << _line_number << "\n";
return false;
}
bool okflag = true;
LPoint3d pos;
okflag &= string_to_double(words[1], pos[0]);
okflag &= string_to_double(words[2], pos[1]);
okflag &= string_to_double(words[3], pos[2]);
if (!okflag) {
objegg_cat.error()
<< "Invalid number at line " << _line_number << "\n";
return false;
}
EggVertex *vertex = get_vertex(_vi);
vertex->set_pos(pos);
++_vi;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: ObjToEggConverter::process_vt
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
bool ObjToEggConverter::
process_vt(vector_string &words) {
if (words.size() != 3 && words.size() != 4) {
objegg_cat.error()
<< "Wrong number of tokens at line " << _line_number << "\n";
return false;
}
bool okflag = true;
TexCoord3d uvw;
okflag &= string_to_double(words[1], uvw[0]);
okflag &= string_to_double(words[2], uvw[1]);
if (words.size() == 4) {
okflag &= string_to_double(words[3], uvw[2]);
}
if (!okflag) {
objegg_cat.error()
<< "Invalid number at line " << _line_number << "\n";
return false;
}
EggVertex *vertex = get_vertex(_vi);
if (words.size() == 4) {
vertex->set_uvw("", uvw);
} else {
vertex->set_uv("", TexCoordd(uvw[0], uvw[1]));
}
++_vi;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: ObjToEggConverter::process_vn
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
bool ObjToEggConverter::
process_vn(vector_string &words) {
if (words.size() != 4) {
objegg_cat.error()
<< "Wrong number of tokens at line " << _line_number << "\n";
return false;
}
bool okflag = true;
LVector3d normal;
okflag &= string_to_double(words[1], normal[0]);
okflag &= string_to_double(words[2], normal[1]);
okflag &= string_to_double(words[3], normal[2]);
if (!okflag) {
objegg_cat.error()
<< "Invalid number at line " << _line_number << "\n";
return false;
}
normal.normalize();
EggVertex *vertex = get_vertex(_vi);
vertex->set_normal(normal);
++_vi;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: ObjToEggConverter::process_f
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
bool ObjToEggConverter::
process_f(vector_string &words) {
PT(EggPolygon) poly = new EggPolygon;
for (size_t i = 1; i < words.size(); ++i) {
EggVertex *vertex = get_face_vertex(words[i]);
if (vertex == NULL) {
return false;
}
poly->add_vertex(vertex);
}
_egg_data->add_child(poly);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: ObjToEggConverter::get_vertex
// Access: Protected
// Description: Returns or creates a vertex in the vpool with the
// given index.
////////////////////////////////////////////////////////////////////
EggVertex *ObjToEggConverter::
get_vertex(int n) {
EggVertex *vertex = _vpool->get_vertex(n);
if (vertex == NULL) {
vertex = new EggVertex;
_vpool->add_vertex(vertex, n);
}
return vertex;
}
////////////////////////////////////////////////////////////////////
// Function: ObjToEggConverter::get_face_vertex
// Access: Protected
// Description: Returns or creates a vertex in the vpool according to
// the indicated face reference.
////////////////////////////////////////////////////////////////////
EggVertex *ObjToEggConverter::
get_face_vertex(const string &reference) {
vector_string words;
tokenize(reference, words, "/", false);
nassertr(!words.empty(), NULL);
vector<EggVertex *> vertices;
vertices.reserve(words.size());
for (size_t i = 0; i < words.size(); ++i) {
if (trim(words[i]).empty()) {
if (i == 0) {
objegg_cat.error()
<< "Invalid null vertex at line " << _line_number << "\n";
return NULL;
} else {
vertices.push_back(vertices[0]);
continue;
}
}
int index;
if (!string_to_int(words[i], index)) {
objegg_cat.error()
<< "Invalid integer " << words[i] << " at line " << _line_number << "\n";
return NULL;
}
EggVertex *vertex = get_vertex(index);
if (vertex == NULL){
objegg_cat.error()
<< "Invalid vertex " << index << " at line " << _line_number << "\n";
return NULL;
}
vertices.push_back(vertex);
}
nassertr(!vertices.empty(), NULL);
nassertr(vertices.size() == words.size(), NULL);
if (vertices.size() == 1) {
// Just a pos reference.
return vertices[0];
} else if (vertices.size() == 2) {
// Pos + uv.
if (vertices[0] == vertices[1]) {
return vertices[0];
}
// Synthesize a vertex.
EggVertex synth(*vertices[0]);
if (vertices[1]->has_uv("")) {
synth.set_uv("", vertices[1]->get_uv(""));
} else if (vertices[1]->has_uvw("")) {
synth.set_uvw("", vertices[1]->get_uvw(""));
}
return _vpool->create_unique_vertex(synth);
} else if (vertices.size() >= 3) {
// pos + uv + normal.
if (vertices[0] == vertices[1] && vertices[0] == vertices[2]) {
return vertices[0];
}
// Synthesize a vertex.
EggVertex synth(*vertices[0]);
if (vertices[1]->has_uv("")) {
synth.set_uv("", vertices[1]->get_uv(""));
} else if (vertices[1]->has_uvw("")) {
synth.set_uvw("", vertices[1]->get_uvw(""));
}
if (vertices[2]->has_normal()) {
synth.set_normal(vertices[2]->get_normal());
}
return _vpool->create_unique_vertex(synth);
}
return NULL;
}

View File

@ -0,0 +1,60 @@
// Filename: ObjToEggConverter.h
// Created by: drose (07Dec10)
//
////////////////////////////////////////////////////////////////////
//
// 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."
//
////////////////////////////////////////////////////////////////////
#ifndef ObjTOEGGCONVERTER_H
#define ObjTOEGGCONVERTER_H
#include "pandatoolbase.h"
#include "somethingToEggConverter.h"
#include "eggVertexPool.h"
////////////////////////////////////////////////////////////////////
// Class : ObjToEggConverter
// Description : Convert an Obj file to egg data.
////////////////////////////////////////////////////////////////////
class ObjToEggConverter : public SomethingToEggConverter {
public:
ObjToEggConverter();
ObjToEggConverter(const ObjToEggConverter &copy);
~ObjToEggConverter();
virtual SomethingToEggConverter *make_copy();
virtual string get_name() const;
virtual string get_extension() const;
virtual bool supports_compressed() const;
virtual bool convert_file(const Filename &filename);
protected:
bool process(const Filename &filename);
bool process_line(const string &line);
bool process_v(vector_string &words);
bool process_vt(vector_string &words);
bool process_vn(vector_string &words);
bool process_f(vector_string &words);
EggVertex *get_vertex(int n);
EggVertex *get_face_vertex(const string &face_reference);
int _line_number;
int _vi, _vti, _vni;
PT(EggVertexPool) _vpool;
pset<string> _ignored_tags;
};
#endif

View File

@ -0,0 +1,21 @@
#define UNIX_SYS_LIBS m
#define OTHER_LIBS \
egg:c pandaegg:m \
pipeline:c event:c pstatclient:c panda:m \
pandabase:c pnmimage:c mathutil:c linmath:c putil:c express:c \
pandaexpress:m \
interrogatedb:c prc:c dconfig:c dtoolconfig:m \
dtoolutil:c dtoolbase:c dtool:m \
$[if $[WANT_NATIVE_NET],nativenet:c] \
$[if $[and $[HAVE_NET],$[WANT_NATIVE_NET]],net:c downloader:c] \
pystub
#begin bin_target
#define TARGET obj2egg
#define LOCAL_LIBS objegg eggbase progbase
#define SOURCES \
objToEgg.cxx objToEgg.h
#end bin_target

View File

@ -0,0 +1,81 @@
// Filename: objToEgg.cxx
// Created by: drose (04May04)
//
////////////////////////////////////////////////////////////////////
//
// 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."
//
////////////////////////////////////////////////////////////////////
#include "objToEgg.h"
#include "objToEggConverter.h"
#include "pystub.h"
////////////////////////////////////////////////////////////////////
// Function: ObjToEgg::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
ObjToEgg::
ObjToEgg() :
SomethingToEgg("obj", ".obj")
{
add_units_options();
add_normals_options();
add_transform_options();
set_program_description
("This program converts obj files to egg. It "
"only converts polygon data, with no fancy tricks. "
"Very bare-bones at the moment, not even texture maps are supported.");
redescribe_option
("cs",
"Specify the coordinate system of the input " + _format_name +
" file. Normally, this is z-up.");
_coordinate_system = CS_zup_right;
}
////////////////////////////////////////////////////////////////////
// Function: ObjToEgg::run
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void ObjToEgg::
run() {
nout << "Reading " << _input_filename << "\n";
_data->set_coordinate_system(_coordinate_system);
ObjToEggConverter converter;
converter.set_egg_data(_data);
converter._allow_errors = _allow_errors;
apply_parameters(converter);
if (!converter.convert_file(_input_filename)) {
nout << "Errors in conversion.\n";
exit(1);
}
write_egg_file();
nout << "\n";
}
int main(int argc, char *argv[]) {
// A call to pystub() to force libpystub.so to be linked in.
pystub();
ObjToEgg prog;
prog.parse_command_line(argc, argv);
prog.run();
return 0;
}

View File

@ -0,0 +1,35 @@
// Filename: objToEgg.h
// Created by: drose (07Dec10)
//
////////////////////////////////////////////////////////////////////
//
// 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."
//
////////////////////////////////////////////////////////////////////
#ifndef OBJTOEGG_H
#define OBJTOEGG_H
#include "pandatoolbase.h"
#include "somethingToEgg.h"
#include "objToEggConverter.h"
////////////////////////////////////////////////////////////////////
// Class : ObjToEgg
// Description : A program to read a Obj file and generate an egg
// file.
////////////////////////////////////////////////////////////////////
class ObjToEgg : public SomethingToEgg {
public:
ObjToEgg();
void run();
};
#endif

View File

@ -5,6 +5,7 @@
#define BUILDING_DLL BUILDING_PTLOADER
#define LOCAL_LIBS \
fltegg flt lwoegg lwo dxfegg dxf vrmlegg pvrml xfileegg xfile \
objegg \
converter pandatoolbase $[if $[HAVE_FCOLLADA],daeegg]
#define OTHER_LIBS \
egg2pg:c egg:c pandaegg:m \

View File

@ -27,6 +27,7 @@
#include "lwoToEggConverter.h"
#include "dxfToEggConverter.h"
#include "vrmlToEggConverter.h"
#include "objToEggConverter.h"
#include "config_xfile.h"
#include "xFileToEggConverter.h"
@ -90,6 +91,9 @@ init_libptloader() {
XFileToEggConverter *xfile = new XFileToEggConverter;
reg->register_type(new LoaderFileTypePandatool(xfile));
ObjToEggConverter *obj = new ObjToEggConverter;
reg->register_type(new LoaderFileTypePandatool(obj));
#ifdef HAVE_FCOLLADA
DAEToEggConverter *dae = new DAEToEggConverter;
reg->register_type(new LoaderFileTypePandatool(dae));