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