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