Overte C++ Documentation
MatrixStack.h
1 //
2 // Created by Bradley Austin Davis
3 // Copyright 2013 High Fidelity, Inc.
4 //
5 // Distributed under the Apache License, Version 2.0.
6 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
7 //
8 
9 #pragma once
10 #include <glm/glm.hpp>
11 #include <glm/gtc/matrix_transform.hpp>
12 #include <glm/gtc/type_ptr.hpp>
13 #include <glm/gtc/noise.hpp>
14 #include <glm/gtc/epsilon.hpp>
15 #include <glm/gtc/matrix_transform.hpp>
16 #include <stack>
17 
18 class MatrixStack : public std::stack<glm::mat4> {
19 
20 public:
21 
22  MatrixStack() {
23  push(glm::mat4());
24  }
25 
26  explicit MatrixStack(const MatrixStack& other) : std::stack<glm::mat4>() {
27  *((std::stack<glm::mat4>*)this) = *((std::stack<glm::mat4>*)&other);
28  }
29 
30  operator const glm::mat4 & () const {
31  return top();
32  }
33 
34  MatrixStack & pop() {
35  std::stack<glm::mat4>::pop();
36  assert(!empty());
37  return *this;
38  }
39 
40  MatrixStack & push() {
41  emplace(top());
42  return *this;
43  }
44 
45  MatrixStack & identity() {
46  top() = glm::mat4();
47  return *this;
48  }
49 
50  MatrixStack & push(const glm::mat4 & mat) {
51  std::stack<glm::mat4>::push(mat);
52  return *this;
53  }
54 
55  MatrixStack & rotate(const glm::mat3 & rotation) {
56  return postMultiply(glm::mat4(rotation));
57  }
58 
59  MatrixStack & rotate(const glm::quat & rotation) {
60  return postMultiply(glm::mat4_cast(rotation));
61  }
62 
63  MatrixStack & rotate(float theta, const glm::vec3 & axis) {
64  return postMultiply(glm::rotate(glm::mat4(), theta, axis));
65  }
66 
67  MatrixStack & translate(float translation) {
68  return translate(glm::vec3(translation, 0, 0));
69  }
70 
71  MatrixStack & translate(const glm::vec2 & translation) {
72  return translate(glm::vec3(translation, 0));
73  }
74 
75  MatrixStack & translate(const glm::vec3 & translation) {
76  return postMultiply(glm::translate(glm::mat4(), translation));
77  }
78 
79  MatrixStack & preTranslate(const glm::vec3 & translation) {
80  return preMultiply(glm::translate(glm::mat4(), translation));
81  }
82 
83 
84  MatrixStack & scale(float factor) {
85  return scale(glm::vec3(factor));
86  }
87 
88  MatrixStack & scale(const glm::vec3 & scale) {
89  return postMultiply(glm::scale(glm::mat4(), scale));
90  }
91 
92  MatrixStack & transform(const glm::mat4 & xfm) {
93  return postMultiply(xfm);
94  }
95 
96  MatrixStack & preMultiply(const glm::mat4 & xfm) {
97  top() = xfm * top();
98  return *this;
99  }
100 
101  MatrixStack & postMultiply(const glm::mat4 & xfm) {
102  top() *= xfm;
103  return *this;
104  }
105 
106  // Remove the rotation component of a matrix. useful for billboarding
107  MatrixStack & unrotate() {
108  glm::quat inverse = glm::inverse(glm::quat_cast(top()));
109  top() = top() * glm::mat4_cast(inverse);
110  return *this;
111  }
112 
113  // Remove the translation component of a matrix. useful for skyboxing
114  MatrixStack & untranslate() {
115  top()[3] = glm::vec4(0, 0, 0, 1);
116  return *this;
117  }
118 
119  template <typename Function>
120  void withPush(Function f) {
121  #ifndef NDEBUG
122  size_t startingDepth = size();
123  #endif
124  push();
125  f();
126  pop();
127  #ifndef NDEBUG
128  assert(startingDepth == size());
129  #endif
130  }
131 
132  template <typename Function>
133  void withIdentity(Function f) {
134  withPush([&] {
135  identity();
136  f();
137  });
138  }
139 
140  static MatrixStack & projection() {
141  static MatrixStack projection;
142  return projection;
143  }
144 
145  static MatrixStack & modelview() {
146  static MatrixStack modelview;
147  return modelview;
148  }
149 
150  template <typename Function>
151  static void withPushAll(Function f) {
152  withPush(projection(), modelview(), f);
153  }
154 
155  template <typename Function>
156  static void withIdentityAll(Function f) {
157  withPush(projection(), modelview(), [=] {
158  projection().identity();
159  modelview().identity();
160  f();
161  });
162  }
163 
164  template <typename Function>
165  static void withPush(MatrixStack& stack, Function f) {
166  stack.withPush(f);
167  }
168 
169  template <typename Function>
170  static void withPush(MatrixStack& stack1, MatrixStack& stack2, Function f) {
171  stack1.withPush([&]{
172  stack2.withPush(f);
173  });
174  }
175 };
176