450 lines
15 KiB
C++
450 lines
15 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;
|
|
}
|