From e6e8c04114373e9ecacfdccd496e7503ed1046a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Sun, 30 Nov 2008 23:45:13 +0100 Subject: Add OpenGL model renderer and improve update/visibility handling for increased performance. --- model.cpp | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 model.cpp (limited to 'model.cpp') diff --git a/model.cpp b/model.cpp new file mode 100644 index 0000000..9831138 --- /dev/null +++ b/model.cpp @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** Copyright (C) 2008-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the Graphics Dojo project on Trolltech Labs. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ +#include "model.h" + +#include +#include +#include + +#include + +Model::Model(const QString &filePath) + : m_fileName(QFileInfo(filePath).fileName()) +{ + QFile file(filePath); + if (!file.open(QIODevice::ReadOnly)) + return; + + Point3d boundsMin( 1e9, 1e9, 1e9); + Point3d boundsMax(-1e9,-1e9,-1e9); + + QTextStream in(&file); + while (!in.atEnd()) { + QString input = in.readLine(); + if (input.isEmpty() || input[0] == '#') + continue; + + QTextStream ts(&input); + QString id; + ts >> id; + if (id == "v") { + Point3d p; + for (int i = 0; i < 3; ++i) { + ts >> p[i]; + boundsMin[i] = qMin(boundsMin[i], p[i]); + boundsMax[i] = qMax(boundsMax[i], p[i]); + } + m_points << p; + } else if (id == "f" || id == "fo") { + QVarLengthArray p; + + while (!ts.atEnd()) { + QString vertex; + ts >> vertex; + const int vertexIndex = vertex.split('/').value(0).toInt(); + if (vertexIndex) + p.append(vertexIndex > 0 ? vertexIndex - 1 : m_points.size() + vertexIndex); + } + + for (int i = 0; i < p.size(); ++i) { + const int edgeA = p[i]; + const int edgeB = p[(i + 1) % p.size()]; + + if (edgeA < edgeB) + m_edgeIndices << edgeA << edgeB; + } + + for (int i = 0; i < 3; ++i) + m_pointIndices << p[i]; + + if (p.size() == 4) + for (int i = 0; i < 3; ++i) + m_pointIndices << p[(i + 2) % 4]; + } + } + + const Point3d bounds = boundsMax - boundsMin; + const qreal scale = 1 / qMax(bounds.x / 1, qMax(bounds.y, bounds.z / 1)); + for (int i = 0; i < m_points.size(); ++i) + m_points[i] = (m_points[i] - (boundsMin + bounds * 0.5)) * scale; + + m_size = bounds * scale; + + m_normals.resize(m_points.size()); + for (int i = 0; i < m_pointIndices.size(); i += 3) { + const Point3d a = m_points.at(m_pointIndices.at(i)); + const Point3d b = m_points.at(m_pointIndices.at(i+1)); + const Point3d c = m_points.at(m_pointIndices.at(i+2)); + + const Point3d normal = cross(b - a, c - a).normalize(); + + for (int j = 0; j < 3; ++j) + m_normals[m_pointIndices.at(i + j)] += normal; + } + + for (int i = 0; i < m_normals.size(); ++i) + m_normals[i] = m_normals[i].normalize(); +} + +Point3d Model::size() const +{ + return m_size; +} + +void Model::render(bool wireframe, bool normals) const +{ + glEnable(GL_DEPTH_TEST); + glEnableClientState(GL_VERTEX_ARRAY); + glDepthFunc(GL_GEQUAL); + glDepthMask(true); + glDisable(GL_TEXTURE_1D); + glDisable(GL_TEXTURE_2D); + if (wireframe) { + glVertexPointer(3, GL_FLOAT, 0, (float *)m_points.data()); + glDrawElements(GL_LINES, m_edgeIndices.size(), GL_UNSIGNED_INT, m_edgeIndices.data()); + } else { + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_COLOR_MATERIAL); + glShadeModel(GL_SMOOTH); + + glEnableClientState(GL_NORMAL_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, (float *)m_points.data()); + glNormalPointer(GL_FLOAT, 0, (float *)m_normals.data()); + glDrawElements(GL_TRIANGLES, m_pointIndices.size(), GL_UNSIGNED_INT, m_pointIndices.data()); + + glDisableClientState(GL_NORMAL_ARRAY); + glDisable(GL_COLOR_MATERIAL); + glDisable(GL_LIGHT0); + glDisable(GL_LIGHTING); + } + + if (normals) { + QVector normals; + for (int i = 0; i < m_normals.size(); ++i) + normals << m_points.at(i) << (m_points.at(i) + m_normals.at(i) * 0.02f); + glVertexPointer(3, GL_FLOAT, 0, (float *)normals.data()); + glDrawArrays(GL_LINES, 0, normals.size()); + } + glDisableClientState(GL_VERTEX_ARRAY); + glDisable(GL_DEPTH_TEST); +} + +void Model::render(QPainter *painter, const Matrix4x4 &matrix, bool normals) const +{ + QVector lines; + for (int i = 0; i < m_edgeIndices.size(); i += 2) + lines << QLineF((matrix * m_points.at(m_edgeIndices.at(i))).toQPoint(), + (matrix * m_points.at(m_edgeIndices.at(i+1))).toQPoint()); + + if (normals) { + for (int i = 0; i < m_normals.size(); ++i) + lines << QLineF((matrix * m_points.at(i)).toQPoint(), + (matrix * (m_points.at(i) + m_normals.at(i) * 0.02f)).toQPoint()); + } + + painter->drawLines(lines); +} -- cgit v1.2.3