David Rose hace 14 años
padre
commit
7db604c791

+ 1 - 1
pandatool/src/objegg/objToEggConverter.cxx

@@ -354,7 +354,7 @@ process_g(vector_string &words) {
 
   // Thus, iterate from the back to the front.
   size_t i = words.size();
-  while (i != 0) {
+  while (i > 1) {
     --i;
     EggNode *child = group->find_child(words[i]);
     if (child == NULL || !child->is_of_type(EggGroup::get_class_type())) {

+ 9 - 0
pandatool/src/objprogs/Sources.pp

@@ -19,3 +19,12 @@
     objToEgg.cxx objToEgg.h
 
 #end bin_target
+
+#begin bin_target
+  #define TARGET egg2obj
+  #define LOCAL_LIBS p3eggbase p3progbase
+
+  #define SOURCES \
+    eggToObj.cxx eggToObj.h
+
+#end bin_target

+ 385 - 0
pandatool/src/objprogs/eggToObj.cxx

@@ -0,0 +1,385 @@
+// Filename: eggToObj.cxx
+// Created by:  drose (28Feb12)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "eggToObj.h"
+#include "pystub.h"
+#include "eggPolygon.h"
+#include "eggGroupNode.h"
+#include "dcast.h"
+#include "string_utils.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggToObj::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+EggToObj::
+EggToObj() :
+  EggToSomething("Obj", ".obj", true, false)
+{
+  set_program_description
+    ("This program converts egg files to obj.  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 resulting " + _format_name +
+     " file.  Normally, this is z-up.");
+
+  _coordinate_system = CS_zup_right;
+  _got_coordinate_system = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggToObj::run
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+void EggToObj::
+run() {
+  _data->flatten_transforms();
+  collect_vertices(_data);
+
+  ostream &out = get_output();
+  _current_group = NULL;
+
+  out << "\n#\n"
+      << "# obj file generated by the following command:\n"
+      << "# " << get_exec_command() << "\n"
+      << "#\n\n";
+
+  write_vertices(out, "v", 3, _unique_vert3);
+  write_vertices(out, "v", 4, _unique_vert4);
+  write_vertices(out, "vt", 2, _unique_uv2);
+  write_vertices(out, "vt", 3, _unique_uv3);
+  write_vertices(out, "vn", 3, _unique_norm);
+
+  write_faces(out, _data);
+
+  if (!out) {
+    nout << "An error occurred while writing.\n";
+    exit(1);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggToObj::handle_args
+//       Access: Protected, Virtual
+//  Description: Does something with the additional arguments on the
+//               command line (after all the -options have been
+//               parsed).  Returns true if the arguments are good,
+//               false otherwise.
+////////////////////////////////////////////////////////////////////
+bool EggToObj::
+handle_args(ProgramBase::Args &args) {
+  return EggToSomething::handle_args(args);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggToObj::collect_vertices
+//       Access: Private
+//  Description: Recursively walks the egg structure, looking for
+//               vertices referenced by polygons.  Any such vertices
+//               are added to the vertex tables for writing to the obj
+//               file.
+////////////////////////////////////////////////////////////////////
+void EggToObj::
+collect_vertices(EggNode *egg_node) {
+  if (egg_node->is_of_type(EggPolygon::get_class_type())) {
+    EggPolygon *egg_poly = DCAST(EggPolygon, egg_node);
+    EggPolygon::iterator pi;
+    for (pi = egg_poly->begin(); pi != egg_poly->end(); ++pi) {
+      record_vertex(*pi);
+    }
+
+  } else if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
+    EggGroupNode *egg_group = DCAST(EggGroupNode, egg_node);
+
+    EggGroupNode::iterator ci;
+    for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
+      collect_vertices(*ci);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggToObj::write_faces
+//       Access: Private
+//  Description: Recursively walks the egg structure again, this time
+//               writing out the face records for any polygons
+//               encountered.
+////////////////////////////////////////////////////////////////////
+void EggToObj::
+write_faces(ostream &out, EggNode *egg_node) {
+  if (egg_node->is_of_type(EggPolygon::get_class_type())) {
+    write_group_reference(out, egg_node);
+
+    EggPolygon *egg_poly = DCAST(EggPolygon, egg_node);
+
+    out << "f";
+    EggPolygon::iterator pi;
+    for (pi = egg_poly->begin(); pi != egg_poly->end(); ++pi) {
+      VertexDef &vdef = _vmap[(*pi)];
+      int vert_index = -1;
+      int uv_index = -1;
+      int norm_index = -1;
+
+      if (vdef._vert3_index != -1) {
+        vert_index = vdef._vert3_index + 1;
+      } else if (vdef._vert4_index != -1) {
+        vert_index = vdef._vert4_index + 1 + (int)_unique_vert3.size();
+      }
+
+      if (vdef._uv2_index != -1) {
+        uv_index = vdef._uv2_index + 1;
+      } else if (vdef._uv3_index != -1) {
+        uv_index = vdef._uv3_index + 1 + (int)_unique_uv2.size();
+      }
+
+      if (vdef._norm_index != -1) {
+        norm_index = vdef._norm_index + 1;
+      }
+
+      if (vert_index == -1) {
+        continue;
+      }
+
+      if (norm_index != -1) {
+        if (uv_index != -1) {
+          out << " " << vert_index << "/" << uv_index << "/" << norm_index;
+        } else {
+          out << " " << vert_index << "//" << norm_index;
+        }
+      } else if (uv_index != -1) {
+        out << " " << vert_index << "/" << uv_index;
+      } else {
+        out << " " << vert_index;
+      }
+    }
+    out << "\n";
+
+  } else if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
+    EggGroupNode *egg_group = DCAST(EggGroupNode, egg_node);
+
+    EggGroupNode::iterator ci;
+    for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
+      write_faces(out, *ci);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggToObj::write_group_reference
+//       Access: Private
+//  Description: Writes the "g" tag to describe this polygon's group,
+//               if needed.
+////////////////////////////////////////////////////////////////////
+void EggToObj::
+write_group_reference(ostream &out, EggNode *egg_node) {
+  EggGroupNode *egg_group = egg_node->get_parent();
+  if (egg_group == _current_group) {
+    // Same group we wrote last time.
+    return;
+  }
+
+  string group_name;
+  get_group_name(group_name, egg_group);
+  if (group_name.empty()) {
+    out << "g default\n";
+  } else {
+    out << "g" << group_name << "\n";
+  }
+  _current_group = egg_group;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggToObj::get_group_name
+//       Access: Private
+//  Description: Recursively determines the appropriate string to
+//               write for the "g" tag to describe a particular
+//               EggGroupNode.
+////////////////////////////////////////////////////////////////////
+void EggToObj::
+get_group_name(string &group_name, EggGroupNode *egg_group) {
+  string name = trim(egg_group->get_name());
+  if (!name.empty()) {
+    group_name += ' ';
+
+    // Remove nonstandard characters.
+    for (string::const_iterator ni = name.begin(); ni != name.end(); ++ni) {
+      char c = (*ni);
+      if (!isalnum(c)) {
+        c = '_';
+      }
+      group_name += c;
+    }
+  }
+
+  // Now recurse.
+  EggGroupNode *egg_parent = egg_group->get_parent();
+  if (egg_parent != NULL) {
+    get_group_name(group_name, egg_parent);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggToObj::record_vertex
+//       Access: Private
+//  Description: Adds the indicated EggVertex to the unique vertex
+//               tables, for writing later by write_vertices().
+////////////////////////////////////////////////////////////////////
+void EggToObj::
+record_vertex(EggVertex *vertex) {
+  VertexDef &vdef = _vmap[vertex];
+
+  switch (vertex->get_num_dimensions()) {
+  case 1:
+    vdef._vert3_index = record_unique(_unique_vert3, vertex->get_pos1());
+    break;
+  case 2:
+    vdef._vert3_index = record_unique(_unique_vert3, vertex->get_pos2());
+    break;
+  case 3:
+    vdef._vert3_index = record_unique(_unique_vert3, vertex->get_pos3());
+    break;
+  case 4:
+    vdef._vert4_index = record_unique(_unique_vert4, vertex->get_pos4());
+    break;
+  }
+
+  if (vertex->has_uv("")) {
+    vdef._uv2_index = record_unique(_unique_uv2, vertex->get_uv(""));
+  } else if (vertex->has_uvw("")) {
+    vdef._uv3_index = record_unique(_unique_uv3, vertex->get_uvw(""));
+  }
+
+  if (vertex->has_normal()) {
+    vdef._norm_index = record_unique(_unique_norm, vertex->get_normal());
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggToObj::record_unique
+//       Access: Private
+//  Description: Records the indicated vertex value, returning the
+//               shared index if this value already appears elsewhere
+//               in the table, or the new unique index if this is the
+//               first time this value appears.
+////////////////////////////////////////////////////////////////////
+int EggToObj::
+record_unique(UniqueVertices &unique, const LVecBase4d &vec) {
+  // We record a zero-based index.  Note that we will actually write
+  // out a one-based index to the obj file, as required by the
+  // standard.
+  int index = unique.size();
+  UniqueVertices::iterator ui = unique.insert(UniqueVertices::value_type(vec, index)).first;
+  return (*ui).second;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggToObj::record_unique
+//       Access: Private
+//  Description: Records the indicated vertex value, returning the
+//               shared index if this value already appears elsewhere
+//               in the table, or the new unique index if this is the
+//               first time this value appears.
+////////////////////////////////////////////////////////////////////
+int EggToObj::
+record_unique(UniqueVertices &unique, const LVecBase3d &vec) {
+  return record_unique(unique, LVecBase4d(vec[0], vec[1], vec[2], 0.0));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggToObj::record_unique
+//       Access: Private
+//  Description: Records the indicated vertex value, returning the
+//               shared index if this value already appears elsewhere
+//               in the table, or the new unique index if this is the
+//               first time this value appears.
+////////////////////////////////////////////////////////////////////
+int EggToObj::
+record_unique(UniqueVertices &unique, const LVecBase2d &vec) {
+  return record_unique(unique, LVecBase4d(vec[0], vec[1], 0.0, 0.0));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggToObj::record_unique
+//       Access: Private
+//  Description: Records the indicated vertex value, returning the
+//               shared index if this value already appears elsewhere
+//               in the table, or the new unique index if this is the
+//               first time this value appears.
+////////////////////////////////////////////////////////////////////
+int EggToObj::
+record_unique(UniqueVertices &unique, double pos) {
+  return record_unique(unique, LVecBase4d(pos, 0.0, 0.0, 0.0));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggToObj::write_vertices
+//       Access: Private
+//  Description: Actually writes the vertex values recorded in the
+//               indicated table to the obj output stream.
+////////////////////////////////////////////////////////////////////
+void EggToObj::
+write_vertices(ostream &out, const string &prefix, int num_components, 
+               const UniqueVertices &unique) {
+  // First, sort the list into numeric order.
+  int num_vertices = (int)unique.size();
+  const LVecBase4d **vertices = (const LVecBase4d **)alloca(num_vertices * sizeof(LVecBase4d *));
+  memset(vertices, 0, num_vertices * sizeof(LVecBase4d *));
+  UniqueVertices::const_iterator ui;
+  for (ui = unique.begin(); ui != unique.end(); ++ui) {
+    int index = (*ui).second;
+    const LVecBase4d &vec = (*ui).first;
+    nassertv(index >= 0 && index < num_vertices);
+    nassertv(vertices[index] == NULL);
+    vertices[index] = &vec;
+  }
+
+  for (int i = 0; i < num_vertices; ++i) {
+    out << prefix;
+    const LVecBase4d &vec = *(vertices[i]);
+    for (int ci = 0; ci < num_components; ++ci) {
+      out << " " << vec[ci];
+    }
+    out << "\n";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggToObj::VertexDef::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+EggToObj::VertexDef::
+VertexDef() :
+  _vert3_index(-1),
+  _vert4_index(-1),
+  _uv2_index(-1),
+  _uv3_index(-1),
+  _norm_index(-1)
+{
+}
+
+int main(int argc, char *argv[]) {
+  // A call to pystub() to force libpystub.so to be linked in.
+  pystub();
+
+  EggToObj prog;
+  prog.parse_command_line(argc, argv);
+  prog.run();
+  return 0;
+}

+ 71 - 0
pandatool/src/objprogs/eggToObj.h

@@ -0,0 +1,71 @@
+// Filename: eggToObj.h
+// Created by:  drose (25Feb12)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 EGGTOOBJ_H
+#define EGGTOOBJ_H
+
+#include "pandatoolbase.h"
+#include "eggToSomething.h"
+#include "pmap.h"
+
+class EggNode;
+class EggVertex;
+
+////////////////////////////////////////////////////////////////////
+//       Class : EggToObj
+// Description :
+////////////////////////////////////////////////////////////////////
+class EggToObj : public EggToSomething {
+public:
+  EggToObj();
+
+  void run();
+
+protected:
+  virtual bool handle_args(Args &args);
+
+private:
+  typedef pmap<LVecBase4d, int> UniqueVertices;
+  class VertexDef {
+  public:
+    VertexDef();
+    int _vert3_index;
+    int _vert4_index;
+    int _uv2_index;
+    int _uv3_index;
+    int _norm_index;
+  };
+  typedef pmap<EggVertex *, VertexDef> VertexMap;
+
+  void collect_vertices(EggNode *egg_node);
+  void write_faces(ostream &out, EggNode *egg_node);
+  void write_group_reference(ostream &out, EggNode *egg_node);
+  void get_group_name(string &group_name, EggGroupNode *egg_group);
+
+  void record_vertex(EggVertex *vertex);
+  int record_unique(UniqueVertices &unique, const LVecBase4d &vec);
+  int record_unique(UniqueVertices &unique, const LVecBase3d &vec);
+  int record_unique(UniqueVertices &unique, const LVecBase2d &vec);
+  int record_unique(UniqueVertices &unique, double pos);
+
+  void write_vertices(ostream &out, const string &prefix, int num_components, 
+                      const UniqueVertices &unique);
+
+private:
+  UniqueVertices _unique_vert3, _unique_vert4, _unique_uv2, _unique_uv3, _unique_norm;
+  VertexMap _vmap;
+  EggGroupNode *_current_group;
+};
+
+#endif

+ 1 - 1
pandatool/src/objprogs/objToEgg.cxx

@@ -34,7 +34,7 @@ ObjToEgg() :
   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.");
+     "Very bare-bones at the moment; not even texture maps are supported.");
 
   redescribe_option
     ("cs",