Added a LoadObj function that reads from a std::istream.
+ Added a LoadObj function that reads from a std::istream. This should allow
more generic usage and possibly make testing a little easier.
o This LoadObj accepts a function that returns a
std::unique_ptr<std::istream> for a material.
+ Modified LoadMtl to read from a std::istream to allow more generic
usage.
+ Modified test.cc to check that the changes work as expected and nothing was
broken.
Tests:
+ Compiled test.cc, checked diff of output against pre change output.
Same output where expected.
This commit is contained in:
135
test.cc
135
test.cc
@@ -3,23 +3,15 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cstddef>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
static bool
|
static void PrintInfo(const std::vector<tinyobj::shape_t>& shapes)
|
||||||
TestLoadObj(
|
|
||||||
const char* filename,
|
|
||||||
const char* basepath = NULL)
|
|
||||||
{
|
{
|
||||||
std::cout << "Loading " << filename << std::endl;
|
|
||||||
|
|
||||||
std::vector<tinyobj::shape_t> shapes;
|
|
||||||
std::string err = tinyobj::LoadObj(shapes, filename, basepath);
|
|
||||||
|
|
||||||
if (!err.empty()) {
|
|
||||||
std::cerr << err << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "# of shapes : " << shapes.size() << std::endl;
|
std::cout << "# of shapes : " << shapes.size() << std::endl;
|
||||||
|
|
||||||
for (size_t i = 0; i < shapes.size(); i++) {
|
for (size_t i = 0; i < shapes.size(); i++) {
|
||||||
@@ -53,13 +45,123 @@ TestLoadObj(
|
|||||||
printf(" material.map_Kd = %s\n", shapes[i].material.diffuse_texname.c_str());
|
printf(" material.map_Kd = %s\n", shapes[i].material.diffuse_texname.c_str());
|
||||||
printf(" material.map_Ks = %s\n", shapes[i].material.specular_texname.c_str());
|
printf(" material.map_Ks = %s\n", shapes[i].material.specular_texname.c_str());
|
||||||
printf(" material.map_Ns = %s\n", shapes[i].material.normal_texname.c_str());
|
printf(" material.map_Ns = %s\n", shapes[i].material.normal_texname.c_str());
|
||||||
std::map<std::string, std::string>::iterator it(shapes[i].material.unknown_parameter.begin());
|
auto it = shapes[i].material.unknown_parameter.begin();
|
||||||
std::map<std::string, std::string>::iterator itEnd(shapes[i].material.unknown_parameter.end());
|
auto itEnd = shapes[i].material.unknown_parameter.end();
|
||||||
for (; it != itEnd; it++) {
|
for (; it != itEnd; it++) {
|
||||||
printf(" material.%s = %s\n", it->first.c_str(), it->second.c_str());
|
printf(" material.%s = %s\n", it->first.c_str(), it->second.c_str());
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
TestLoadObj(
|
||||||
|
const char* filename,
|
||||||
|
const char* basepath = NULL)
|
||||||
|
{
|
||||||
|
std::cout << "Loading " << filename << std::endl;
|
||||||
|
|
||||||
|
std::vector<tinyobj::shape_t> shapes;
|
||||||
|
std::string err = tinyobj::LoadObj(shapes, filename, basepath);
|
||||||
|
|
||||||
|
if (!err.empty()) {
|
||||||
|
std::cerr << err << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintInfo(shapes);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
TestStreamLoadObj()
|
||||||
|
{
|
||||||
|
std::cout << "Stream Loading " << std::endl;
|
||||||
|
|
||||||
|
std::stringstream objStream;
|
||||||
|
objStream
|
||||||
|
<< "mtllib cube.mtl\n"
|
||||||
|
"\n"
|
||||||
|
"v 0.000000 2.000000 2.000000\n"
|
||||||
|
"v 0.000000 0.000000 2.000000\n"
|
||||||
|
"v 2.000000 0.000000 2.000000\n"
|
||||||
|
"v 2.000000 2.000000 2.000000\n"
|
||||||
|
"v 0.000000 2.000000 0.000000\n"
|
||||||
|
"v 0.000000 0.000000 0.000000\n"
|
||||||
|
"v 2.000000 0.000000 0.000000\n"
|
||||||
|
"v 2.000000 2.000000 0.000000\n"
|
||||||
|
"# 8 vertices\n"
|
||||||
|
"\n"
|
||||||
|
"g front cube\n"
|
||||||
|
"usemtl white\n"
|
||||||
|
"f 1 2 3 4\n"
|
||||||
|
"g back cube\n"
|
||||||
|
"# expects white material\n"
|
||||||
|
"f 8 7 6 5\n"
|
||||||
|
"g right cube\n"
|
||||||
|
"usemtl red\n"
|
||||||
|
"f 4 3 7 8\n"
|
||||||
|
"g top cube\n"
|
||||||
|
"usemtl white\n"
|
||||||
|
"f 5 1 4 8\n"
|
||||||
|
"g left cube\n"
|
||||||
|
"usemtl green\n"
|
||||||
|
"f 5 6 2 1\n"
|
||||||
|
"g bottom cube\n"
|
||||||
|
"usemtl white\n"
|
||||||
|
"f 2 6 7 3\n"
|
||||||
|
"# 6 elements";
|
||||||
|
|
||||||
|
auto getMatFileIStreamFunc =
|
||||||
|
[](const std::string& matId)
|
||||||
|
{
|
||||||
|
if (matId == "cube.mtl") {
|
||||||
|
|
||||||
|
std::unique_ptr<std::stringstream> matStream(
|
||||||
|
new std::stringstream(
|
||||||
|
"newmtl white\n"
|
||||||
|
"Ka 0 0 0\n"
|
||||||
|
"Kd 1 1 1\n"
|
||||||
|
"Ks 0 0 0\n"
|
||||||
|
"\n"
|
||||||
|
"newmtl red\n"
|
||||||
|
"Ka 0 0 0\n"
|
||||||
|
"Kd 1 0 0\n"
|
||||||
|
"Ks 0 0 0\n"
|
||||||
|
"\n"
|
||||||
|
"newmtl green\n"
|
||||||
|
"Ka 0 0 0\n"
|
||||||
|
"Kd 0 1 0\n"
|
||||||
|
"Ks 0 0 0\n"
|
||||||
|
"\n"
|
||||||
|
"newmtl blue\n"
|
||||||
|
"Ka 0 0 0\n"
|
||||||
|
"Kd 0 0 1\n"
|
||||||
|
"Ks 0 0 0\n"
|
||||||
|
"\n"
|
||||||
|
"newmtl light\n"
|
||||||
|
"Ka 20 20 20\n"
|
||||||
|
"Kd 1 1 1\n"
|
||||||
|
"Ks 0 0 0"));
|
||||||
|
|
||||||
|
return matStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<std::stringstream> emptyUP( nullptr );
|
||||||
|
return emptyUP;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<tinyobj::shape_t> shapes;
|
||||||
|
std::string err = tinyobj::LoadObj(shapes, objStream, getMatFileIStreamFunc);
|
||||||
|
|
||||||
|
if (!err.empty()) {
|
||||||
|
std::cerr << err << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintInfo(shapes);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -79,6 +181,7 @@ main(
|
|||||||
} else {
|
} else {
|
||||||
assert(true == TestLoadObj("cornell_box.obj"));
|
assert(true == TestLoadObj("cornell_box.obj"));
|
||||||
assert(true == TestLoadObj("cube.obj"));
|
assert(true == TestLoadObj("cube.obj"));
|
||||||
|
assert(true == TestStreamLoadObj());
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -290,35 +290,19 @@ exportFaceGroupToShape(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string LoadMtl (
|
std::string LoadMtl (
|
||||||
std::map<std::string, material_t>& material_map,
|
std::map<std::string, material_t>& material_map,
|
||||||
const char* filename,
|
std::istream& inStream)
|
||||||
const char* mtl_basepath)
|
|
||||||
{
|
{
|
||||||
material_map.clear();
|
material_map.clear();
|
||||||
std::stringstream err;
|
std::stringstream err;
|
||||||
|
|
||||||
std::string filepath;
|
|
||||||
|
|
||||||
if (mtl_basepath) {
|
|
||||||
filepath = std::string(mtl_basepath) + std::string(filename);
|
|
||||||
} else {
|
|
||||||
filepath = std::string(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ifstream ifs(filepath.c_str());
|
|
||||||
if (!ifs) {
|
|
||||||
err << "Cannot open file [" << filepath << "]" << std::endl;
|
|
||||||
return err.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
material_t material;
|
material_t material;
|
||||||
|
|
||||||
int maxchars = 8192; // Alloc enough size.
|
int maxchars = 8192; // Alloc enough size.
|
||||||
std::vector<char> buf(maxchars); // Alloc enough size.
|
std::vector<char> buf(maxchars); // Alloc enough size.
|
||||||
while (ifs.peek() != -1) {
|
while (inStream.peek() != -1) {
|
||||||
ifs.getline(&buf[0], maxchars);
|
inStream.getline(&buf[0], maxchars);
|
||||||
|
|
||||||
std::string linebuf(&buf[0]);
|
std::string linebuf(&buf[0]);
|
||||||
|
|
||||||
@@ -511,6 +495,31 @@ LoadObj(
|
|||||||
return err.str();
|
return err.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto getMatFileIStreamFunc =
|
||||||
|
[&](const std::string& matId)
|
||||||
|
{
|
||||||
|
std::string filepath;
|
||||||
|
|
||||||
|
if (mtl_basepath) {
|
||||||
|
filepath = std::string(mtl_basepath) + matId;
|
||||||
|
} else {
|
||||||
|
filepath = matId;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<std::ifstream> ifs( new std::ifstream(filepath.c_str()) );
|
||||||
|
return ifs;
|
||||||
|
};
|
||||||
|
|
||||||
|
return LoadObj(shapes, ifs, getMatFileIStreamFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string LoadObj(
|
||||||
|
std::vector<shape_t>& shapes,
|
||||||
|
std::istream& inStream,
|
||||||
|
GetMtlIStreamFn getMatFn)
|
||||||
|
{
|
||||||
|
std::stringstream err;
|
||||||
|
|
||||||
std::vector<float> v;
|
std::vector<float> v;
|
||||||
std::vector<float> vn;
|
std::vector<float> vn;
|
||||||
std::vector<float> vt;
|
std::vector<float> vt;
|
||||||
@@ -524,8 +533,8 @@ LoadObj(
|
|||||||
|
|
||||||
int maxchars = 8192; // Alloc enough size.
|
int maxchars = 8192; // Alloc enough size.
|
||||||
std::vector<char> buf(maxchars); // Alloc enough size.
|
std::vector<char> buf(maxchars); // Alloc enough size.
|
||||||
while (ifs.peek() != -1) {
|
while (inStream.peek() != -1) {
|
||||||
ifs.getline(&buf[0], maxchars);
|
inStream.getline(&buf[0], maxchars);
|
||||||
|
|
||||||
std::string linebuf(&buf[0]);
|
std::string linebuf(&buf[0]);
|
||||||
|
|
||||||
@@ -625,11 +634,20 @@ LoadObj(
|
|||||||
token += 7;
|
token += 7;
|
||||||
sscanf(token, "%s", namebuf);
|
sscanf(token, "%s", namebuf);
|
||||||
|
|
||||||
std::string err_mtl = LoadMtl(material_map, namebuf, mtl_basepath);
|
if (!getMatFn) {
|
||||||
if (!err_mtl.empty()) {
|
err << "Could not read material, no callable function target.";
|
||||||
faceGroup.clear(); // for safety
|
return err.str();
|
||||||
return err_mtl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<std::istream> matIStream = getMatFn(namebuf);
|
||||||
|
if (matIStream) {
|
||||||
|
std::string err_mtl = LoadMtl(material_map, *matIStream);
|
||||||
|
if (!err_mtl.empty()) {
|
||||||
|
faceGroup.clear(); // for safety
|
||||||
|
return err_mtl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace tinyobj {
|
namespace tinyobj {
|
||||||
|
|
||||||
@@ -49,6 +51,13 @@ typedef struct
|
|||||||
mesh_t mesh;
|
mesh_t mesh;
|
||||||
} shape_t;
|
} shape_t;
|
||||||
|
|
||||||
|
/// typedef for a function that returns a pointer to an istream for
|
||||||
|
/// the material identified by the const std::string&
|
||||||
|
typedef std::function<
|
||||||
|
std::unique_ptr<std::istream>(
|
||||||
|
const std::string&)
|
||||||
|
> GetMtlIStreamFn;
|
||||||
|
|
||||||
/// Loads .obj from a file.
|
/// Loads .obj from a file.
|
||||||
/// 'shapes' will be filled with parsed shape data
|
/// 'shapes' will be filled with parsed shape data
|
||||||
/// The function returns error string.
|
/// The function returns error string.
|
||||||
@@ -59,6 +68,13 @@ std::string LoadObj(
|
|||||||
const char* filename,
|
const char* filename,
|
||||||
const char* mtl_basepath = NULL);
|
const char* mtl_basepath = NULL);
|
||||||
|
|
||||||
|
/// Loads object from a std::istream, uses GetMtlIStreamFn to retrieve
|
||||||
|
/// std::istream for materials.
|
||||||
|
/// Returns empty string when loading .obj success.
|
||||||
|
std::string LoadObj(
|
||||||
|
std::vector<shape_t>& shapes, // [output]
|
||||||
|
std::istream& inStream,
|
||||||
|
GetMtlIStreamFn getMatFn);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _TINY_OBJ_LOADER_H
|
#endif // _TINY_OBJ_LOADER_H
|
||||||
|
|||||||
Reference in New Issue
Block a user