git-svn-id: svn://db.shs.com.ru/libs@43 a8b55f48-bf90-11e4-a774-851b48703e85
This commit is contained in:
270
qglview/loader_obj.cpp
Normal file
270
qglview/loader_obj.cpp
Normal file
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
QGLView
|
||||
Copyright (C) 2012 Ivan Pelipenko peri4ko@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "loader_obj.h"
|
||||
|
||||
|
||||
void LoaderOBJ::initOBJMesh(GLObjectBase * o, const QVector<Vector3d> & src_vertices, const QVector<Vector3d> & src_normals, const QVector<Vector3d> & src_texcoords) {
|
||||
QVector<GLfloat> & vertices(o->VBO().vertices()), & normals(o->VBO().normals()), & uvs(o->VBO().texcoords());
|
||||
QVector<Vector3i> & faces(o->faces), & uvws(o->uvws), & norms(o->norms);
|
||||
//Vector3d pos = Vector3d(o->pos());
|
||||
bool has_uv = !uvws.isEmpty();
|
||||
Vector3i cf, ct, cn;
|
||||
Vector3d v[3], t[3], n[3];
|
||||
//for (int i = 0; i < points.size(); ++i)
|
||||
// points[i] -= pos;
|
||||
uint fcnt = faces.size() * 3;
|
||||
vertices.resize(fcnt * 3);
|
||||
normals.resize(vertices.size());
|
||||
if (has_uv) uvs.resize(fcnt * 2);
|
||||
uint ind = 0, induv = 0;
|
||||
//qDebug() << "initOBJMesh" << faces.size();
|
||||
for (int i = 0; i < faces.size(); ++i) {
|
||||
cf = faces[i];
|
||||
ct = uvws[i];
|
||||
cn = norms[i];
|
||||
v[0] = src_vertices[cf.p0];
|
||||
v[1] = src_vertices[cf.p1];
|
||||
v[2] = src_vertices[cf.p2];
|
||||
n[0] = src_normals[cn.p0];
|
||||
n[1] = src_normals[cn.p1];
|
||||
n[2] = src_normals[cn.p2];
|
||||
vertices[ind] = v[0].x; normals[ind] = n[0].x; ++ind;
|
||||
vertices[ind] = v[0].y; normals[ind] = n[0].y; ++ind;
|
||||
vertices[ind] = v[0].z; normals[ind] = n[0].z; ++ind;
|
||||
vertices[ind] = v[1].x; normals[ind] = n[1].x; ++ind;
|
||||
vertices[ind] = v[1].y; normals[ind] = n[1].y; ++ind;
|
||||
vertices[ind] = v[1].z; normals[ind] = n[1].z; ++ind;
|
||||
vertices[ind] = v[2].x; normals[ind] = n[2].x; ++ind;
|
||||
vertices[ind] = v[2].y; normals[ind] = n[2].y; ++ind;
|
||||
vertices[ind] = v[2].z; normals[ind] = n[2].z; ++ind;
|
||||
if (has_uv) {
|
||||
if ((ct.p0 >= 0) && (ct.p1 >= 0) && (ct.p2 >= 0)) {
|
||||
t[0] = src_texcoords[ct.p0];
|
||||
t[1] = src_texcoords[ct.p1];
|
||||
t[2] = src_texcoords[ct.p2];
|
||||
uvs[induv] = t[0].x; ++induv;
|
||||
uvs[induv] = t[0].y; ++induv;
|
||||
uvs[induv] = t[1].x; ++induv;
|
||||
uvs[induv] = t[1].y; ++induv;
|
||||
uvs[induv] = t[2].x; ++induv;
|
||||
uvs[induv] = t[2].y; ++induv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vector3d readVector3d(QString s) {
|
||||
Vector3d ret;
|
||||
QStringList sl(s.trimmed().split(" "));
|
||||
sl.removeAll(""); sl.removeAll(" ");
|
||||
if (sl.size() > 0) ret.x = sl[0].toDouble();
|
||||
if (sl.size() > 1) ret.y = sl[1].toDouble();
|
||||
if (sl.size() > 2) ret.z = sl[2].toDouble();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Vector2d readVector2d(QString s) {
|
||||
Vector2d ret;
|
||||
QStringList sl(s.trimmed().split(" "));
|
||||
sl.removeAll(""); sl.removeAll(" ");
|
||||
if (sl.size() > 0) ret.x = sl[0].toDouble();
|
||||
if (sl.size() > 1) ret.y = sl[1].toDouble();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
QColor readColor(QString s) {
|
||||
Vector3d c = readVector3d(s);
|
||||
return QColor::fromRgbF(c.x, c.y, c.z);
|
||||
}
|
||||
|
||||
|
||||
void readFaces(QString s, GLObjectBase * co) {
|
||||
QStringList sl(s.trimmed().split(" "));
|
||||
sl.removeAll(""); sl.removeAll(" ");
|
||||
static Vector3i inds[4];
|
||||
for (int i = 0; i < sl.size(); ++i) {
|
||||
inds[i].p0 = inds[i].p1 = inds[i].p2 = 0;
|
||||
QStringList sl2(sl[i].split("/"));
|
||||
if (sl2.size() > 4) continue;
|
||||
inds[i].p0 = sl2[0].toInt();
|
||||
inds[i].p1 = sl2[1].toInt();
|
||||
inds[i].p2 = sl2[2].toInt();
|
||||
}
|
||||
if (sl.size() == 3) {
|
||||
co->faces << Vector3i(inds[0].p0 - 1, inds[1].p0 - 1, inds[2].p0 - 1);
|
||||
co->uvws << Vector3i(inds[0].p1 - 1, inds[1].p1 - 1, inds[2].p1 - 1);
|
||||
co->norms << Vector3i(inds[0].p2 - 1, inds[1].p2 - 1, inds[2].p2 - 1);
|
||||
}
|
||||
if (sl.size() == 4) {
|
||||
co->faces << Vector3i(inds[0].p0 - 1, inds[1].p0 - 1, inds[2].p0 - 1);
|
||||
co->uvws << Vector3i(inds[0].p1 - 1, inds[1].p1 - 1, inds[2].p1 - 1);
|
||||
co->norms << Vector3i(inds[0].p2 - 1, inds[1].p2 - 1, inds[2].p2 - 1);
|
||||
co->faces << Vector3i(inds[0].p0 - 1, inds[2].p0 - 1, inds[3].p0 - 1);
|
||||
co->uvws << Vector3i(inds[0].p1 - 1, inds[2].p1 - 1, inds[3].p1 - 1);
|
||||
co->norms << Vector3i(inds[0].p2 - 1, inds[2].p2 - 1, inds[3].p2 - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QVector<Material> readMTL(QString obj_path, QString path) {
|
||||
QVector<Material> ret;
|
||||
QStringList sp = GLTextureManagerBase::searchPathes();
|
||||
sp.prepend(QFileInfo(obj_path).absoluteDir().path());
|
||||
QFile f(findFile(path, sp));
|
||||
if (!f.open(QIODevice::ReadOnly)) {
|
||||
qDebug() << "[Loader OBJ] Warning: can`t open \"" + path + "\"";
|
||||
return ret;
|
||||
}
|
||||
QTextStream stream(&f);
|
||||
QString name;
|
||||
Material mat;
|
||||
while (!stream.atEnd()) {
|
||||
QString line = stream.readLine().trimmed();
|
||||
if (line.startsWith("newmtl")) {
|
||||
if (!mat.name.isEmpty())
|
||||
ret << mat;
|
||||
mat = Material();
|
||||
mat.name = line.mid(6).trimmed();
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("Kd")) {
|
||||
mat.color_diffuse = readColor(line.mid(2).trimmed());
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("Ke")) {
|
||||
mat.color_self_illumination = readColor(line.mid(2).trimmed());
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("Ks")) {
|
||||
Vector3d v = readVector3d(line.mid(2).trimmed());
|
||||
mat.shine_strength = v.length();
|
||||
double mc = qMax(v.x, qMax(v.y, v.z));
|
||||
if (mc > 0.) v /= mc;
|
||||
mat.color_specular = QColor::fromRgbF(v.x, v.y, v.z);
|
||||
//qDebug() << mat.shine_strength << mat.color_specular;
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("Ns")) {
|
||||
mat.shine = line.mid(2).trimmed().toDouble();
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("d")) {
|
||||
mat.transparency = 1. - line.mid(1).trimmed().toDouble();
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("map_Kd")) {
|
||||
mat.diffuse.bitmap_path = findFile(line.mid(6).trimmed(), sp);
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("map_bump")) {
|
||||
line = line.mid(8).trimmed();
|
||||
if (line.startsWith("-bm")) {
|
||||
line = line.mid(3).trimmed();
|
||||
QString sv = line.left(line.indexOf(" "));
|
||||
line = line.mid(sv.size()).trimmed();
|
||||
mat.bump_scale = sv.toDouble();
|
||||
}
|
||||
mat.bump.bitmap_path = findFile(line, sp);
|
||||
//qDebug() << "BUMP" << mat.name << mat.bump_scale << mat.bump.bitmap_path;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!mat.name.isEmpty())
|
||||
ret << mat;
|
||||
qDebug() << "load from MTL" << f.fileName() << ret.size() << "materials";
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Material LoaderOBJ::materialByName(const QVector<Material> & materials, const QString & name) {
|
||||
foreach (const Material & m, materials)
|
||||
if (m.name == name)
|
||||
return m;
|
||||
return Material();
|
||||
}
|
||||
|
||||
|
||||
GLObjectBase * loadFromOBJFile(const QString & filepath, double scale) {
|
||||
QFile f(filepath);
|
||||
if (!f.exists()) {
|
||||
qDebug() << "[Loader OBJ] Error: can`t open \"" + filepath + "\"";
|
||||
return 0;
|
||||
}
|
||||
f.open(QIODevice::ReadOnly);
|
||||
QTextStream stream(&f);
|
||||
QVector<Vector3d> vertices, normals, texcoords;
|
||||
QVector<Material> materials;
|
||||
GLObjectBase * root = new GLObjectBase(), * co = 0;
|
||||
QString name;
|
||||
root->setName(QFileInfo(f).baseName());
|
||||
int cnt = 0;
|
||||
while (!stream.atEnd()) {
|
||||
QString line = stream.readLine().trimmed();
|
||||
if (line.startsWith("mtllib")) {
|
||||
materials = readMTL(filepath, line.mid(6).trimmed());
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("v ")) {
|
||||
vertices << readVector3d(line.mid(1));
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("vt ")) {
|
||||
texcoords << readVector3d(line.mid(2));
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("vn ")) {
|
||||
normals << readVector3d(line.mid(2));
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("g ")) {
|
||||
name = line.mid(1).trimmed();
|
||||
if (co != 0) {
|
||||
LoaderOBJ::initOBJMesh(co, vertices, normals, texcoords);
|
||||
root->addChild(co);
|
||||
}
|
||||
co = new GLObjectBase();
|
||||
co->setName(name);
|
||||
//qDebug() << "new object" << co->name();
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("f ")) {
|
||||
readFaces(line.mid(2), co);
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("usemtl")) {
|
||||
if (!co->faces.isEmpty()) {
|
||||
LoaderOBJ::initOBJMesh(co, vertices, normals, texcoords);
|
||||
root->addChild(co);
|
||||
co = new GLObjectBase();
|
||||
co->setName(name + "_" + QString::number(cnt++));
|
||||
}
|
||||
co->material() = LoaderOBJ::materialByName(materials, line.mid(6).trimmed());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (co != 0) {
|
||||
LoaderOBJ::initOBJMesh(co, vertices, normals, texcoords);
|
||||
root->addChild(co);
|
||||
}
|
||||
qDebug() << "[Loader OBJ] Loaded" << root->childCount() << "objects from" << filepath;
|
||||
return root;
|
||||
}
|
||||
Reference in New Issue
Block a user