Browse Source

bare-bones obj2egg in C++

David Rose 15 years ago
parent
commit
70d9503dd0

+ 23 - 0
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

+ 41 - 0
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;
+}
+

+ 25 - 0
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

+ 417 - 0
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 &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;
+}

+ 60 - 0
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 &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

+ 21 - 0
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

+ 81 - 0
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;
+}

+ 35 - 0
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

+ 1 - 0
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 \

+ 4 - 0
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));