vsg: include/vsg/vk/State.h Source File

vsg 1.1.13 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 <stack>
23
24namespace vsg
25{
26
27#define POLYTOPE_SIZE 5
28#define STATESTACK_SIZE 16
29
31 template<class T>
32 class StateStack
33 {
34 public:
35 StateStack() = default;
36 StateStack(const StateStack& rhs) = default;
37
38 using Stack = std::array<const T*, STATESTACK_SIZE>;
39 Stack stack;
40 size_t pos = 0;
41
42 StateStack& operator=(const StateStack& rhs)
43 {
44 stack = rhs.stack;
45 pos = rhs.pos;
46 dirty();
47
48 return *this;
49 }
50
51 inline void reset()
52 {
53 pos = 0;
54 stack[0] = nullptr;
55 }
56
57 inline void dirty()
58 {
59 stack[0] = nullptr;
60 }
61
62 inline void push(const T* value)
63 {
64 stack[++pos] = value;
65 }
66
67 inline void pop()
68 {
69 --pos;
70 }
71
72 bool empty() const { return pos == 0; }
73 size_t size() const { return pos; }
74 const T* top() const { return stack[pos]; }
75
76 inline void record(CommandBuffer& commandBuffer)
77 {
78 const T* current = stack[pos];
79 if (current != stack[0])
80 {
81 current->record(commandBuffer);
82 stack[0] = current;
83 }
84 }
85 };
86
88 class MatrixStack
89 {
90 public:
91 explicit MatrixStack(uint32_t in_offset = 0) :
92 offset(in_offset)
93 {
94 // make sure there is an initial matrix
95 matrixStack.emplace(dmat4());
96 dirty = true;
97 }
98
99 using value_type = double;
100
101 std::stack<dmat4> matrixStack;
102 uint32_t offset = 0;
103 bool dirty = false;
104
105 MatrixStack& operator=(const MatrixStack& rhs)
106 {
107 matrixStack = rhs.matrixStack;
108 offset = rhs.offset;
109 dirty = true;
110
111 return *this;
112 }
113
114 inline void set(const mat4& matrix)
115 {
116 matrixStack = {};
117 matrixStack.emplace(matrix);
118 dirty = true;
119 }
120
121 inline void set(const dmat4& matrix)
122 {
123 matrixStack = {};
124 matrixStack.emplace(matrix);
125 dirty = true;
126 }
127
128 inline void push(const mat4& matrix)
129 {
130 matrixStack.emplace(matrix);
131 dirty = true;
132 }
133 inline void push(const dmat4& matrix)
134 {
135 matrixStack.emplace(matrix);
136 dirty = true;
137 }
138 inline void push(const Transform& transform)
139 {
140 matrixStack.emplace(transform.transform(matrixStack.top()));
141 dirty = true;
142 }
143
144 inline void push(const MatrixTransform& transform)
145 {
146 matrixStack.emplace(matrixStack.top() * transform.matrix);
147 dirty = true;
148 }
149
150 const dmat4& top() const { return matrixStack.top(); }
151
152 inline void pop()
153 {
154 matrixStack.pop();
155 dirty = true;
156 }
157
158 inline void record(CommandBuffer& commandBuffer)
159 {
160 if (dirty)
161 {
162 auto pipeline = commandBuffer.getCurrentPipelineLayout();
163 auto stageFlags = commandBuffer.getCurrentPushConstantStageFlags();
164
165 // don't attempt to push matrices if no pipeline is current or no stages are enabled for push constants
166 if (pipeline == 0 || stageFlags == 0)
167 {
168 return;
169 }
170
171 // make sure matrix is a float matrix.
172 mat4 newmatrix(matrixStack.top());
173 vkCmdPushConstants(commandBuffer, pipeline, stageFlags, offset, sizeof(newmatrix), newmatrix.data());
174 dirty = false;
175 }
176 }
177 };
178
180 struct Frustum
181 {
182 using value_type = MatrixStack::value_type;
183 using Plane = t_plane<value_type>;
184 using Vector = t_vec4<value_type>;
185 Plane face[POLYTOPE_SIZE];
186 Vector lodScale;
187
188 Frustum()
189 {
190 face[0].set(1.0, 0.0, 0.0, 1.0); // left plane
191 face[1].set(-1.0, 0.0, 0.0, 1.0); // right plane
192 face[2].set(0.0, -1.0, 0.0, 1.0); // bottom plane
193 face[3].set(0.0, 1.0, 0.0, 1.0); // top plane
194 if constexpr (POLYTOPE_SIZE >= 5) face[4].set(0.0, 0.0, 1.0, 0.0); // far plane
195 if constexpr (POLYTOPE_SIZE >= 6) face[5].set(0.0, 0.0, -1.0, 1.0); // near plane
196 }
197
198 template<class M>
199 Frustum(const Frustum& pt, const M& matrix)
200 {
201 face[0] = pt.face[0] * matrix;
202 face[1] = pt.face[1] * matrix;
203 face[2] = pt.face[2] * matrix;
204 face[3] = pt.face[3] * matrix;
205 if constexpr (POLYTOPE_SIZE >= 5) face[4] = pt.face[4] * matrix;
206 if constexpr (POLYTOPE_SIZE >= 6) face[5] = pt.face[5] * matrix;
207 }
208
209 template<class M>
210 void set(const Frustum& pt, const M& matrix)
211 {
212 face[0] = pt.face[0] * matrix;
213 face[1] = pt.face[1] * matrix;
214 face[2] = pt.face[2] * matrix;
215 face[3] = pt.face[3] * matrix;
216 if constexpr (POLYTOPE_SIZE >= 5) face[4] = pt.face[4] * matrix;
217 if constexpr (POLYTOPE_SIZE >= 6) face[5] = pt.face[5] * matrix;
218 }
219
220 template<class M>
221 void computeLodScale(const M& proj, const M& mv)
222 {
223 value_type f = -proj[1][1];
224 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;
225 value_type inv_scale = value_type(1.0) / sc;
226 lodScale.set(mv[0][2] * inv_scale,
227 mv[1][2] * inv_scale,
228 mv[2][2] * inv_scale,
229 mv[3][2] * inv_scale);
230 }
231
232 template<typename T>
233 bool intersect(const t_sphere<T>& s) const
234 {
235 auto negative_radius = -s.radius;
236 if (distance(face[0], s.center) < negative_radius) return false;
237 if (distance(face[1], s.center) < negative_radius) return false;
238 if (distance(face[2], s.center) < negative_radius) return false;
239 if (distance(face[3], s.center) < negative_radius) return false;
240 if constexpr (POLYTOPE_SIZE >= 5)
241 if (distance(face[4], s.center) < negative_radius) return false;
242 if constexpr (POLYTOPE_SIZE >= 6)
243 if (distance(face[5], s.center) < negative_radius) return false;
244 return true;
245 }
246 };
247
249 class VSG_DECLSPEC State : public Inherit<Object, State>
250 {
251 public:
252 explicit State(const Slots& in_maxSlots);
253
254 using StateCommandStack = StateStack<StateCommand>;
255 using StateStacks = std::vector<StateCommandStack>;
256
257 ref_ptr<CommandBuffer> _commandBuffer;
258
259 Frustum _frustumUnit;
260 Frustum _frustumProjected;
261
262 using FrustumStack = std::stack<Frustum>;
263 FrustumStack _frustumStack;
264
265 bool dirty = true;
266
267 bool inheritViewForLODScaling = false;
268 dmat4 inheritedProjectionMatrix;
269 dmat4 inheritedViewMatrix;
270 dmat4 inheritedViewTransform;
271
272 Slots maxSlots;
273 uint32_t activeMaxStateSlot = 0;
274
275 StateStacks stateStacks;
276
277 uint32_t viewportStateHint = 0;
278
279 MatrixStack projectionMatrixStack{0};
280 MatrixStack modelviewMatrixStack{64};
281
282 void reserve(const Slots& in_maxSlots);
283
284 void connect(ref_ptr<CommandBuffer> commandBuffer);
285
286 void reset();
287
288 enum InheritanceMask
289 {
290 INHERIT_STATE = (1 << 0),
291 INHERIT_VIEWPORT_STATE_HINT = (1 << 1),
292 INHERIT_VIEW_SETTINGS = (1 << 2),
293 INHERIT_MATRICES = (1 << 4),
294 INHERIT_ALL = INHERIT_STATE | INHERIT_VIEWPORT_STATE_HINT | INHERIT_VIEW_SETTINGS | INHERIT_MATRICES
295 };
296
297 InheritanceMask inheritanceMask = InheritanceMask::INHERIT_ALL;
298
299 void inherit(const State& state);
300
301 inline void dirtyStateStacks()
302 {
303 dirty = true;
304 for (auto& stateStack : stateStacks)
305 {
306 stateStack.dirty();
307 }
308 }
309
310 void setInhertiedViewProjectionAndViewMatrix(const dmat4& projMatrix, const dmat4& viewMatrix)
311 {
312 inheritedProjectionMatrix = projMatrix;
313 inheritedViewMatrix = viewMatrix;
314 }
315
316 void setProjectionAndViewMatrix(const dmat4& projMatrix, const dmat4& viewMatrix)
317 {
318 projectionMatrixStack.set(projMatrix);
319
320 const auto& proj = projectionMatrixStack.top();
321
322 _frustumProjected.set(_frustumUnit, proj);
323
324 modelviewMatrixStack.set(viewMatrix);
325
326 // clear frustum stack
327 while (!_frustumStack.empty()) _frustumStack.pop();
328
329 if (inheritViewForLODScaling)
330 {
331 inheritedViewTransform = inheritedViewMatrix * inverse(viewMatrix);
332 }
333
334 // push frustum in world coords
335 pushFrustum();
336 }
337
338 inline void record()
339 {
340 if (dirty)
341 {
342 for (uint32_t slot = 0; slot <= activeMaxStateSlot; ++slot)
343 {
344 stateStacks[slot].record(*_commandBuffer);
345 }
346
347 // reset the active maxslot to the minimum required
348 activeMaxStateSlot = maxSlots.state;
349
350 projectionMatrixStack.record(*_commandBuffer);
351 modelviewMatrixStack.record(*_commandBuffer);
352
353 dirty = false;
354 }
355 }
356
357 template<typename Iterator>
358 inline void push(Iterator begin, Iterator end)
359 {
360 for (auto itr = begin; itr != end; ++itr)
361 {
362 stateStacks[(*itr)->slot].push((*itr));
363 }
364 dirty = true;
365 }
366
367 inline void push(const StateCommands& commands)
368 {
369 push(commands.begin(), commands.end());
370 }
371
372 template<typename Iterator>
373 inline void pop(Iterator begin, Iterator end)
374 {
375 for (auto itr = begin; itr != end; ++itr)
376 {
377 stateStacks[(*itr)->slot].pop();
378 }
379 dirty = true;
380 }
381
382 inline void pop(const StateCommands& commands)
383 {
384 pop(commands.begin(), commands.end());
385 }
386
387 inline void push(ref_ptr<StateCommand> command)
388 {
389 stateStacks[command->slot].push(command);
390 dirty = true;
391 }
392
393 inline void pop(ref_ptr<StateCommand> command)
394 {
395 stateStacks[command->slot].pop();
396 dirty = true;
397 }
398
399 void pushView(ref_ptr<StateCommand> command);
400
401 void popView(ref_ptr<StateCommand> command);
402
403 void pushView(const View& view);
404
405 void popView(const View& view);
406
407 inline void pushFrustum()
408 {
409 _frustumStack.push(Frustum(_frustumProjected, modelviewMatrixStack.top()));
410 if (inheritViewForLODScaling)
411 _frustumStack.top().computeLodScale(inheritedProjectionMatrix, inheritedViewTransform * modelviewMatrixStack.top());
412 else
413 _frustumStack.top().computeLodScale(projectionMatrixStack.top(), modelviewMatrixStack.top());
414 }
415
416 inline void applyFrustum()
417 {
418 _frustumStack.top().set(_frustumProjected, modelviewMatrixStack.top());
419 _frustumStack.top().computeLodScale(projectionMatrixStack.top(), modelviewMatrixStack.top());
420 }
421
422 inline void popFrustum()
423 {
424 _frustumStack.pop();
425 }
426
427 template<typename T>
428 bool intersect(const t_sphere<T>& s) const
429 {
430 return _frustumStack.top().intersect(s);
431 }
432
433 template<typename T>
434 T lodDistance(const t_sphere<T>& s) const
435 {
436 const auto& frustum = _frustumStack.top();
437 if (!frustum.intersect(s)) return -1.0;
438
439 const auto& lodScale = frustum.lodScale;
440 return std::abs(lodScale[0] * s.x + lodScale[1] * s.y + lodScale[2] * s.z + lodScale[3]);
441 }
442 };
443
444} // namespace vsg
vsg::CommandBuffer
CommandBuffer encapsulates VkCommandBuffer.
Definition CommandBuffer.h:30
vsg::MatrixStack
MatrixStack used internally by vsg::State to manage stack of projection or modelview matrices.
Definition State.h:89
vsg::MatrixTransform
Definition MatrixTransform.h:24
vsg::StateStack
StateStack used internally by vsg::State to manage stack of vsg::StateCommand.
Definition State.h:33
vsg::Transform
Transform node is a pure virtual base class for positioning/scaling/rotating subgraphs.
Definition Transform.h:22
vsg::View
View is a Group class that pairs a Camera that defines the view with a subgraph that defines the scen...
Definition View.h:36
vsg::ref_ptr
Definition ref_ptr.h:22
vsg::Frustum
Frustum used internally by vsg::State to manage view fustum culling during vsg::RecordTraversal.
Definition State.h:181
vsg::Slots
max slot values used for general state and view state related State::stateStacks
Definition Slots.h:22
vsg::t_plane
Definition plane.h:33
vsg::t_sphere
template sphere class
Definition sphere.h:34
vsg::t_vec4
t_vec4 template class that represents a 4D vector
Definition vec4.h:35