Simulant  21.12-574
A portable game engine for Windows, OSX, Linux, Dreamcast, and PSP
render_queue.h
1 /* * Copyright (c) 2011-2017 Luke Benstead https://simulant-engine.appspot.com
2  *
3  * This file is part of Simulant.
4  *
5  * Simulant is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * Simulant is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with Simulant. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #pragma once
20 
21 #include <list>
22 #include <set>
23 
24 #include "../../generic/containers/contiguous_map.h"
25 
26 #include "../../types.h"
27 #include "../../threads/shared_mutex.h"
28 #include "../../macros.h"
29 
30 namespace smlt {
31 
32 class MaterialPass;
33 class Renderer;
34 struct Renderable;
35 class Light;
36 
37 namespace batcher {
38 
40  uint8_t pass; // 1 byte
41  bool is_blended; // 1 byte
42  float distance_to_camera; // 4 bytes
43  uint16_t padding; // 2-bytes to get 8-byte alignment
44 };
45 
46 
47 struct RenderGroup {
48  /* A sort key, generated from priority and material properties, this
49  * may differ per-renderer */
50  RenderGroupKey sort_key;
51 
52  bool operator<(const RenderGroup& rhs) const {
53  if(sort_key.pass < rhs.sort_key.pass) {
54  return true;
55  }
56 
57  if(sort_key.is_blended < rhs.sort_key.is_blended) {
58  return true;
59  }
60 
61  if(!sort_key.is_blended) {
62  if(sort_key.distance_to_camera < rhs.sort_key.distance_to_camera) {
63  // If the object is opaque, we want to render
64  // front-to-back, so less distance is less
65  return true;
66  }
67  } else {
68  if(rhs.sort_key.distance_to_camera < sort_key.distance_to_camera) {
69  // If the object is translucent, we want to render
70  // back-to-front
71  return true;
72  }
73  }
74 
75  return false;
76  }
77 
78  bool operator==(const RenderGroup& rhs) const {
79  return (
80  sort_key.pass == rhs.sort_key.pass &&
81  sort_key.is_blended == rhs.sort_key.is_blended &&
82  sort_key.distance_to_camera == rhs.sort_key.distance_to_camera
83  );
84  }
85 
86  bool operator!=(const RenderGroup& rhs) const {
87  return !(*this == rhs);
88  }
89 };
90 
91 RenderGroupKey generate_render_group_key(const uint8_t pass, const bool is_blended, const float distance_to_camera);
92 
94 public:
95  virtual ~RenderGroupFactory() {}
96 
97  /* Initialize a render group based on the provided arguments
98  * Returns the group's sort_key */
99  virtual RenderGroupKey prepare_render_group(
100  RenderGroup* group,
101  const Renderable* renderable,
102  const MaterialPass* material_pass,
103  const uint8_t pass_number,
104  const bool is_blended,
105  const float distance_to_camera
106  ) = 0;
107 };
108 
109 typedef uint32_t Pass;
110 typedef uint32_t Iteration;
111 
112 class RenderQueue;
113 
115 public:
116  virtual ~RenderQueueVisitor() {}
117 
118  virtual void start_traversal(const RenderQueue& queue, uint64_t frame_id, Stage* stage) = 0;
119 
120  virtual void change_render_group(const RenderGroup* prev, const RenderGroup* next) = 0;
121 
122  virtual void change_material_pass(const MaterialPass* prev, const MaterialPass* next) = 0;
123  virtual void apply_lights(const LightPtr* lights, const uint8_t count) = 0;
124 
125  virtual void visit(const Renderable*, const MaterialPass*, Iteration) = 0;
126  virtual void end_traversal(const RenderQueue& queue, Stage* stage) = 0;
127 };
128 
129 
131 public:
133  queue_(queue) {}
134 
135  void watch(MaterialID material_id, Renderable* renderable);
136  void unwatch(Renderable* renderable);
137 
138 private:
139  RenderQueue* queue_;
140 
141  /*
142  * We store a list of all the renderables that need to be reinserted if a material changes
143  */
144  std::unordered_map<MaterialID, std::set<Renderable*>> renderables_by_material_;
145 
146  /*
147  * We store connections to material update signals, when all renderables are removed
148  * for a particular material, we disconnect the signal
149  */
150  std::unordered_map<MaterialID, sig::connection> material_update_conections_;
151 
152  void on_material_changed(MaterialID material);
153 };
154 
155 
156 class RenderQueue {
157 public:
158  typedef std::function<void (bool, const RenderGroup*, Renderable*, MaterialPass*, Light*, Iteration)> TraverseCallback;
159 
160  RenderQueue();
161 
162  void reset(Stage* stage, RenderGroupFactory* render_group_factory, CameraPtr camera);
163 
164  void insert_renderable(Renderable&& renderable); // IMPORTANT, must update RenderGroups if they exist already
165  void clear();
166 
167  void traverse(RenderQueueVisitor* callback, uint64_t frame_id) const;
168 
169  std::size_t queue_count() const { return priority_queues_.size(); }
170  std::size_t group_count(Pass pass_number) const;
171 
172  std::size_t renderable_count() const { return renderables_.size(); }
173  Renderable* renderable(const std::size_t i) {
174  return &renderables_[i];
175  }
176 private:
177  // std::map is ordered, so by using the RenderGroup as the key we
178  // minimize GL state changes (e.g. if a RenderGroupImpl orders by TextureID, then ShaderID
179  // then we'll see (TexID(1), ShaderID(1)), (TexID(1), ShaderID(2)) for example meaning the
180  // texture doesn't change even if the shader does
182 
183  Stage* stage_ = nullptr;
184  RenderGroupFactory* render_group_factory_ = nullptr;
185  CameraPtr camera_;
186 
187  std::vector<Renderable> renderables_;
188  std::array<SortedRenderables, RENDER_PRIORITY_MAX - RENDER_PRIORITY_MIN> priority_queues_;
189 
190  void clean_empty_batches();
191 
192  mutable thread::Mutex queue_lock_;
193 };
194 
195 }
196 }
smlt::Stage
Definition: stage.h:80
smlt
Definition: animation.cpp:25
smlt::batcher::MaterialChangeWatcher
Definition: render_queue.h:130
smlt::Light
Definition: light.h:35
smlt::batcher::RenderGroupKey
Definition: render_queue.h:39
smlt::batcher::RenderQueue
Definition: render_queue.h:156
smlt::batcher::RenderQueueVisitor
Definition: render_queue.h:114
smlt::UniqueID< MaterialPtr >
smlt::MaterialPass
Definition: material.h:47
smlt::batcher::RenderGroup
Definition: render_queue.h:47
smlt::batcher::RenderGroupFactory
Definition: render_queue.h:93
smlt::default_init_ptr< Light >
smlt::Renderable
Definition: renderable.h:67
smlt::thread::Mutex
Definition: mutex.h:25
smlt::ContiguousMultiMap
Definition: contiguous_map.h:64