diff options
author | Samuel Rødal <sroedal@trolltech.com> | 2008-06-23 10:01:08 +0200 |
---|---|---|
committer | Samuel Rødal <sroedal@trolltech.com> | 2008-06-23 10:01:08 +0200 |
commit | 3984206b94c0cf6ddf332caf2a0679fe28e7f865 (patch) | |
tree | c32939358e2221986cb3d7b2ef628a54d2046de6 | |
parent | 8b44c875279603745a02ac3b80f83806a4bfbfc6 (diff) |
Added some more controls.
-rw-r--r-- | main.cpp | 100 | ||||
-rw-r--r-- | model.cpp | 118 | ||||
-rw-r--r-- | model.h | 13 |
3 files changed, 208 insertions, 23 deletions
@@ -17,10 +17,21 @@ public: public slots: void setModel(Model *model); + void enableAutoRotate(bool enabled); void enableWireframe(bool enabled); + void enableNormals(bool enabled); + void setLightPosition(int pos); + void setColor(QRgb color); private: bool m_wireframeEnabled; + bool m_normalsEnabled; + bool m_autoRotate; + + float m_angle; + float m_lightPos; + + QRgb m_color; Model *m_model; }; @@ -35,19 +46,24 @@ public: private slots: void loadModel(const QString &model); void modelLoaded(); + void setColor(bool showDialog = true); private: GraphicsScene *m_scene; QFutureWatcher<Model *> m_modelLoader; QComboBox *m_models; + QRgb m_color; }; Controls::Controls(GraphicsScene *scene) : m_scene(scene) , m_models(new QComboBox) + , m_color(qRgb(180, 100, 255)) { QVBoxLayout *layout = new QVBoxLayout(this); + layout->addWidget(new QLabel("Model:")); + QDir dir("models"); dir.setNameFilters(QStringList() << "*.obj"); m_models->addItems(dir.entryList()); @@ -56,14 +72,35 @@ Controls::Controls(GraphicsScene *scene) if (m_models->count() > 0) loadModel(m_models->currentText()); - layout->addWidget(m_models); - QCheckBox *wireframe = new QCheckBox("Wireframe"); + QCheckBox *autoRotate = new QCheckBox("Auto-rotate"); + autoRotate->setChecked(true); + connect(autoRotate, SIGNAL(toggled(bool)), m_scene, SLOT(enableAutoRotate(bool))); + layout->addWidget(autoRotate); + + QCheckBox *wireframe = new QCheckBox("Render as wireframe"); wireframe->setChecked(true); connect(wireframe, SIGNAL(toggled(bool)), m_scene, SLOT(enableWireframe(bool))); - layout->addWidget(wireframe); + + QCheckBox *normals = new QCheckBox("Display normals vectors"); + wireframe->setChecked(false); + connect(normals, SIGNAL(toggled(bool)), m_scene, SLOT(enableNormals(bool))); + layout->addWidget(normals); + + layout->addWidget(new QLabel("Light position:")); + QSlider *lightPosition = new QSlider(Qt::Horizontal); + lightPosition->setRange(-1000, 1000); + connect(lightPosition, SIGNAL(valueChanged(int)), m_scene, SLOT(setLightPosition(int))); + layout->addWidget(lightPosition); + + m_scene->setLightPosition(lightPosition->value()); + + QPushButton *colorButton = new QPushButton("Set model color"); + connect(colorButton, SIGNAL(pressed()), this, SLOT(setColor())); + layout->addWidget(colorButton); + setColor(false); } Model *loadModel(const QString &filename) @@ -85,15 +122,26 @@ void Controls::modelLoaded() QApplication::restoreOverrideCursor(); } +void Controls::setColor(bool showDialog) +{ + if (showDialog) + m_color = QColorDialog::getRgba(m_color); + + m_scene->setColor(m_color); +} + GraphicsScene::GraphicsScene() : m_wireframeEnabled(true) + , m_normalsEnabled(false) + , m_autoRotate(true) + , m_angle(0) , m_model(0) { Controls *controls = new Controls(this); controls->setWindowOpacity(0.8); addWidget(controls)->translate(10, 10); - setSceneRect(QRect(0, 0, 800, 600)); + setSceneRect(QRect(0, 0, 1024, 768)); } void GraphicsScene::drawBackground(QPainter *painter, const QRectF &) @@ -101,7 +149,7 @@ void GraphicsScene::drawBackground(QPainter *painter, const QRectF &) painter->save(); glClearColor(1, 1, 1, 1); - glClear(GL_COLOR_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); bool useMultisample = static_cast<QGLWidget *>(painter->device())->format().sampleBuffers(); @@ -109,21 +157,26 @@ void GraphicsScene::drawBackground(QPainter *painter, const QRectF &) glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); - glOrtho(-1, 1, 1, -1, -10, 10); + gluPerspective(70, painter->device()->width() / float(painter->device()->height()), 0.01, 1000); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); + float pos[] = { m_lightPos, 5, 2, 0 }; + glLightfv(GL_LIGHT0, GL_POSITION, pos); + glColor4f(qRed(m_color)/255.0f, qGreen(m_color)/255.0f, qBlue(m_color)/255.0f, 1.0f); + if (useMultisample) glEnable(GL_MULTISAMPLE); - static float rot = 0; - glRotatef(rot, 0, 1, 0); - rot += 0.1; + glTranslatef(0, 0, -1.5); + glRotatef(m_angle, 0.5, 1, 0.1); + + if (m_autoRotate) + m_angle += 0.4; - glColor3f(0, 0, 0); - m_model->render(m_wireframeEnabled); + m_model->render(m_wireframeEnabled, m_normalsEnabled); if (useMultisample) glDisable(GL_MULTISAMPLE); @@ -136,7 +189,7 @@ void GraphicsScene::drawBackground(QPainter *painter, const QRectF &) painter->restore(); - update(); + QTimer::singleShot(20, this, SLOT(update())); } void GraphicsScene::setModel(Model *model) @@ -146,11 +199,34 @@ void GraphicsScene::setModel(Model *model) update(); } +void GraphicsScene::enableAutoRotate(bool enabled) +{ + m_autoRotate = enabled; + update(); +} + void GraphicsScene::enableWireframe(bool enabled) { m_wireframeEnabled = enabled; } +void GraphicsScene::enableNormals(bool enabled) +{ + m_normalsEnabled = enabled; +} + +void GraphicsScene::setLightPosition(int pos) +{ + m_lightPos = pos * 0.005; + update(); +} + +void GraphicsScene::setColor(QRgb color) +{ + m_color = color; + update(); +} + int main(int argc, char **argv) { QApplication app(argc, argv); @@ -45,9 +45,6 @@ Model::Model(const QString &filename) QVector<Point3d> pointData; QVector<Point3d> normalData; - QVector<int> pointIndices; - QVector<int> normalIndices; - QTextStream in(&file); while (!in.atEnd()) { QString input = in.readLine(); @@ -63,6 +60,7 @@ Model::Model(const QString &filename) Point3d p = readPoint(ts); p.y = -p.y; pointData << p; + normalData << Point3d(); min.x = qMin(min.x, p.x); min.y = qMin(min.y, p.y); @@ -91,13 +89,26 @@ Model::Model(const QString &filename) } for (int i = 0; i < 3; ++i) - pointIndices << p[i]; + m_pointIndices << p[i]; if (p.size() == 4) for (int i = 0; i < 3; ++i) - pointIndices << p[(i + 2) % 4]; + m_pointIndices << p[(i + 2) % 4]; + } + } + +#if 0 + for (int i = 0; i < m_pointIndices.size(); ++i) { + Point3d p1 = pointData.at(m_pointIndices.at(i)); + for (int j = 0; j < m_pointIndices.at(i); ++j) { + Point3d p2 = pointData.at(j); + if (p1.x == p2.x && p1.y == p2.y && p1.z == p2.z) { + m_pointIndices[i] = j; + break; + } } } +#endif Point3d bounds = max - min; qreal scale = 1 / qMax(bounds.x, qMax(bounds.y, bounds.z)); @@ -114,22 +125,109 @@ Model::Model(const QString &filename) p.z *= scale; } - for (int i = 0; i < pointIndices.size(); ++i) - m_points << pointData.at(pointIndices.at(i)); + QVector<int> counts(normalData.size()); + + for (int i = 0; i < counts.size(); ++i) + counts[i] = 0; + + for (int i = 0; i < m_pointIndices.size(); i += 3) { + const Point3d a = pointData.at(m_pointIndices.at(i)); + const Point3d b = pointData.at(m_pointIndices.at(i+1)); + const Point3d c = pointData.at(m_pointIndices.at(i+2)); + + Point3d normal = cross(c - a, b - a).normalize(); + + for (int j = 0; j < 3; ++j) { + Point3d old = normalData.at(m_pointIndices.at(i + j)); + normalData[m_pointIndices.at(i + j)] = old + normal; + ++counts[m_pointIndices.at(i + j)]; + } + } + + for (int i = 0; i < normalData.size(); ++i) { + float r = 1. / counts.at(i); + normalData[i] = normalData.at(i) * r;//.normalize(); + } + +#if 0 + Point3d normal; + for (int i = 0; i < m_pointIndices.size(); ++i) { +#if 0 + if ((i % 3) == 0) { + Point3d a = pointData.at(m_pointIndices.at(i)); + Point3d b = pointData.at(m_pointIndices.at(i+1)); + Point3d c = pointData.at(m_pointIndices.at(i+2)); + + normal = cross(c - a, b - a).normalize(); + + //float len = normal.x * normal.x +normal.y * normal.y +normal.z * normal.z; + } +#endif + + m_points << pointData.at(m_pointIndices.at(i)); + m_normals << normalData.at(m_pointIndices.at(i)).normalize(); + +#if 0 + Point3d p = m_points.last(); + Point3d n = m_normals.last(); + + printf("Index: %d, point: %f %f %f, normal: %f %f %f\n", m_pointIndices.at(i), + p.x, p.y, p.z, + n.x, n.y, n.z); +#endif + } +#endif + + m_points = pointData; + m_normals = normalData; foreach(const Edge &edge, QVector<Edge>::fromList(edges.toList())) m_edges << pointData.at(edge.pointA) << pointData.at(edge.pointB); } -void Model::render(bool wireframe) const +void Model::render(bool wireframe, bool normals) const { glEnableClientState(GL_VERTEX_ARRAY); if (wireframe) { + glColor3f(0, 0, 0); glVertexPointer(3, GL_FLOAT, 0, m_edges.data()); glDrawArrays(GL_LINES, 0, m_edges.size()); } else { - glVertexPointer(3, GL_FLOAT, 0, m_points.data()); - glDrawArrays(GL_TRIANGLES, 0, m_points.size()); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_COLOR_MATERIAL); + + glShadeModel(GL_SMOOTH); + + glEnable(GL_DEPTH_TEST); + + 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_DEPTH_TEST); + + glDisable(GL_COLOR_MATERIAL); + glDisable(GL_LIGHT0); + glDisable(GL_LIGHTING); } glDisableClientState(GL_VERTEX_ARRAY); + + if (normals) { + glColor3f(1, 0, 0); + glBegin(GL_LINES); + for (int i = 0; i < m_normals.size(); ++i) { + Point3d a = m_points.at(i); + Point3d b = m_points.at(i) + m_normals.at(i) * 0.02; + glVertex3f(a.x, a.y, a.z); + glVertex3f(b.x, b.y, b.z); + } + glEnd(); + } } + @@ -28,11 +28,21 @@ struct Point3d return Point3d(x - p.x, y - p.y, z - p.z); } + Point3d operator+(const Point3d &p) const + { + return Point3d(x + p.x, y + p.y, z + p.z); + } + Point3d normalize() const { float r = 1. / sqrt(x * x + y * y + z * z); return Point3d(x * r, y * r, z * r); } + + Point3d operator*(float f) const + { + return Point3d(x * f, y * f, z * f); + } }; inline float dot(const Point3d &a, const Point3d &b) @@ -52,12 +62,13 @@ class Model public: Model(const QString &filename); - void render(bool wireframe = false) const; + void render(bool wireframe = false, bool normals = false) const; private: QVector<Point3d> m_points; QVector<Point3d> m_normals; QVector<Point3d> m_edges; + QVector<int> m_pointIndices; }; #endif |