limited TGA loading support, better OBJ material import
parent
76e6ac6322
commit
bd9ff72f4d
|
@ -17,6 +17,7 @@ public:
|
||||||
enum EFileFormat {
|
enum EFileFormat {
|
||||||
EPNG = 0,
|
EPNG = 0,
|
||||||
EEXR,
|
EEXR,
|
||||||
|
ETGA,
|
||||||
EJPEG
|
EJPEG
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -101,6 +102,9 @@ protected:
|
||||||
/// Load a file stored using the PNG file format
|
/// Load a file stored using the PNG file format
|
||||||
void loadPNG(Stream *stream);
|
void loadPNG(Stream *stream);
|
||||||
|
|
||||||
|
/// Load a file stored using the TGA file format
|
||||||
|
void loadTGA(Stream *stream);
|
||||||
|
|
||||||
/// Load a file stored using the JPEG file format
|
/// Load a file stored using the JPEG file format
|
||||||
void loadJPEG(Stream *stream);
|
void loadJPEG(Stream *stream);
|
||||||
|
|
||||||
|
|
|
@ -629,29 +629,30 @@ void loadImage(GeometryConverter *cvt, std::ostream &os, const std::string &text
|
||||||
fileToId[filename] = image.getId();
|
fileToId[filename] = image.getId();
|
||||||
|
|
||||||
boost::filesystem::path path = boost::filesystem::path(filename, boost::filesystem::native);
|
boost::filesystem::path path = boost::filesystem::path(filename, boost::filesystem::native);
|
||||||
std::string leaf = path.leaf();
|
ref<FileResolver> fRes = FileResolver::getInstance();
|
||||||
|
std::string resolved = fRes->resolve(path.leaf());
|
||||||
|
|
||||||
if (endsWith(leaf, ".rgb"))
|
if (endsWith(resolved, ".rgb"))
|
||||||
SLog(EWarn, "Maya RGB images must be converted to PNG, EXR or JPEG! The 'imgcvt' "
|
SLog(EWarn, "Maya RGB images must be converted to PNG, EXR or JPEG! The 'imgcvt' "
|
||||||
"utility found in the Maya binary directory can be used to do this.");
|
"utility found in the Maya binary directory can be used to do this.");
|
||||||
|
|
||||||
if (!FileStream::exists(filename)) {
|
if (!FileStream::exists(filename)) {
|
||||||
if (!FileStream::exists(leaf)) {
|
if (!FileStream::exists(resolved)) {
|
||||||
SLog(EWarn, "Found neither \"%s\" nor \"%s\"!", filename.c_str(), leaf.c_str());
|
SLog(EWarn, "Found neither \"%s\" nor \"%s\"!", filename.c_str(), resolved.c_str());
|
||||||
filename = cvt->locateResource(filename);
|
filename = cvt->locateResource(filename);
|
||||||
if (filename == "")
|
if (filename == "")
|
||||||
SLog(EError, "Unable to locate a resource -- aborting conversion.");
|
SLog(EError, "Unable to locate a resource -- aborting conversion.");
|
||||||
} else {
|
} else {
|
||||||
filename = leaf;
|
filename = resolved;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ref<FileStream> input = new FileStream(filename, FileStream::EReadOnly);
|
ref<FileStream> input = new FileStream(filename, FileStream::EReadOnly);
|
||||||
ref<FileStream> output = new FileStream(textureDir + leaf.c_str(), FileStream::ETruncReadWrite);
|
ref<FileStream> output = new FileStream(textureDir + path.leaf(), FileStream::ETruncReadWrite);
|
||||||
input->copyTo(output);
|
input->copyTo(output);
|
||||||
|
|
||||||
os << "\t<texture id=\"" << image.getId() << "\" type=\"ldrtexture\">" << endl;
|
os << "\t<texture id=\"" << image.getId() << "\" type=\"ldrtexture\">" << endl;
|
||||||
os << "\t\t<string name=\"filename\" value=\"" << textureDir + leaf << "\"/>" << endl;
|
os << "\t\t<string name=\"filename\" value=\"" << textureDir + path.leaf() << "\"/>" << endl;
|
||||||
os << "\t</texture>" << endl << endl;
|
os << "\t</texture>" << endl << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,8 @@ void help() {
|
||||||
<< "Syntax: mtsimport [options] <DAE/OBJ scene> <XML output file> [Adjustment file]" << endl
|
<< "Syntax: mtsimport [options] <DAE/OBJ scene> <XML output file> [Adjustment file]" << endl
|
||||||
<< "Options/Arguments:" << endl
|
<< "Options/Arguments:" << endl
|
||||||
<< " -h Display this help text" << endl << endl
|
<< " -h Display this help text" << endl << endl
|
||||||
|
<< " -a p1;p2;.. Add one or more entries to the resource search path" << endl << endl
|
||||||
|
<< " -v Be more verbose" << endl << endl
|
||||||
<< " -p <num> Use the specified number of samples per pixel." << endl << endl
|
<< " -p <num> Use the specified number of samples per pixel." << endl << endl
|
||||||
<< " -s Assume that colors are in sRGB space." << endl << endl
|
<< " -s Assume that colors are in sRGB space." << endl << endl
|
||||||
<< " -m Map the larger image side to the full field of view" << endl << endl
|
<< " -m Map the larger image side to the full field of view" << endl << endl
|
||||||
|
@ -69,11 +71,19 @@ int colladaMain(int argc, char **argv) {
|
||||||
int xres = -1, yres = -1;
|
int xres = -1, yres = -1;
|
||||||
int samplesPerPixel = 8;
|
int samplesPerPixel = 8;
|
||||||
Float fov = -1;
|
Float fov = -1;
|
||||||
|
FileResolver *resolver = FileResolver::getInstance();
|
||||||
|
ELogLevel logLevel = EInfo;
|
||||||
|
|
||||||
optind = 1;
|
optind = 1;
|
||||||
|
|
||||||
while ((optchar = getopt(argc, argv, "shmr:p:f:")) != -1) {
|
while ((optchar = getopt(argc, argv, "svhmr:a:p:f:")) != -1) {
|
||||||
switch (optchar) {
|
switch (optchar) {
|
||||||
|
case 'a': {
|
||||||
|
std::vector<std::string> paths = tokenize(optarg, ";");
|
||||||
|
for (unsigned int i=0; i<paths.size(); ++i)
|
||||||
|
resolver->addPath(paths[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
srgb = true;
|
srgb = true;
|
||||||
break;
|
break;
|
||||||
|
@ -85,6 +95,9 @@ int colladaMain(int argc, char **argv) {
|
||||||
if (*end_ptr != '\0')
|
if (*end_ptr != '\0')
|
||||||
SLog(EError, "Invalid number of samples per pixel!");
|
SLog(EError, "Invalid number of samples per pixel!");
|
||||||
break;
|
break;
|
||||||
|
case 'v':
|
||||||
|
logLevel = EDebug;
|
||||||
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
fov = strtod(optarg, &end_ptr);
|
fov = strtod(optarg, &end_ptr);
|
||||||
if (*end_ptr != '\0')
|
if (*end_ptr != '\0')
|
||||||
|
@ -114,6 +127,9 @@ int colladaMain(int argc, char **argv) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ref<Logger> log = Thread::getThread()->getLogger();
|
||||||
|
log->setLogLevel(logLevel);
|
||||||
|
|
||||||
ConsoleGeometryConverter converter;
|
ConsoleGeometryConverter converter;
|
||||||
converter.setSRGB(srgb);
|
converter.setSRGB(srgb);
|
||||||
converter.setResolution(xres, yres);
|
converter.setResolution(xres, yres);
|
||||||
|
|
|
@ -1,25 +1,147 @@
|
||||||
|
#define BOOST_FILESYSTEM_NO_LIB
|
||||||
|
#define BOOST_SYSTEM_NO_LIB
|
||||||
|
|
||||||
#include <mitsuba/core/plugin.h>
|
#include <mitsuba/core/plugin.h>
|
||||||
|
#include <mitsuba/core/fresolver.h>
|
||||||
#include <mitsuba/core/fstream.h>
|
#include <mitsuba/core/fstream.h>
|
||||||
#include <mitsuba/render/trimesh.h>
|
#include <mitsuba/render/trimesh.h>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <fstream>
|
||||||
#include "converter.h"
|
#include "converter.h"
|
||||||
|
|
||||||
|
std::string copyTexture(GeometryConverter *cvt, const std::string &textureDir, std::string filename) {
|
||||||
|
SLog(EInfo, "Copying texture \"%s\" ..", filename.c_str());
|
||||||
|
#if defined(WIN32)
|
||||||
|
for (size_t i=0; i<filename.length(); ++i)
|
||||||
|
if (filename[i] == '/')
|
||||||
|
filename[i] = '\\';
|
||||||
|
#else
|
||||||
|
for (size_t i=0; i<filename.length(); ++i)
|
||||||
|
if (filename[i] == '\\')
|
||||||
|
filename[i] = '/';
|
||||||
|
#endif
|
||||||
|
boost::filesystem::path path = boost::filesystem::path(filename, boost::filesystem::native);
|
||||||
|
ref<FileResolver> fRes = FileResolver::getInstance();
|
||||||
|
std::string resolved = fRes->resolve(path.leaf());
|
||||||
|
if (!FileStream::exists(filename)) {
|
||||||
|
if (!FileStream::exists(resolved)) {
|
||||||
|
SLog(EWarn, "Found neither \"%s\" nor \"%s\"!", filename.c_str(), resolved.c_str());
|
||||||
|
filename = cvt->locateResource(filename);
|
||||||
|
if (filename == "")
|
||||||
|
SLog(EError, "Unable to locate a resource -- aborting conversion.");
|
||||||
|
} else {
|
||||||
|
filename = resolved;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string targetPath = textureDir + path.leaf();
|
||||||
|
|
||||||
|
ref<FileStream> input = new FileStream(filename, FileStream::EReadOnly);
|
||||||
|
ref<FileStream> output = new FileStream(targetPath, FileStream::ETruncReadWrite);
|
||||||
|
input->copyTo(output);
|
||||||
|
output->close();
|
||||||
|
input->close();
|
||||||
|
|
||||||
|
return targetPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addMaterial(GeometryConverter *cvt, std::ostream &os, const std::string &mtlName,
|
||||||
|
const std::string &texturesDir, const Spectrum &diffuseValue,
|
||||||
|
const std::string &diffuseMap) {
|
||||||
|
if (mtlName == "")
|
||||||
|
return;
|
||||||
|
SLog(EInfo, "Copying material \"%s\" ..", mtlName.c_str());
|
||||||
|
os << "\t<bsdf id=\"" << mtlName << "\" type=\"lambertian\">" << endl;
|
||||||
|
if (diffuseMap == "") {
|
||||||
|
Float r, g, b;
|
||||||
|
diffuseValue.toLinearRGB(r, g, b);
|
||||||
|
os << "\t\t<rgb name=\"reflectance\" value=\""
|
||||||
|
<< r << " " << g << " " << b << "\"/>" << endl;
|
||||||
|
} else {
|
||||||
|
os << "\t\t<texture name=\"reflectance\" type=\"ldrtexture\">" << endl
|
||||||
|
<< "\t\t\t<string name=\"filename\" value=\"" << copyTexture(cvt, texturesDir, diffuseMap) << "\"/>" << endl
|
||||||
|
<< "\t\t</texture>" << endl;
|
||||||
|
}
|
||||||
|
os << "\t</bsdf>" << endl << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseMaterials(GeometryConverter *cvt, std::ostream &os, const std::string &texturesDir,
|
||||||
|
const std::string &mtlFileName) {
|
||||||
|
SLog(EInfo, "Loading OBJ materials from \"%s\" ..", mtlFileName.c_str());
|
||||||
|
std::ifstream is(mtlFileName.c_str());
|
||||||
|
if (is.bad() || is.fail())
|
||||||
|
SLog(EError, "Unexpected I/O error while accessing material file '%s'!", mtlFileName.c_str());
|
||||||
|
std::string buf, line;
|
||||||
|
std::string mtlName;
|
||||||
|
Spectrum diffuse(0.0f);
|
||||||
|
std::string diffuseMap;
|
||||||
|
|
||||||
|
while (is >> buf) {
|
||||||
|
if (buf == "newmtl") {
|
||||||
|
addMaterial(cvt, os, mtlName, texturesDir, diffuse, diffuseMap);
|
||||||
|
std::getline(is, line);
|
||||||
|
mtlName = line.substr(1, line.length()-2);
|
||||||
|
diffuse = Spectrum(0.0f);
|
||||||
|
diffuseMap = "";
|
||||||
|
} else if (buf == "Kd") {
|
||||||
|
Float r, g, b;
|
||||||
|
is >> r >> g >> b;
|
||||||
|
if (cvt->m_srgb)
|
||||||
|
diffuse.fromSRGB(r, g, b);
|
||||||
|
else
|
||||||
|
diffuse.fromLinearRGB(r, g, b);
|
||||||
|
} else if (buf == "map_Kd") {
|
||||||
|
std::getline(is, line);
|
||||||
|
diffuseMap = line.substr(1, line.length()-2);
|
||||||
|
} else {
|
||||||
|
/* Ignore */
|
||||||
|
std::getline(is, line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addMaterial(cvt, os, mtlName, texturesDir, diffuse, diffuseMap);
|
||||||
|
}
|
||||||
|
|
||||||
void GeometryConverter::convertOBJ(const std::string &inputFile,
|
void GeometryConverter::convertOBJ(const std::string &inputFile,
|
||||||
std::ostream &os,
|
std::ostream &os,
|
||||||
const std::string &textureDirectory,
|
const std::string &textureDirectory,
|
||||||
const std::string &meshesDirectory) {
|
const std::string &meshesDirectory) {
|
||||||
|
|
||||||
|
std::ifstream is(inputFile.c_str());
|
||||||
|
if (is.bad() || is.fail())
|
||||||
|
SLog(EError, "Could not open OBJ file '%s'!", inputFile.c_str());
|
||||||
|
|
||||||
|
os << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << endl << endl;
|
||||||
|
os << "<!--" << endl << endl;
|
||||||
|
os << "\tAutomatically converted from Wavefront OBJ" << endl << endl;
|
||||||
|
os << "-->" << endl << endl;
|
||||||
|
os << "<scene>" << endl;
|
||||||
|
os << "\t<integrator id=\"integrator\" type=\"direct\"/>" << endl << endl;
|
||||||
|
|
||||||
|
std::string buf, line;
|
||||||
|
while (is >> buf) {
|
||||||
|
if (buf == "mtllib") {
|
||||||
|
std::getline(is, line);
|
||||||
|
std::string mtlName = line.substr(1, line.length()-2);
|
||||||
|
ref<FileResolver> fRes = FileResolver::getInstance()->clone();
|
||||||
|
fRes->addPathFromFile(fRes->resolveAbsolute(inputFile));
|
||||||
|
std::string fullMtlName = fRes->resolve(mtlName);
|
||||||
|
if (FileStream::exists(fullMtlName))
|
||||||
|
parseMaterials(this, os, textureDirectory, fullMtlName);
|
||||||
|
else
|
||||||
|
SLog(EWarn, "Could not find referenced material library '%s'", mtlName.c_str());
|
||||||
|
} else {
|
||||||
|
/* Ignore */
|
||||||
|
std::getline(is, line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Properties objProps("obj");
|
Properties objProps("obj");
|
||||||
objProps.setString("filename", inputFile);
|
objProps.setString("filename", inputFile);
|
||||||
|
|
||||||
ref<Shape> rootShape = static_cast<Shape *> (PluginManager::getInstance()->
|
ref<Shape> rootShape = static_cast<Shape *> (PluginManager::getInstance()->
|
||||||
createObject(Shape::m_theClass, objProps));
|
createObject(Shape::m_theClass, objProps));
|
||||||
SAssert(rootShape->isCompound());
|
SAssert(rootShape->isCompound());
|
||||||
os << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << endl << endl;
|
|
||||||
os << "<!--" << endl << endl;
|
|
||||||
os << "\tAutomatically converted from Wavefront OBJ" << endl << endl;
|
|
||||||
os << "-->" << endl << endl;
|
|
||||||
os << "<scene>" << endl;
|
|
||||||
os << "\t<integrator id=\"integrator\" type=\"direct\"/>" << endl << endl;
|
|
||||||
|
|
||||||
int ctr = 0;
|
int ctr = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
|
@ -150,9 +150,11 @@ Bitmap::Bitmap(int width, int height, int bpp)
|
||||||
m_data = static_cast<unsigned char *>(allocAligned(m_size));
|
m_data = static_cast<unsigned char *>(allocAligned(m_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
Bitmap::Bitmap(EFileFormat format, Stream *stream) {
|
Bitmap::Bitmap(EFileFormat format, Stream *stream) : m_data(NULL) {
|
||||||
if (format == EPNG)
|
if (format == EPNG)
|
||||||
loadPNG(stream);
|
loadPNG(stream);
|
||||||
|
else if (format == ETGA)
|
||||||
|
loadTGA(stream);
|
||||||
else if (format == EJPEG)
|
else if (format == EJPEG)
|
||||||
loadJPEG(stream);
|
loadJPEG(stream);
|
||||||
else if (format == EEXR)
|
else if (format == EEXR)
|
||||||
|
@ -189,6 +191,40 @@ void Bitmap::loadEXR(Stream *stream) {
|
||||||
delete[] rgba;
|
delete[] rgba;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Bitmap::loadTGA(Stream *stream) {
|
||||||
|
int headerSize = stream->readUChar();
|
||||||
|
if (stream->readUChar() != 0)
|
||||||
|
Log(EError, "Invalid TGA format -- only raw (non-RLE encoded) RGB is supported for now");
|
||||||
|
if (stream->readUChar() != 2)
|
||||||
|
Log(EError, "Invalid TGA format -- only raw (non-RLE encoded) RGB is supported for now");
|
||||||
|
stream->setPos(8);
|
||||||
|
int x1 = stream->readShort();
|
||||||
|
int y1 = stream->readShort();
|
||||||
|
int x2 = stream->readShort();
|
||||||
|
int y2 = stream->readShort();
|
||||||
|
m_width = x2-x1;
|
||||||
|
m_height = y2-y1;
|
||||||
|
Log(EInfo, "Reading %ix%i TGA file", m_width, m_height);
|
||||||
|
|
||||||
|
stream->setPos(16);
|
||||||
|
m_bpp = stream->readUChar();
|
||||||
|
if (m_bpp != 24 && m_bpp != 32)
|
||||||
|
Log(EError, "Invalid TGA format -- only 24 or 32 bpp images are supported for now");
|
||||||
|
|
||||||
|
m_gamma = -1;
|
||||||
|
int channels = m_bpp / 8;
|
||||||
|
m_size = m_width * m_height * channels;
|
||||||
|
m_data = static_cast<unsigned char *>(allocAligned(m_size));
|
||||||
|
stream->setPos(18 + headerSize);
|
||||||
|
stream->read(m_data, m_size);
|
||||||
|
|
||||||
|
/* Convert BGR to RGB */
|
||||||
|
for (size_t i=0; i<m_size; i += channels) {
|
||||||
|
uint8_t tmp = m_data[i];
|
||||||
|
m_data[i] = m_data[i+2];
|
||||||
|
m_data[i+2] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Bitmap::loadPNG(Stream *stream) {
|
void Bitmap::loadPNG(Stream *stream) {
|
||||||
png_structp png_ptr;
|
png_structp png_ptr;
|
||||||
|
@ -357,6 +393,7 @@ void Bitmap::loadJPEG(Stream *stream) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Bitmap::~Bitmap() {
|
Bitmap::~Bitmap() {
|
||||||
|
if (m_data)
|
||||||
freeAligned(m_data);
|
freeAligned(m_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
MTS_NAMESPACE_BEGIN
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gamma-corrected bitmap texture using the JPG or PNG file format
|
* Gamma-corrected bitmap texture using the JPG, TGA or PNG file format
|
||||||
*/
|
*/
|
||||||
class LDRTexture : public Texture {
|
class LDRTexture : public Texture {
|
||||||
public:
|
public:
|
||||||
|
@ -24,13 +24,14 @@ public:
|
||||||
ref<FileStream> fs = new FileStream(m_filename, FileStream::EReadOnly);
|
ref<FileStream> fs = new FileStream(m_filename, FileStream::EReadOnly);
|
||||||
std::string lower = toLowerCase(m_filename);
|
std::string lower = toLowerCase(m_filename);
|
||||||
|
|
||||||
if (lower.find("jpg") != std::string::npos || lower.find("jpeg") != std::string::npos) {
|
if (endsWith(lower, ".jpg") || endsWith(lower, ".jpeg"))
|
||||||
m_format = Bitmap::EJPEG;
|
m_format = Bitmap::EJPEG;
|
||||||
} else if (lower.find("png") != std::string::npos) {
|
else if (endsWith(lower, ".png"))
|
||||||
m_format = Bitmap::EPNG;
|
m_format = Bitmap::EPNG;
|
||||||
} else {
|
else if (endsWith(lower, ".tga"))
|
||||||
|
m_format = Bitmap::ETGA;
|
||||||
|
else
|
||||||
Log(EError, "Cannot deduce the file type of '%s'!", m_filename.c_str());
|
Log(EError, "Cannot deduce the file type of '%s'!", m_filename.c_str());
|
||||||
}
|
|
||||||
|
|
||||||
ref<Bitmap> bitmap = new Bitmap(m_format, fs);
|
ref<Bitmap> bitmap = new Bitmap(m_format, fs);
|
||||||
initializeFrom(bitmap);
|
initializeFrom(bitmap);
|
||||||
|
@ -281,5 +282,5 @@ Shader *LDRTexture::createShader(Renderer *renderer) const {
|
||||||
|
|
||||||
MTS_IMPLEMENT_CLASS_S(LDRTexture, false, Texture)
|
MTS_IMPLEMENT_CLASS_S(LDRTexture, false, Texture)
|
||||||
MTS_IMPLEMENT_CLASS(LDRTextureShader, false, Shader)
|
MTS_IMPLEMENT_CLASS(LDRTextureShader, false, Shader)
|
||||||
MTS_EXPORT_PLUGIN(LDRTexture, "LDR texture (JPG/PNG)");
|
MTS_EXPORT_PLUGIN(LDRTexture, "LDR texture (JPG/TGA/PNG)");
|
||||||
MTS_NAMESPACE_END
|
MTS_NAMESPACE_END
|
||||||
|
|
Loading…
Reference in New Issue