Simulant  21.12-553
A portable game engine for Windows, OSX, Linux, Dreamcast, and PSP
vertex_data.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 <cstdint>
22 #include <vector>
23 
24 #include "signals/signal.h"
25 #include "generic/managed.h"
26 #include "generic/uniquely_identifiable.h"
27 #include "generic/notifies_destruction.h"
28 
29 #include "colour.h"
30 #include "types.h"
31 
32 namespace smlt {
33 
34 class Window;
35 
36 enum VertexAttributeType {
37  VERTEX_ATTRIBUTE_TYPE_EMPTY = 0,
38  VERTEX_ATTRIBUTE_TYPE_POSITION,
39  VERTEX_ATTRIBUTE_TYPE_NORMAL,
40  VERTEX_ATTRIBUTE_TYPE_TEXCOORD0,
41  VERTEX_ATTRIBUTE_TYPE_TEXCOORD1,
42  VERTEX_ATTRIBUTE_TYPE_TEXCOORD2,
43  VERTEX_ATTRIBUTE_TYPE_TEXCOORD3,
44  VERTEX_ATTRIBUTE_TYPE_TEXCOORD4,
45  VERTEX_ATTRIBUTE_TYPE_TEXCOORD5,
46  VERTEX_ATTRIBUTE_TYPE_TEXCOORD6,
47  VERTEX_ATTRIBUTE_TYPE_TEXCOORD7,
48  VERTEX_ATTRIBUTE_TYPE_DIFFUSE,
49  VERTEX_ATTRIBUTE_TYPE_SPECULAR
50 };
51 
52 VertexAttribute attribute_for_type(VertexAttributeType type, const VertexSpecification& spec);
53 
54 class VertexData :
55  public RefCounted<VertexData>,
56  public UniquelyIdentifiable<VertexData>,
57  public NotifiesDestruction<VertexData> {
58 
59 public:
60  VertexData(VertexSpecification vertex_specification);
61  virtual ~VertexData();
62 
63  VertexData(const VertexData& rhs) = delete;
64  VertexData& operator=(const VertexData& rhs) = delete;
65 
66  void reset(VertexSpecification vertex_specification);
67 
68  /* If release_memory is true, then allocated RAM
69  * will be freed. This can be costly which is why it defaults
70  * to false. */
71  void clear(bool release_memory=false);
72 
73  void move_to_start();
74  bool move_by(int32_t amount);
75  bool move_to(int32_t index);
76  void move_to_end();
77  uint32_t move_next();
78 
79  void done();
80  uint64_t last_updated() const;
81 
82  void position(float x, float y, float z, float w);
83  void position(float x, float y, float z);
84  void position(float x, float y);
85  void position(const Vec3& pos);
86  void position(const Vec2& pos);
87  void position(const Vec4& pos);
88 
89  template<typename T>
90  const T* position_at(uint32_t idx) const;
91 
92  template<typename T>
93  const T* normal_at(uint32_t idx) const;
94 
95  template<typename T>
96  const T* texcoord0_at(uint32_t idx) const;
97 
98  template<typename T>
99  const T* texcoord1_at(uint32_t idx) const;
100 
101  template<typename T>
102  const T* diffuse_at(const uint32_t index) const;
103 
104  /*
105  * Position Non-Dimensional
106  * Returns the position as a Vec4 with the remaining components
107  * set to default (e.g. if your vertices are 2D, this will return
108  * Vec4(x, y, def, def)
109  */
110  Vec4 position_nd_at(uint32_t idx, float defz=0.0f, float defw=1.0f) const;
111 
112  void normal(float x, float y, float z);
113  void normal(const Vec3& n);
114 
115  void tex_coord0(float u, float v);
116  void tex_coord0(float u, float v, float w);
117  void tex_coord0(float x, float y, float z, float w);
118  void tex_coord0(const Vec2& vec) { tex_coord0(vec.x, vec.y); }
119 
120  void tex_coord1(float u, float v);
121  void tex_coord1(float u, float v, float w);
122  void tex_coord1(float x, float y, float z, float w);
123  void tex_coord1(const Vec2& vec) { tex_coord1(vec.x, vec.y); }
124 
125  void tex_coord2(float u, float v);
126  void tex_coord2(float u, float v, float w);
127  void tex_coord2(float x, float y, float z, float w);
128  void tex_coord2(const Vec2& vec) { tex_coord2(vec.x, vec.y); }
129 
130  void tex_coord3(float u, float v);
131  void tex_coord3(float u, float v, float w);
132  void tex_coord3(float x, float y, float z, float w);
133  void tex_coord3(const Vec2& vec) { tex_coord3(vec.x, vec.y); }
134 
135  void diffuse(float r, float g, float b, float a);
136  void diffuse(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
137  void diffuse(const Colour& colour);
138 
139  void specular(float r, float g, float b, float a);
140  void specular(const Colour& colour);
141 
142  uint32_t count() const { return vertex_count_; }
143 
144  sig::signal<void ()>& signal_update_complete() { return signal_update_complete_; }
145  bool empty() const { return data_.empty(); }
146 
147  int32_t cursor_position() const { return cursor_position_; }
148  int32_t cursor_offset() const { return cursor_position_ * stride_; }
149 
150  inline uint32_t stride() const {
151  return stride_;
152  }
153 
154  uint32_t copy_vertex_to_another(VertexData& out, uint32_t idx) {
155  if(out.vertex_specification_ != this->vertex_specification_) {
156  throw std::runtime_error("Cannot copy vertex as formats differ");
157  }
158 
159  uint32_t start = idx * stride();
160  uint32_t end = (idx + 1) * stride();
161 
162  out.data_.insert(out.data_.end(), data_.begin() + start, data_.begin() + end);
163  out.vertex_count_++; //Increment the vertex count on the output
164 
165  // Return the index to the new vertex
166  return out.count() - 1;
167  }
168 
169  std::size_t extend(const VertexData& other) {
170  if(vertex_specification_ != other.vertex_specification_) {
171  S_ERROR("Tried to extend vertex data with incompatible data");
172  return 0;
173  }
174 
175  data_.insert(data_.end(), other.data_.begin(), other.data_.end());
176  vertex_count_ += other.count();
177  return count();
178  }
179 
180  void transform_by(const Mat4& transform) {
181  for(auto i = 0u; i < count(); ++i) {
182  move_to(i);
183 
184  Vec4 pos = position_nd_at(i);
185  pos = transform * pos;
186  if(vertex_specification_.position_attribute == VERTEX_ATTRIBUTE_2F) {
187  position(pos.x, pos.y);
188  } else if(vertex_specification_.position_attribute == VERTEX_ATTRIBUTE_3F) {
189  position(pos.x, pos.y, pos.z);
190  } else if(vertex_specification_.position_attribute == VERTEX_ATTRIBUTE_4F) {
191  position(pos);
192  } else {
193  S_ERROR("Attempted to transform unsupported position attribute type");
194  }
195  }
196  }
197 
198  bool interp_vertex(uint32_t source_idx, const VertexData& dest_state, uint32_t dest_idx, VertexData& out, uint32_t out_idx, float interp);
199  uint8_t* data() { if(empty()) { return nullptr; } return &data_[0]; }
200  const uint8_t* data() const { if(empty()) { return nullptr; } return &data_[0]; }
201  uint32_t data_size() const { return data_.size(); }
202 
203  VertexAttribute attribute_for_type(VertexAttributeType type) const;
204 
205  void reserve(uint32_t size);
206 
207  void resize(uint32_t size);
208 
209  const VertexSpecification& vertex_specification() const { return vertex_specification_; }
210 
211  /* Clones this VertexData into another. The other data must have the same
212  * specification and will be wiped if it contains vertices already.
213  *
214  * We don't do this with a traditional assignment operator as copying vertex data
215  * is a costly and rare operation and so copying should be explicit
216  *
217  * Returns true on success, false otherwise.
218  */
219  bool clone_into(VertexData& other);
220 
221 private:
222  VertexSpecification vertex_specification_;
223  std::vector<uint8_t> data_;
224  uint32_t vertex_count_ = 0;
225  uint32_t stride_ = 0;
226  int32_t cursor_position_ = 0;
227  uint64_t last_updated_ = 0;
228 
229  void tex_coordX(uint8_t which, float u);
230  void tex_coordX(uint8_t which, float u, float v);
231  void tex_coordX(uint8_t which, float u, float v, float w);
232  void tex_coordX(uint8_t which, float x, float y, float z, float w);
233  void check_texcoord(uint8_t which);
234 
235  VertexAttribute attribute_from_type(VertexAttributeType type);
236 
237  sig::signal<void ()> signal_update_complete_;
238 
239  void push_back();
240 
241  void position_checks();
242  void recalc_attributes();
243 
244  friend class VertexDataTest;
245 };
246 
247 typedef std::shared_ptr<VertexData> VertexDataPtr;
248 
249 template<>
250 const Vec2* VertexData::position_at<Vec2>(uint32_t idx) const;
251 
252 template<>
253 const Vec3* VertexData::position_at<Vec3>(uint32_t idx) const;
254 
255 template<>
256 const Vec4* VertexData::position_at<Vec4>(uint32_t idx) const;
257 
258 template<>
259 const Vec2* VertexData::normal_at<Vec2>(uint32_t idx) const;
260 
261 template<>
262 const Vec3* VertexData::normal_at<Vec3>(uint32_t idx) const;
263 
264 template<>
265 const Vec2* VertexData::texcoord0_at<Vec2>(uint32_t idx) const;
266 
267 template<>
268 const Vec3* VertexData::texcoord0_at<Vec3>(uint32_t idx) const;
269 
270 template<>
271 const Vec4* VertexData::texcoord0_at<Vec4>(uint32_t idx) const;
272 
273 template<>
274 const Vec2* VertexData::texcoord1_at<Vec2>(uint32_t idx) const;
275 
276 template<>
277 const Vec3* VertexData::texcoord1_at<Vec3>(uint32_t idx) const;
278 
279 template<>
280 const Vec4* VertexData::texcoord1_at<Vec4>(uint32_t idx) const;
281 
282 template<>
283 const Colour* VertexData::diffuse_at(const uint32_t index) const;
284 
285 template<>
286 const uint8_t* VertexData::diffuse_at(const uint32_t index) const;
287 
288 typedef uint32_t Index;
289 
290 class IndexData;
291 
293 private:
294  friend class IndexData;
295 
296  IndexDataIterator(const IndexData* owner, int pos);
297 
298 public:
299  IndexDataIterator& operator++() {
300  ptr_ += stride_;
301  return *this;
302  }
303 
304  bool operator==(const IndexDataIterator& rhs) const {
305  return ptr_ == rhs.ptr_;
306  }
307 
308  bool operator!=(const IndexDataIterator& rhs) const {
309  return ptr_ != rhs.ptr_;
310  }
311 
312  uint32_t operator*() const {
313  switch(type_) {
314  case INDEX_TYPE_8_BIT:
315  return *((uint8_t*) ptr_);
316  case INDEX_TYPE_16_BIT:
317  return *((uint16_t*) ptr_);
318  case INDEX_TYPE_32_BIT:
319  default:
320  return *((uint32_t*) ptr_);
321  }
322  }
323 private:
324  const IndexData* owner_;
325  IndexType type_;
326  uint8_t stride_;
327  const uint8_t* ptr_;
328 };
329 
330 
331 class IndexData:
332  public RefCounted<IndexData>,
333  public UniquelyIdentifiable<IndexData>,
334  public NotifiesDestruction<IndexData> {
335 
336  friend class IndexDataIterator;
337 public:
338  IndexData(IndexType type);
339 
340  IndexDataIterator begin() const {
341  return IndexDataIterator(this, 0);
342  }
343 
344  IndexDataIterator end() const {
345  return IndexDataIterator(this, count());
346  }
347 
348  void reset();
349  void clear(bool release_memory=false);
350  void resize(uint32_t size);
351  void reserve(uint32_t size) { indices_.reserve(size * stride()); }
352 
353  std::vector<uint32_t> all();
354 
355  uint32_t min_index() const { return min_index_; }
356  uint32_t max_index() const { return max_index_; }
357 
358  template<typename T, int BS>
359  void _index(uint32_t* indexes, std::size_t count) {
360  auto i = indices_.size();
361  indices_.resize(i + (count * BS));
362 
363  uint32_t* idx = indexes;
364  for(std::size_t j = 0; j < count; ++j) {
365  min_index_ = std::min(min_index_, *idx);
366  max_index_ = std::max(max_index_, *idx);
367 
368  auto ptr = (T*) &indices_[i];
369  *ptr = (T) (*idx);
370  ++idx;
371  i += sizeof(T);
372  }
373  }
374 
375  void index(uint32_t* indexes, std::size_t count) {
376  switch(index_type_) {
377  case INDEX_TYPE_8_BIT:
378  _index<uint8_t, 1>(indexes, count);
379  break;
380  case INDEX_TYPE_16_BIT:
381  _index<uint16_t, 2>(indexes, count);
382  break;
383  case INDEX_TYPE_32_BIT:
384  _index<uint32_t, 4>(indexes, count);
385  break;
386  default:
387  break;
388  }
389 
390  count_ = indices_.size() / stride_;
391  }
392 
393  void index(uint32_t idx) {
394  index(&idx, 1);
395  }
396 
397  void done();
398  uint64_t last_updated() const;
399 
400  uint32_t at(const uint32_t i) const {
401  auto ptr = &indices_[i * stride()];
402 
403  switch(index_type_) {
404  case INDEX_TYPE_8_BIT: return *ptr;
405  case INDEX_TYPE_16_BIT: return *((uint16_t*) ptr);
406  case INDEX_TYPE_32_BIT: return *((uint32_t*) ptr);
407  default:
408  throw std::logic_error("Invalid index type");
409  }
410  }
411 
412  uint32_t count() const {
413  return count_;
414  }
415 
416  bool operator==(const IndexData& other) const {
417  return this->indices_ == other.indices_;
418  }
419 
420  bool operator!=(const IndexData& other) const {
421  return !(*this == other);
422  }
423 
424  sig::signal<void ()>& signal_update_complete() { return signal_update_complete_; }
425 
426  const uint8_t* data() const { return &indices_[0]; }
427  std::size_t data_size() const { return indices_.size() * sizeof(uint8_t); }
428 
429  uint32_t stride() const {
430  return stride_;
431  }
432 
433  IndexType index_type() const { return index_type_; }
434 
435 private:
436  IndexType index_type_;
437  std::vector<uint8_t> indices_;
438  uint32_t stride_ = 0;
439  uint32_t count_ = 0;
440  uint64_t last_updated_ = 0;
441 
442  sig::signal<void ()> signal_update_complete_;
443 
444  /* For glDrawRangeElements */
445  uint32_t min_index_ = ~0;
446  uint32_t max_index_ = 0;
447 };
448 
449 typedef std::shared_ptr<IndexData> IndexDataPtr;
450 
451 }
smlt::VertexData
Definition: vertex_data.h:57
smlt::UniquelyIdentifiable
Definition: uniquely_identifiable.h:14
smlt::Mat4
Definition: mat4.h:29
smlt::VertexSpecification
Definition: types.h:121
smlt::Vec3
Definition: vec3.h:23
smlt::RefCounted
Definition: managed.h:65
smlt
Definition: animation.cpp:25
smlt::NotifiesDestruction
Definition: notifies_destruction.h:9
smlt::IndexDataIterator
Definition: vertex_data.h:292
smlt::IndexData
Definition: vertex_data.h:334
smlt::Colour
Definition: colour.h:29
smlt::Vec4
Definition: vec4.h:12
smlt::Vec2
Definition: vec2.h:14
smlt::sig::signal
Definition: signal.h:330