This commit is contained in:
David Rose 2012-02-26 00:43:21 +00:00
parent ce0ad5dde8
commit 7db604c791
5 changed files with 467 additions and 2 deletions

View File

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

View File

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

View File

@ -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;
}

View File

@ -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

View File

@ -34,7 +34,7 @@ ObjToEgg() :
set_program_description set_program_description
("This program converts obj files to egg. It " ("This program converts obj files to egg. It "
"only converts polygon data, with no fancy tricks. " "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 redescribe_option
("cs", ("cs",