/* 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 . */ #include "loader_ase.h" void LoaderASE::initASEMesh(GLObjectBase * o) { QVector & vertices(o->VBO().vertices()), & normals(o->VBO().normals()), & uvs(o->VBO().texcoords()); QVector & points(o->points), & puvws(o->puvws), & fnormals(o->normals); QVector & 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 materials; GLObjectBase * root = new GLObjectBase(), * co = nullptr; root->setName(QFileInfo(f).baseName()); QTextStream stream(&f); QVector materials; QVector points, puvws; QVector faces, uvws; QVector 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; }