From 70d9503dd08a8d76e7f2c78f9fd2594c80b43369 Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 7 Dec 2010 22:22:11 +0000 Subject: [PATCH] bare-bones obj2egg in C++ --- pandatool/src/objegg/Sources.pp | 23 ++ pandatool/src/objegg/config_objegg.cxx | 41 ++ pandatool/src/objegg/config_objegg.h | 25 ++ pandatool/src/objegg/objToEggConverter.cxx | 417 +++++++++++++++++++++ pandatool/src/objegg/objToEggConverter.h | 60 +++ pandatool/src/objprogs/Sources.pp | 21 ++ pandatool/src/objprogs/objToEgg.cxx | 81 ++++ pandatool/src/objprogs/objToEgg.h | 35 ++ pandatool/src/ptloader/Sources.pp | 1 + pandatool/src/ptloader/config_ptloader.cxx | 4 + 10 files changed, 708 insertions(+) create mode 100755 pandatool/src/objegg/Sources.pp create mode 100755 pandatool/src/objegg/config_objegg.cxx create mode 100755 pandatool/src/objegg/config_objegg.h create mode 100755 pandatool/src/objegg/objToEggConverter.cxx create mode 100755 pandatool/src/objegg/objToEggConverter.h create mode 100755 pandatool/src/objprogs/Sources.pp create mode 100755 pandatool/src/objprogs/objToEgg.cxx create mode 100755 pandatool/src/objprogs/objToEgg.h diff --git a/pandatool/src/objegg/Sources.pp b/pandatool/src/objegg/Sources.pp new file mode 100755 index 0000000000..22dc687d3c --- /dev/null +++ b/pandatool/src/objegg/Sources.pp @@ -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 diff --git a/pandatool/src/objegg/config_objegg.cxx b/pandatool/src/objegg/config_objegg.cxx new file mode 100755 index 0000000000..1d5647f0df --- /dev/null +++ b/pandatool/src/objegg/config_objegg.cxx @@ -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; +} + diff --git a/pandatool/src/objegg/config_objegg.h b/pandatool/src/objegg/config_objegg.h new file mode 100755 index 0000000000..af1e74a326 --- /dev/null +++ b/pandatool/src/objegg/config_objegg.h @@ -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 diff --git a/pandatool/src/objegg/objToEggConverter.cxx b/pandatool/src/objegg/objToEggConverter.cxx new file mode 100755 index 0000000000..6249b34eb1 --- /dev/null +++ b/pandatool/src/objegg/objToEggConverter.cxx @@ -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 ©) : + 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 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; +} diff --git a/pandatool/src/objegg/objToEggConverter.h b/pandatool/src/objegg/objToEggConverter.h new file mode 100755 index 0000000000..15c9657e71 --- /dev/null +++ b/pandatool/src/objegg/objToEggConverter.h @@ -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 ©); + ~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 _ignored_tags; +}; + +#endif diff --git a/pandatool/src/objprogs/Sources.pp b/pandatool/src/objprogs/Sources.pp new file mode 100755 index 0000000000..f83175d0a8 --- /dev/null +++ b/pandatool/src/objprogs/Sources.pp @@ -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 diff --git a/pandatool/src/objprogs/objToEgg.cxx b/pandatool/src/objprogs/objToEgg.cxx new file mode 100755 index 0000000000..52f51f49af --- /dev/null +++ b/pandatool/src/objprogs/objToEgg.cxx @@ -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; +} diff --git a/pandatool/src/objprogs/objToEgg.h b/pandatool/src/objprogs/objToEgg.h new file mode 100755 index 0000000000..98786d25f0 --- /dev/null +++ b/pandatool/src/objprogs/objToEgg.h @@ -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 diff --git a/pandatool/src/ptloader/Sources.pp b/pandatool/src/ptloader/Sources.pp index ad94a79d1a..8dadf6713e 100644 --- a/pandatool/src/ptloader/Sources.pp +++ b/pandatool/src/ptloader/Sources.pp @@ -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 \ diff --git a/pandatool/src/ptloader/config_ptloader.cxx b/pandatool/src/ptloader/config_ptloader.cxx index 9f8bbf2336..9caf855ef7 100644 --- a/pandatool/src/ptloader/config_ptloader.cxx +++ b/pandatool/src/ptloader/config_ptloader.cxx @@ -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));