Files
qad/libs/qglview/loader_ase.cpp
2020-08-25 22:24:02 +03:00

387 lines
14 KiB
C++

/*
QGLView
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "loader_ase.h"
void LoaderASE::initASEMesh(GLObjectBase * o) {
QVector<GLfloat> & vertices(o->VBO().vertices()), & normals(o->VBO().normals()), & uvs(o->VBO().texcoords());
QVector<Vector3d> & points(o->points), & puvws(o->puvws), & fnormals(o->normals);
QVector<Vector3i> & faces(o->faces);
Vector3d pos = Vector3d(o->pos());
bool has_uv = !puvws.isEmpty(), has_norms = !fnormals.isEmpty();
Vector3i cf;
Vector3d v0, v1, v2, cn0, cn1, cn2;
int ni = 0;
for (int i = 0; i < points.size(); ++i)
points[i] -= pos;
if (!has_norms) {
fnormals.resize(faces.size() * 3);
for (int i = 0; i < faces.size(); ++i) {
cf = faces[i];
v0 = points[cf.p0];
v1 = points[cf.p1];
v2 = points[cf.p2];
cn0 = ((v1 - v0) * (v2 - v0)).normalized();
fnormals[ni] = cn0; ++ni;
fnormals[ni] = cn0; ++ni;
fnormals[ni] = cn0; ++ni;
}
}
int fcnt = faces.size() * 3;
vertices.resize(fcnt * 3);
normals.resize(vertices.size());
if (has_uv) uvs.resize(fcnt * 2);
int ind = 0, induv = 0;
qDebug() << "init ase" << faces.size() << "faces";
ni = 0;
for (int i = 0; i < faces.size(); ++i) {
cf = faces[i];
v0 = points[cf.p0];
v1 = points[cf.p1];
v2 = points[cf.p2];
cn0 = fnormals[ni]; ++ni;
cn1 = fnormals[ni]; ++ni;
cn2 = fnormals[ni]; ++ni;
vertices[ind] = v0.x; normals[ind] = cn0.x; ++ind;
vertices[ind] = v0.y; normals[ind] = cn0.y; ++ind;
vertices[ind] = v0.z; normals[ind] = cn0.z; ++ind;
vertices[ind] = v1.x; normals[ind] = cn1.x; ++ind;
vertices[ind] = v1.y; normals[ind] = cn1.y; ++ind;
vertices[ind] = v1.z; normals[ind] = cn1.z; ++ind;
vertices[ind] = v2.x; normals[ind] = cn2.x; ++ind;
vertices[ind] = v2.y; normals[ind] = cn2.y; ++ind;
vertices[ind] = v2.z; normals[ind] = cn2.z; ++ind;
if (has_uv) {
uvs[induv] = puvws[cf.p0].x; ++induv;
uvs[induv] = puvws[cf.p0].y; ++induv;
uvs[induv] = puvws[cf.p1].x; ++induv;
uvs[induv] = puvws[cf.p1].y; ++induv;
uvs[induv] = puvws[cf.p2].x; ++induv;
uvs[induv] = puvws[cf.p2].y; ++induv;
}
}
}
GLObjectBase * loadFromASEFile(const QString & filepath, float scale) {
QFile f(filepath);
if (!f.exists()) {
qDebug() << "[Loader ASE] Error: can`t open" << filepath;
return nullptr;
}
f.open(QIODevice::ReadOnly);
//QVector<Material> materials;
GLObjectBase * root = new GLObjectBase(), * co = nullptr;
root->setName(QFileInfo(f).baseName());
QTextStream stream(&f);
QVector<Material> materials;
QVector<Vector3d> points, puvws;
QVector<Vector3i> faces, uvws;
QVector<Vector3d> normals;
Vector3d cv;
int mst = -1;//, mat_ind;
qint64 pst;
QString line, cname;
/// Parse materials
while (mst < 0 && !stream.atEnd()) {
line = stream.readLine();
mst = line.indexOf("MATERIAL_LIST {");
}
line = stream.readLine().trimmed();
mst = line.indexOf("MATERIAL_COUNT");
materials.resize(line.right(line.length() - mst - 14).toInt());
//qDebug() << materials.size() << "materials";
for (int i = 0; i < materials.size(); ++i) {
materials[i].map_diffuse.bitmap_id = 0;
mst = -1;
while (mst < 0 && !stream.atEnd()) {
line = stream.readLine();
mst = line.indexOf("MATERIAL " + QString::number(i) + " {");
}
/// Parse material i
while (line != "}" && !stream.atEnd()) {
line = stream.readLine().trimmed();
if (line.left(17) == "*MATERIAL_DIFFUSE") {materials[i].color_diffuse = colorFromString(line.right(line.length() - 18)); continue;} //qDebug() << "diffuse " << i << " = " << colorFromString(line.right(line.length() - 18));
if (line.left(18) == "*MATERIAL_SPECULAR") {materials[i].color_specular = colorFromString(line.right(line.length() - 19)); continue;} //qDebug() << "specular " << i << " = " << colorFromString(line.right(line.length() - 19));
if (line.left(23) == "*MATERIAL_SHINESTRENGTH") {materials[i].map_specular.color_amount = line.right(line.length() - 24).toFloat(); continue;}
if (line.left(15) == "*MATERIAL_SHINE") {materials[i].map_specularity.color_amount = 2.f / expf(line.right(line.length() - 16).toFloat()); continue;}
if (line.left(22) == "*MATERIAL_TRANSPARENCY") {materials[i].transparency = line.right(line.length() - 23).toFloat(); continue;}
if (line.left(12) == "*MAP_DIFFUSE") {
line = stream.readLine().trimmed();
while (line.left(11) != "*MAP_AMOUNT" && !stream.atEnd()) line = stream.readLine().trimmed();
materials[i].map_normal.color_amount = line.right(line.length() - 12).toFloat();
while (line.left(7) != "*BITMAP" && !stream.atEnd()) line = stream.readLine().trimmed();
materials[i].map_diffuse.bitmap_path = line.mid(9, line.length() - 10);
/*if (!materials[i].diffuse.bitmap_path.isEmpty()) {
materials[i].diffuse.bitmap_id = currentQGLView->bindTexture(QImage(materials[i].diffuse.bitmap_path));
parent->textures << materials[i].diffuse.bitmap_id;
}
qDebug() << materials[i].diffuse.bitmap_path << ", bind to" << materials[i].diffuse.bitmap_id;*/
while (line != "}" && !stream.atEnd()) line = stream.readLine().trimmed();
line = "";
continue;
}
if (line.left(9) == "*MAP_BUMP") {
line = stream.readLine().trimmed();
while (line.left(11) != "*MAP_AMOUNT" && !stream.atEnd()) line = stream.readLine().trimmed();
materials[i].map_normal.color_amount = line.right(line.length() - 12).toFloat();
//qDebug() << "bump amount" << materials[i].bump.color_amount;
while (line.left(7) != "*BITMAP" && !stream.atEnd()) line = stream.readLine().trimmed();
materials[i].map_normal.bitmap_path = line.mid(9, line.length() - 10);
/*if (!materials[i].bump.bitmap_path.isEmpty()) {
materials[i].bump.bitmap_id = currentQGLView->bindTexture(QImage(materials[i].bump.bitmap_path));
parent->textures << materials[i].bump.bitmap_id;
}
qDebug() << materials[i].bump.bitmap_path << ", bind to" << materials[i].bump.bitmap_id;*/
while (line != "}" && !stream.atEnd()) line = stream.readLine().trimmed();
line = "";
continue;
}
}
}
//bs << materials;
/// Geometry objects
int cotype = 0;
mst = -1;
while (mst < 0 && !stream.atEnd()) {
line = stream.readLine();
if (line.indexOf("GEOMOBJECT {") >= 0 || line.indexOf("LIGHTOBJECT {") >= 0) {
if (line.indexOf("GEOMOBJECT {") >= 0) cotype = 0;
if (line.indexOf("LIGHTOBJECT {") >= 0) cotype = 1;
mst = -1;
if (co != nullptr) {
co->points = points;
co->faces = faces;
co->normals = normals;
co->uvws = uvws;
LoaderASE::initASEMesh(co);
root->addChild(co);
}
co = new GLObjectBase();
while (mst < 0 && !stream.atEnd()) {
line = stream.readLine();
mst = line.indexOf("NODE_NAME");
}
cname = line.right(line.length() - mst - 10);
co->setName(cname.mid(1, cname.length() - 2));
qDebug() << co->name();
}
mst = -1;
switch (cotype) {
case 0:
//qDebug() << "object";
while (mst < 0 && !stream.atEnd()) {
line = stream.readLine();
mst = line.indexOf("MESH {");
}
mst = -1;
while (mst < 0 && !stream.atEnd()) {
line = stream.readLine();
mst = line.indexOf("MESH_NUMVERTEX ");
}
points.resize(line.right(line.length() - mst - 15).toInt());
//qDebug() << points.size() << "vertices";
mst = -1;
while (mst < 0 && !stream.atEnd()) {
line = stream.readLine();
mst = line.indexOf("MESH_NUMFACES ");
}
faces.resize(line.right(line.length() - mst - 14).toInt());
normals.resize(faces.size() * 3);
//qDebug() << faces.size() << "faces";
//uvws.resize(faces.size());
/// Points
mst = -1;
while (mst < 0 && !stream.atEnd()) {
line = stream.readLine();
mst = line.indexOf("MESH_VERTEX_LIST {");
}
for (int i = 0; i < points.size(); ++i) {
line = stream.readLine().trimmed();
mst = line.indexOf("MESH_VERTEX");
points[i] = Vector3d(line.right(line.length() - mst - 17)) * scale;
//qDebug() << points[i];
}
/// Faces
mst = -1;
while (mst < 0 && !stream.atEnd()) {
line = stream.readLine();
mst = line.indexOf("MESH_FACE_LIST {");
}
for (int i = 0; i < faces.size(); ++i) {
line = stream.readLine().trimmed();
mst = line.indexOf("MESH_FACE");
line = line.right(line.length() - mst - 15);
mst = line.indexOf("A:"); line = line.right(line.length() - mst - 2);
mst = line.indexOf("B:");
faces[i].p0 = line.left(mst).toInt(); line = line.right(line.length() - mst - 2);
mst = line.indexOf("C:");
faces[i].p1 = line.left(mst).toInt(); line = line.right(line.length() - mst - 2);
mst = line.indexOf("AB");
faces[i].p2 = line.left(mst).toInt();
//qDebug() << faces[i];
}
/// Texture coordinates
mst = -1;
pst = stream.pos();
while (mst < 0 && !stream.atEnd()) {
line = stream.readLine();
mst = line.indexOf("MESH_NUMTVERTEX ");
}
if (mst >= 0) {
puvws.resize(line.right(line.length() - mst - 16).toInt());
//qDebug() << puvws.size() << "tvertices";
mst = -1;
while (mst < 0 && !stream.atEnd()) {
line = stream.readLine();
mst = line.indexOf("MESH_TVERTLIST {");
}
for (int i = 0; i < puvws.size(); ++i) {
line = stream.readLine().trimmed();
mst = line.indexOf("MESH_TVERT"); line = line.right(line.length() - mst - 10);
mst = line.indexOf("\t"); line = line.right(line.length() - mst - 1);
puvws[i] = Vector3d(line);
}
mst = -1;
while (mst < 0 && !stream.atEnd()) {
line = stream.readLine();
mst = line.indexOf("MESH_NUMTVFACES ");
}
uvws.resize(line.right(line.length() - mst - 16).toInt());
mst = -1;
while (mst < 0 && !stream.atEnd()) {
line = stream.readLine();
mst = line.indexOf("MESH_TFACELIST {");
}
for (int i = 0; i < uvws.size(); ++i) {
line = stream.readLine().trimmed();
mst = line.indexOf("MESH_TFACE"); line = line.right(line.length() - mst - 10);
mst = line.indexOf("\t"); line = line.right(line.length() - mst - 1);
uvws[i] = Vector3i(line);
}
} else {
uvws.clear();
uvws.resize(faces.size());
stream.seek(pst);
}
if (puvws.size() <= 0) puvws.resize(1);
/// Normals
mst = -1;
while (mst < 0 && !stream.atEnd()) {
line = stream.readLine();
mst = line.indexOf("MESH_NORMALS {");
}
for (int i = 0; i < faces.size(); ++i) {
line = stream.readLine();
line = stream.readLine().trimmed(); mst = line.indexOf(" ");
line = line.right(line.length() - mst - 1); normals[i * 3] = Vector3d(line);
line = stream.readLine().trimmed(); mst = line.indexOf(" ");
line = line.right(line.length() - mst - 1); normals[i * 3 + 1] = Vector3d(line);
line = stream.readLine().trimmed(); mst = line.indexOf(" ");
line = line.right(line.length() - mst - 1); normals[i * 3 + 2] = Vector3d(line);
//qDebug() << normals[i][0] << normals[i][1] << normals[i][2];
}
/// Material index
mst = -1;
while (mst < 0 && !stream.atEnd()) {
line = stream.readLine();
mst = line.indexOf("MATERIAL_REF ");
}
//mat_ind = line.right(line.length() - mst - 13).toInt();
//qDebug() << mat_ind.back();
if (points.size() == 0 || faces.size() == 0) {
mst = -1;
continue;
}
/// Compiling into GLList
/*glNewList(model, GL_COMPILE);
if (mat_ind < 0 || mat_ind >= materials.size()) {
mat_diffuse[0] = cfr;
mat_diffuse[1] = cfg;
mat_diffuse[2] = cfb;
glColor3f(cfr, cfg, cfb);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_none);
glMaterialf(GL_FRONT, GL_SHININESS, 0.);
} else {
materials[mat_ind].apply();
//parent->material_ = materials[mat_ind];
}
glBegin(GL_TRIANGLES);
if (normals_) {
for (int i = 0; i < faces.size(); ++i) {
glNormal3d(normals[i][0].x, normals[i][0].y, normals[i][0].z);
glTexCoord3d(puvws[uvws[i].p0].x, puvws[uvws[i].p0].y, puvws[uvws[i].p0].z);
cv = points[faces[i].p0] * scale; glVertex3d(cv.x, cv.y, cv.z);
glNormal3d(normals[i][1].x, normals[i][1].y, normals[i][1].z);
glTexCoord3d(puvws[uvws[i].p1].x, puvws[uvws[i].p1].y, puvws[uvws[i].p1].z);
cv = points[faces[i].p1] * scale; glVertex3d(cv.x, cv.y, cv.z);
glNormal3d(normals[i][2].x, normals[i][2].y, normals[i][2].z);
glTexCoord3d(puvws[uvws[i].p2].x, puvws[uvws[i].p2].y, puvws[uvws[i].p2].z);
cv = points[faces[i].p2] * scale; glVertex3d(cv.x, cv.y, cv.z);
}
} else {
for (int i = 0; i < faces.size(); ++i) {
glTexCoord3d(puvws[uvws[i].p0].x, puvws[uvws[i].p0].y, puvws[uvws[i].p0].z);
cv = points[faces[i].p0] * scale; glVertex3d(cv.x, cv.y, cv.z);
glTexCoord3d(puvws[uvws[i].p1].x, puvws[uvws[i].p1].y, puvws[uvws[i].p1].z);
cv = points[faces[i].p1] * scale; glVertex3d(cv.x, cv.y, cv.z);
glTexCoord3d(puvws[uvws[i].p2].x, puvws[uvws[i].p2].y, puvws[uvws[i].p2].z);
cv = points[faces[i].p2] * scale; glVertex3d(cv.x, cv.y, cv.z);
}
}
glEnd();*/
///// Save binary
//bs << mat_ind << points << faces << puvws << uvws << normals;
break;
case 1:
qDebug() << "light";
mst = -1;
while (mst < 0 && !stream.atEnd()) {
line = stream.readLine();
mst = line.indexOf("MESH_NORMALS {");
}
break;
}
/// Continue
mst = -1;
}
f.close();
if (co != nullptr) {
co->points = points;
co->faces = faces;
co->normals = normals;
co->uvws = uvws;
LoaderASE::initASEMesh(co);
root->addChild(co);
}
/*parent->points = points;
parent->puvws = puvws;
parent->faces = faces;
parent->uvws = uvws;
parent->normals = normals;
return model;*/
return root;
}