|
From: Lasse Kärkkäi. <tr...@us...> - 2011-01-26 01:55:41
|
Module: performous
Branch: stereo3d
Commit: 770202d07ee2252d0399f341bcf8dac28840fb2b
Author: Lasse Karkkainen <tro...@tr...>
Date: Wed Jan 26 02:55:26 2011 +0100
Implement OpenGL matrix/transformation operations in C++ & use them in video_driver.
---
game/glmath.hh | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++
game/glutil.hh | 11 ++--
game/video_driver.cc | 14 +++--
3 files changed, 156 insertions(+), 12 deletions(-)
diff --git a/game/glmath.hh b/game/glmath.hh
new file mode 100644
index 0000000..675a3cf
--- /dev/null
+++ b/game/glmath.hh
@@ -0,0 +1,143 @@
+#pragma once
+
+#include <GL/glew.h>
+#include <cmath>
+#include <iomanip>
+#include <iostream>
+#include <stdexcept>
+#include <sstream>
+
+namespace glmath {
+
+ struct Vec3 {
+ GLdouble x, y, z;
+ explicit Vec3(double x = 0.0, double y = 0.0, double z = 0.0): x(x), y(y), z(z) {}
+ };
+
+ struct Vec4 {
+ GLdouble x, y, z, w;
+ explicit Vec4(double x = 0.0, double y = 0.0, double z = 0.0, double w = 0.0): x(x), y(y), z(z), w(w) {}
+ explicit Vec4(Vec3 const& v, double w = 1.0): x(v.x), y(v.y), z(v.z), w(w) {}
+ GLdouble& operator[](unsigned j) { return (&x)[j]; }
+ GLdouble const& operator[](unsigned j) const { return (&x)[j]; }
+ };
+
+ static inline Vec3 operator*(double k, Vec3 const& v) { return Vec3(k * v.x, k * v.y, k * v.z); }
+
+ static inline double dot(Vec3 const& a, Vec3 const& b) {
+ return a.x * b.x + a.y * b.y + a.z * b.z;
+ }
+
+ static inline double len(Vec3 const& v) { return std::sqrt(dot(v, v)); }
+ static inline Vec3 normalize(Vec3 const& v) { return (1 / len(v)) * v; }
+
+ struct Matrix {
+ Vec4 cols[4];
+ /// Identity matrix
+ Matrix() { for (unsigned k = 0; k < 4; ++k) cols[k][k] = 1.0; }
+ operator GLdouble*() { return &cols[0][0]; }
+ operator GLdouble const*() const { return &cols[0][0]; }
+ GLdouble& operator()(unsigned i, unsigned j) { return cols[j][i]; }
+ GLdouble const& operator()(unsigned i, unsigned j) const { return cols[j][i]; }
+ };
+
+ static inline std::ostream& operator<<(std::ostream& os, Matrix const& m) {
+ std::ostringstream oss;
+ oss << std::setprecision(3) << std::fixed;
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < 4; ++j) {
+ oss.width(7);
+ oss << m(i,j);
+ }
+ oss << '\n';
+ }
+ return os << oss.str() << std::endl;
+ }
+
+ static inline Matrix get(GLenum mode_matrix) {
+ Matrix ret;
+ glGetDoublev(mode_matrix, ret);
+ return ret;
+ }
+
+ static inline Matrix getMatrix() {
+ GLint mode;
+ glGetIntegerv(GL_MATRIX_MODE, &mode);
+ if (mode == GL_MODELVIEW) return get(GL_MODELVIEW_MATRIX);
+ if (mode == GL_PROJECTION) return get(GL_PROJECTION_MATRIX);
+ if (mode == GL_TEXTURE) return get(GL_TEXTURE_MATRIX);
+ throw std::logic_error("Unknown current matrix mode in glmath::get()");
+ }
+ static inline void upload(Matrix const& m) { glLoadMatrixd(m); }
+
+ static inline Matrix operator*(Matrix const& a, Matrix const& b) {
+ Matrix ret;
+ for (unsigned i = 0; i < 4; ++i) {
+ for (unsigned j = 0; j < 4; ++j) {
+ GLfloat sum = 0.0;
+ for (unsigned k = 0; k < 4; ++k) {
+ sum += a(i, k) * b(k, j);
+ }
+ ret(i, j) = sum;
+ }
+ }
+ return ret;
+ }
+
+ static inline Matrix translate(Vec3 const& v) {
+ Matrix ret;
+ ret(0,3) = v.x;
+ ret(1,3) = v.y;
+ ret(2,3) = v.z;
+ return ret;
+ }
+
+ static inline Matrix scale(Vec3 const& v) {
+ Matrix ret;
+ ret(0,0) = v.x;
+ ret(1,1) = v.y;
+ ret(2,2) = v.z;
+ return ret;
+ }
+
+ static inline Matrix scale(double k) { return scale(Vec3(k, k, k)); }
+
+ static inline Matrix rotate(double rad, Vec3 axis) {
+ Matrix ret;
+ Vec3 u = normalize(axis);
+ // Based on http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle
+ double s = std::sin(rad);
+ double c = std::cos(rad);
+ double nc = 1 - c;
+ // Column 0
+ ret(0,0) = c + u.x * u.x * nc;
+ ret(1,0) = u.y * u.x * nc + u.z * s;
+ ret(2,0) = u.z * u.x * nc - u.y * s;
+ // Column 1
+ ret(0,1) = u.x * u.y * nc - u.z * s;
+ ret(1,1) = c + u.y * u.y * nc;
+ ret(2,1) = u.z * u.y * nc + u.x * s;
+ // Column 2
+ ret(0,2) = u.x * u.z * nc + u.y * s;
+ ret(1,2) = u.y * u.z * nc - u.x * s;
+ ret(2,2) = c + u.z * u.z * nc;
+ return ret;
+ }
+
+ static inline Matrix frustum(double l, double r, double b, double t, double n, double f) {
+ double w = r - l;
+ double h = t - b;
+ double d = n - f;
+ Matrix ret;
+ ret(0,0) = 2 * n / w;
+ ret(1,1) = 2 * n / h;
+ ret(0,2) = (r + l) / w;
+ ret(1,2) = (t + b) / h;
+ ret(2,2) = (f + n) / d;
+ ret(3,2) = -1.0;
+ ret(2,3) = 2 * f * n / d;
+ ret(3,3) = 0.0;
+ return ret;
+ }
+}
+
diff --git a/game/glutil.hh b/game/glutil.hh
index f25abe1..781b757 100644
--- a/game/glutil.hh
+++ b/game/glutil.hh
@@ -1,13 +1,12 @@
#pragma once
-#include <string>
-#include <iostream>
-#include <vector>
-
-#include <GL/glew.h>
#include "color.hh"
#include "glshader.hh"
+#include <GL/glew.h>
+#include <string>
+#include <iostream>
+#include <vector>
namespace glutil {
@@ -206,6 +205,6 @@ namespace glutil {
}
static void reset() { glGetError(); }
};
-
}
+
diff --git a/game/video_driver.cc b/game/video_driver.cc
index eb505f1..54f677b 100644
--- a/game/video_driver.cc
+++ b/game/video_driver.cc
@@ -2,6 +2,7 @@
#include "config.hh"
#include "fs.hh"
+#include "glmath.hh"
#include "image.hh"
#include "util.hh"
#include "joystick.hh"
@@ -142,19 +143,20 @@ void Window::resize() {
glShadeModel(GL_SMOOTH);
glEnable(GL_BLEND);
// Setup the projection matrix for 2D translates
+ using namespace glmath;
glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
float h = virtH();
// OpenGL normalized coordinates go from -1 to 1, change scale so that our 2D translates can use the Performous normalized coordinates instead
- glScalef(2.0f, 2.0f / h, 1.0f);
+ upload(scale(Vec3(2.0f, 2.0f / h, 1.0f)));
// Note: we do the frustum on MODELVIEW so that 2D positioning can be done via projection matrix.
// glTranslatef on that will move the image, not the camera (i.e. far-away and nearby objects move the same amount)
glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- glScalef(0.5f, 0.5f * h, 1.0f); // Invert the scaling done on projection matrix
const float f = near_ / z0;
- glFrustum(-0.5f * f, 0.5f * f, 0.5f * h * f, -0.5f * h * f, near_, far_);
- glTranslatef(0.0f, 0.0f, -z0); // Move back the world so that z = 0.0f is the monitor surface
+ upload(
+ scale(Vec3(0.5, 0.5 * h, 1.0))
+ * frustum(-0.5f * f, 0.5f * f, 0.5f * h * f, -0.5f * h * f, near_, far_)
+ * translate(Vec3(0.0, 0.0, -z0))
+ );
// Check for OpenGL errors
glutil::GLErrorChecker glerror("Window::resize");
}
|