From 62cba89f0fbdad6d8c04711dc5f049ed4cb5d985 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 7 Feb 2010 17:21:10 +0000 Subject: [PATCH] Try to optimise LTree rendering a bit --- include/Maths.hpp | 1 + include/Matrix.hpp | 165 +++++++++++++++++++++++++++++++++++++++ include/OpenGLHelper.hpp | 18 +++++ src/LTree.cpp | 62 +++++++++++---- 4 files changed, 229 insertions(+), 17 deletions(-) create mode 100644 include/Matrix.hpp diff --git a/include/Maths.hpp b/include/Maths.hpp index 64c9a25..566669f 100644 --- a/include/Maths.hpp +++ b/include/Maths.hpp @@ -22,6 +22,7 @@ #include #include +#include // A generic 3D vector template diff --git a/include/Matrix.hpp b/include/Matrix.hpp new file mode 100644 index 0000000..b409d85 --- /dev/null +++ b/include/Matrix.hpp @@ -0,0 +1,165 @@ +// +// Copyright (C) 2010 Nick Gasson +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#ifndef INC_MATRIX_HPP +#define INC_MATRIX_HPP + +#include "Platform.hpp" +#include "Maths.hpp" + +#include +#include + +template +struct Matrix { + Matrix(const T data[N][N]) + { + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) + entries[i][j] = data[i][j]; + } + } + + Matrix() + { + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) + entries[i][j] = 0; + } + } + + Matrix(const Matrix& rhs) + { + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) + entries[i][j] = rhs.entries[i][j]; + } + } + + // TODO: these factories should work for N != 4 + + static Matrix identity() + { + const T data[4][4] = { + { 1, 0, 0, 0 }, + { 0, 1, 0, 0 }, + { 0, 0, 1, 0 }, + { 0, 0, 0, 1 } + }; + return Matrix(data); + } + + static Matrix translation(T x, T y, T z) + { + const T data[4][4] = { + { 1, 0, 0, x }, + { 0, 1, 0, y }, + { 0, 0, 1, z }, + { 0, 0, 0, 1 } + }; + return Matrix(data); + } + + static Matrix rotation(float a, int x, int y, int z) + { + a *= M_PI / 180; + + assert(x + y + z == 1); + + if (x == 1) { + const T data[4][4] = { + { 1, 0, 0, 0 }, + { 0, cos(a), -sin(a), 0 }, + { 0, sin(a), cos(a), 0 }, + { 0, 0, 0, 1 } + }; + return Matrix(data); + } + else if (y == 1) { + const T data[4][4] = { + { cos(a), 0, sin(a), 0 }, + { 0, 1, 0, 0 }, + { -sin(a), 0, cos(a), 0 }, + { 0, 0, 0, 1 } + }; + return Matrix(data); + } + else if (z == 1) { + const T data[4][4] = { + { cos(a), -sin(a), 0, 0 }, + { sin(a), cos(a), 0, 0 }, + { 0, 0, 1, 0 }, + { 0, 0, 0, 1 } + }; + return Matrix(data); + } + else + assert(false); + } + + Vector transform(const Vector& v) const + { + assert(N == 4); + + T vCols[4] = { v.x, v.y, v.z, 1 }; + T cols[4]; + for (int i = 0; i < N; i++) { + cols[i] = 0; + for (int j = 0; j < N; j++) + cols[i] += entries[i][j] * vCols[j]; + } + + return makeVector(cols[0], cols[1], cols[2]); + } + + Matrix& operator*=(const Matrix& rhs) + { + return *this = *this * rhs; + } + + Matrix operator*(const Matrix& rhs) const + { + // Lame matrix multiplication algorithm + T c[N][N]; + + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + c[i][j] = 0; + for (int k = 0; k < N; k++) + c[i][j] += entries[i][k] * rhs.entries[k][j]; + } + } + + return Matrix(c); + } + + T entries[N][N]; // Square matrices only +}; + +template +ostream& operator<<(ostream& os, const Matrix& m) +{ + for (int i = 0; i < N; i++) { + os << endl; + for (int j = 0; j < N; j++) + os << m.entries[i][j] << " "; + } + return os; +} + +#endif + diff --git a/include/OpenGLHelper.hpp b/include/OpenGLHelper.hpp index 84a24ed..f3df72b 100644 --- a/include/OpenGLHelper.hpp +++ b/include/OpenGLHelper.hpp @@ -54,6 +54,24 @@ namespace gl { { glTranslatef(v.x, v.y, v.z); } + + template + inline void vertex(const Vector& v); + + template <> + inline void vertex(const Vector& v) + { + glVertex3f(v.x, v.y, v.z); + } + + template + inline void normal(const Vector& v); + + template <> + inline void normal(const Vector& v) + { + glNormal3f(v.x, v.y, v.z); + } } #endif diff --git a/src/LTree.cpp b/src/LTree.cpp index b06378f..e2c6022 100644 --- a/src/LTree.cpp +++ b/src/LTree.cpp @@ -19,6 +19,7 @@ #include "ILogger.hpp" #include "Random.hpp" #include "OpenGLHelper.hpp" +#include "Matrix.hpp" #include #include @@ -135,13 +136,16 @@ private: RenderState() { widthStack.push(3.5f); + mStack.push(Matrix::identity()); } stack widthStack; + stack > mStack; }; void interpret(Token t, RenderState& rs) const; void renderToDisplayList() const; + int countLines() const; LSystem ls; Vector position; @@ -153,16 +157,15 @@ private: const Rule LTree::rules[] = { Rule(X, "F-[[X]+X]+F[+FX]-X"), - Rule(X, "F-[[X]+X]+FF[+FX]-X"), Rule(X, "F+[[X]-X]-F[-FX]+X"), - Rule(X, "+[[X]-X]-F[-FX]+X"), + //Rule(X, "+[[X]-X]-F[-FX]+X"), Rule(F, "FF"), }; LTree::LTree() : ls(rules, sizeof(rules) / sizeof(Rule), X) { - const int N_GENERATIONS = 5; + const int N_GENERATIONS = 4; //debug() << "Initial: " << ls; for (int n = 0; n < N_GENERATIONS; n++) { @@ -170,8 +173,12 @@ LTree::LTree() //debug() << "n=" << n << ": " << ls; } + //debug() << ls; + displayList = glGenLists(1); renderToDisplayList(); + + debug() << "LTree has " << countLines() << " lines"; } LTree::~LTree() @@ -181,19 +188,29 @@ LTree::~LTree() void LTree::interpret(Token t, RenderState& rs) const { - const float SEGMENT_LEN = 0.025f; + const float SEGMENT_LEN = 0.07f; const float LEAF_LEN = 0.1f; + + Matrix& m = rs.mStack.top(); switch (t) { case 'F': - glLineWidth(rs.widthStack.top()); - glBegin(GL_LINES); { - glVertex3f(0.0f, 0.0f, 0.0f); - glVertex3f(0.0f, SEGMENT_LEN, 0.0f); + Vector v1 = m.transform(makeVector(0.0f, 0.0f, 0.0f)); + Vector v2 = m.transform(makeVector(0.0f, SEGMENT_LEN, 0.0f)); + Vector n = m.transform(makeVector(0.0f, 1.0f, 0.0f)); + n.normalise(); + + //glLineWidth(rs.widthStack.top()); + glBegin(GL_LINES); + { + gl::normal(n); + gl::vertex(v1); + gl::vertex(v2); + } + glEnd(); } - glEnd(); - glTranslatef(0.0f, SEGMENT_LEN, 0.0f); + m *= Matrix::translation(0.0f, SEGMENT_LEN, 0.0f); break; case 'X': /*glPushAttrib(GL_CURRENT_BIT); @@ -206,20 +223,20 @@ void LTree::interpret(Token t, RenderState& rs) const glPopAttrib();*/ break; case '-': - glRotatef(25.0, 0.0f, 0.0f, 1.0f); - glRotatef(25.0, 0.0f, 1.0f, 0.0f); + m *= Matrix::rotation(25.0f, 0, 0, 1); + m *= Matrix::rotation(25.0f, 0, 1, 0); break; - case '+': - glRotatef(-25.0, 0.0f, 0.0f, 1.0f); - glRotatef(-25.0, 0.0f, 1.0f, 0.0f); + case '+': + m *= Matrix::rotation(-25.0f, 0, 0, 1); + m *= Matrix::rotation(-25.0f, 0, 1, 0); break; case '[': rs.widthStack.push(rs.widthStack.top() * 0.8f); - glPushMatrix(); + rs.mStack.push(m); break; case ']': rs.widthStack.pop(); - glPopMatrix(); + rs.mStack.pop(); break; default: { @@ -273,6 +290,17 @@ void LTree::setPosition(float x, float y, float z) position.z = z; } +int LTree::countLines() const +{ + int count = 0; + for (TokenList::const_iterator it = ls.state.begin(); + it != ls.state.end(); ++it) + if (*it == 'F') + ++count; + + return count; +} + ISceneryPtr makeLTree() { return ISceneryPtr(new LTree); -- 2.39.2