vsg 1.1.3
VulkanSceneGraph library
Loading...
Searching...
No Matches
State.h
1#pragma once
2
3/* <editor-fold desc="MIT License">
4
5Copyright(c) 2018 Robert Osfield
6
7Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8
9The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10
11THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12
13</editor-fold> */
14
15#include <vsg/maths/plane.h>
16#include <vsg/maths/transform.h>
17#include <vsg/nodes/MatrixTransform.h>
18#include <vsg/state/PushConstants.h>
19#include <vsg/vk/CommandBuffer.h>
20
21#include <array>
22#include <map>
23#include <stack>
24
25namespace vsg
26{
27
28#define POLYTOPE_SIZE 5
29
31 template<class T>
33 {
34 public:
35 StateStack() :
36 dirty(false) {}
37
38 using Stack = std::stack<ref_ptr<const T>>;
39 Stack stack;
40 bool dirty;
41
42 template<class R>
43 inline void push(ref_ptr<R> value)
44 {
45 stack.push(value);
46 dirty = true;
47 }
48
49 template<class R>
50 inline void push(R* value)
51 {
52 stack.push(ref_ptr<const T>(value));
53 dirty = true;
54 }
55
56 inline void pop()
57 {
58 stack.pop();
59 dirty = !stack.empty();
60 }
61 size_t size() const { return stack.size(); }
62 const T* top() const { return stack.top(); }
63
64 inline void record(CommandBuffer& commandBuffer)
65 {
66 if (dirty)
67 {
68 stack.top()->record(commandBuffer);
69 dirty = false;
70 }
71 }
72 };
73
76 {
77 public:
78 MatrixStack(uint32_t in_offset = 0) :
79 offset(in_offset)
80 {
81 // make sure there is an initial matrix
82 matrixStack.emplace(dmat4());
83 dirty = true;
84 }
85
86 using value_type = double;
87
88 std::stack<dmat4> matrixStack;
89 uint32_t offset = 0;
90 bool dirty = false;
91
92 inline void set(const mat4& matrix)
93 {
94 matrixStack = {};
95 matrixStack.emplace(matrix);
96 dirty = true;
97 }
98
99 inline void set(const dmat4& matrix)
100 {
101 matrixStack = {};
102 matrixStack.emplace(matrix);
103 dirty = true;
104 }
105
106 inline void push(const mat4& matrix)
107 {
108 matrixStack.emplace(matrix);
109 dirty = true;
110 }
111 inline void push(const dmat4& matrix)
112 {
113 matrixStack.emplace(matrix);
114 dirty = true;
115 }
116 inline void push(const Transform& transform)
117 {
118 matrixStack.emplace(transform.transform(matrixStack.top()));
119 dirty = true;
120 }
121
122 inline void push(const MatrixTransform& transform)
123 {
124 matrixStack.emplace(matrixStack.top() * transform.matrix);
125 dirty = true;
126 }
127
128 const dmat4& top() const { return matrixStack.top(); }
129
130 inline void pop()
131 {
132 matrixStack.pop();
133 dirty = true;
134 }
135
136 inline void record(CommandBuffer& commandBuffer)
137 {
138 if (dirty)
139 {
140 auto pipeline = commandBuffer.getCurrentPipelineLayout();
141 auto stageFlags = commandBuffer.getCurrentPushConstantStageFlags();
142
143 // don't attempt to push matrices if no pipeline is current or no stages are enabled for push constants
144 if (pipeline == 0 || stageFlags == 0)
145 {
146 return;
147 }
148
149 // make sure matrix is a float matrix.
150 mat4 newmatrix(matrixStack.top());
151 vkCmdPushConstants(commandBuffer, pipeline, stageFlags, offset, sizeof(newmatrix), newmatrix.data());
152 dirty = false;
153 }
154 }
155 };
156
158 struct Frustum
159 {
160 using value_type = MatrixStack::value_type;
163 Plane face[POLYTOPE_SIZE];
164 Vector lodScale;
165
166 Frustum()
167 {
168 face[0].set(1.0, 0.0, 0.0, 1.0); // left plane
169 face[1].set(-1.0, 0.0, 0.0, 1.0); // right plane
170 face[2].set(0.0, -1.0, 0.0, 1.0); // bottom plane
171 face[3].set(0.0, 1.0, 0.0, 1.0); // top plane
172 if constexpr (POLYTOPE_SIZE >= 5) face[4].set(0.0, 0.0, 1.0, 0.0); // far plane
173 if constexpr (POLYTOPE_SIZE >= 6) face[5].set(0.0, 0.0, -1.0, 1.0); // near plane
174 }
175
176 template<class M>
177 Frustum(const Frustum& pt, const M& matrix)
178 {
179 face[0] = pt.face[0] * matrix;
180 face[1] = pt.face[1] * matrix;
181 face[2] = pt.face[2] * matrix;
182 face[3] = pt.face[3] * matrix;
183 if constexpr (POLYTOPE_SIZE >= 5) face[4] = pt.face[4] * matrix;
184 if constexpr (POLYTOPE_SIZE >= 6) face[5] = pt.face[5] * matrix;
185 }
186
187 template<class M>
188 void set(const Frustum& pt, const M& matrix)
189 {
190 face[0] = pt.face[0] * matrix;
191 face[1] = pt.face[1] * matrix;
192 face[2] = pt.face[2] * matrix;
193 face[3] = pt.face[3] * matrix;
194 if constexpr (POLYTOPE_SIZE >= 5) face[4] = pt.face[4] * matrix;
195 if constexpr (POLYTOPE_SIZE >= 6) face[5] = pt.face[5] * matrix;
196 }
197
198 template<class M>
199 void computeLodScale(const M& proj, const M& mv)
200 {
201 value_type f = -proj[1][1];
202 value_type sc = f * std::sqrt(square(mv[0][0]) + square(mv[1][0]) + square(mv[2][0]) + square(mv[0][1]) + square(mv[1][1]) + square(mv[2][1])) * 0.5;
203 value_type inv_scale = value_type(1.0) / sc;
204 lodScale.set(mv[0][2] * inv_scale,
205 mv[1][2] * inv_scale,
206 mv[2][2] * inv_scale,
207 mv[3][2] * inv_scale);
208 }
209
210 template<typename T>
211 bool intersect(const t_sphere<T>& s) const
212 {
213 auto negative_radius = -s.radius;
214 if (distance(face[0], s.center) < negative_radius) return false;
215 if (distance(face[1], s.center) < negative_radius) return false;
216 if (distance(face[2], s.center) < negative_radius) return false;
217 if (distance(face[3], s.center) < negative_radius) return false;
218 if constexpr (POLYTOPE_SIZE >= 5)
219 if (distance(face[4], s.center) < negative_radius) return false;
220 if constexpr (POLYTOPE_SIZE >= 6)
221 if (distance(face[5], s.center) < negative_radius) return false;
222 return true;
223 }
224 };
225
227 class State : public Inherit<Object, State>
228 {
229 public:
230 explicit State(uint32_t maxSlot) :
231 dirty(false),
232 stateStacks(maxSlot + 1)
233 {
234 }
235
236 using StateStacks = std::vector<StateStack<StateCommand>>;
237
238 ref_ptr<CommandBuffer> _commandBuffer;
239
240 Frustum _frustumUnit;
241 Frustum _frustumProjected;
242
243 using FrustumStack = std::stack<Frustum>;
244 FrustumStack _frustumStack;
245
246 bool dirty = true;
247
248 bool inheritViewForLODScaling = false;
249 dmat4 inheritedProjectionMatrix;
250 dmat4 inheritedViewMatrix;
251 dmat4 inheritedViewTransform;
252
253 StateStacks stateStacks;
254
255 MatrixStack projectionMatrixStack{0};
256 MatrixStack modelviewMatrixStack{64};
257
258 void setInhertiedViewProjectionAndViewMatrix(const dmat4& projMatrix, const dmat4& viewMatrix)
259 {
260 inheritedProjectionMatrix = projMatrix;
261 inheritedViewMatrix = viewMatrix;
262 }
263
264 void setProjectionAndViewMatrix(const dmat4& projMatrix, const dmat4& viewMatrix)
265 {
266 projectionMatrixStack.set(projMatrix);
267
268 const auto& proj = projectionMatrixStack.top();
269
270 _frustumProjected.set(_frustumUnit, proj);
271
272 modelviewMatrixStack.set(viewMatrix);
273
274 // clear frustum stack
275 while (!_frustumStack.empty()) _frustumStack.pop();
276
277 if (inheritViewForLODScaling)
278 {
279 inheritedViewTransform = inheritedViewMatrix * inverse(viewMatrix);
280 }
281
282 // push frustum in world coords
283 pushFrustum();
284 }
285
286 inline void record()
287 {
288 if (dirty)
289 {
290 for (auto& stateStack : stateStacks)
291 {
292 stateStack.record(*_commandBuffer);
293 }
294
295 projectionMatrixStack.record(*_commandBuffer);
296 modelviewMatrixStack.record(*_commandBuffer);
297
298 dirty = false;
299 }
300 }
301
302 inline void pushFrustum()
303 {
304 _frustumStack.push(Frustum(_frustumProjected, modelviewMatrixStack.top()));
305 if (inheritViewForLODScaling)
306 _frustumStack.top().computeLodScale(inheritedProjectionMatrix, inheritedViewTransform * modelviewMatrixStack.top());
307 else
308 _frustumStack.top().computeLodScale(projectionMatrixStack.top(), modelviewMatrixStack.top());
309 }
310
311 inline void applyFrustum()
312 {
313 _frustumStack.top().set(_frustumProjected, modelviewMatrixStack.top());
314 _frustumStack.top().computeLodScale(projectionMatrixStack.top(), modelviewMatrixStack.top());
315 }
316
317 inline void popFrustum()
318 {
319 _frustumStack.pop();
320 }
321
322 template<typename T>
323 bool intersect(const t_sphere<T>& s) const
324 {
325 return _frustumStack.top().intersect(s);
326 }
327
328 template<typename T>
329 T lodDistance(const t_sphere<T>& s) const
330 {
331 const auto& frustum = _frustumStack.top();
332 if (!frustum.intersect(s)) return -1.0;
333
334 const auto& lodScale = frustum.lodScale;
335 return std::abs(lodScale[0] * s.x + lodScale[1] * s.y + lodScale[2] * s.z + lodScale[3]);
336 }
337 };
338
339} // namespace vsg
CommandBuffer encapsulates VkCommandBuffer.
Definition CommandBuffer.h:27
Definition Inherit.h:28
MatrixStack used internally by vsg::State to manage stack of projection or modelview matrices.
Definition State.h:76
Definition MatrixTransform.h:24
vsg::State is used by vsg::RecordTraversal to manage state stacks, projection and modelview matrices ...
Definition State.h:228
StateStack used internally by vsg::State to manage stack of vsg::StateCommand.
Definition State.h:33
Transform node is a pure virtual base class for positioning/scaling/rotating subgraphs.
Definition Transform.h:22
Definition ref_ptr.h:22
Frustum used internally by vsg::State to manage view fustum culling during vsg::RecordTraversal.
Definition State.h:159
template sphere class
Definition sphere.h:34