Midnight Graphics
Create Fast and Simple Graphics in C++
Buffer.hpp
1 #pragma once
2 
3 #include <Def.hpp>
4 
5 #include "ObjectHandle.hpp"
6 
7 namespace mn::Graphics
8 {
9  struct Buffer : ObjectHandle<Buffer>
10  {
11  using gpu_addr = void*;
12 
13  MN_SYMBOL Buffer();
14  Buffer(Buffer&&);
15  Buffer(const Buffer&) = delete;
16  virtual ~Buffer() { rawFree(); }
17 
18  virtual uint32_t getSize() const { return 0; }
19  virtual uint32_t vertices() const { return 0; }
20 
21  void allocateBytes(std::size_t bytes) { rawResize(bytes); }
22  auto* rawData() const { return reinterpret_cast<std::byte*>(_data); }
23  auto allocated() const { return _size; }
24 
25  MN_SYMBOL gpu_addr getAddress() const;
26 
27  protected:
28  MN_SYMBOL void rawResize(std::size_t newsize);
29  MN_SYMBOL void rawFree();
30  MN_SYMBOL auto rawSize() const { return _size; }
31 
32  private:
33  Handle<Buffer> allocation;
34  void* _data;
35  std::size_t _size;
36  };
37 
38  template<typename T>
39  struct TypeBuffer : Buffer
40  {
41  uint32_t getSize() const override { return sizeof(T); }
42  uint32_t vertices() const override { return size(); }
43 
44  std::size_t size() const
45  {
46  MIDNIGHT_ASSERT(rawSize() % sizeof(T) == 0, "Buffer incorrectly allocated");
47  return rawSize() / sizeof(T);
48  }
49 
50  T& at(std::size_t index)
51  {
52  MIDNIGHT_ASSERT(index < size(), "Index out of bounds");
53  return *(reinterpret_cast<T*>(rawData()) + index);
54  }
55 
56  const T& at(std::size_t index) const
57  {
58  return const_cast<TypeBuffer<T>*>(this)->at(index);
59  }
60 
61  T& operator[](std::size_t index)
62  {
63  return at(index);
64  }
65 
66  const T& operator[](std::size_t index) const
67  {
68  return at(index);
69  }
70 
71  void resize(std::size_t count)
72  {
73  this->rawResize(count * sizeof(T));
74  }
75  };
76 
77  template<typename T>
78  struct Vector
79  {
80  Vector() : count{0} { }
81 
82  Vector(uint32_t elements)
83  {
84  resize(elements);
85  }
86 
87  uint32_t size() const
88  {
89  return count;
90  }
91 
92  Buffer::gpu_addr getAddress() const
93  {
94  return memory.getAddress();
95  }
96 
97  void reserve(const uint32_t& count)
98  {
99  // If count < this->count, we need to call the destructors
100  for (uint32_t i = count; i < this->count; i++)
101  reinterpret_cast<T*>(memory.rawData() + i * sizeof(T))->~T();
102 
103  memory.allocateBytes(count * sizeof(T));
104  }
105 
106  void resize(const uint32_t& count)
107  {
108  if (count == this->count) return;
109 
110  // If count < this->count, we need to call the destructors
111  for (uint32_t i = count; i < this->count; i++)
112  reinterpret_cast<T*>(memory.rawData() + i * sizeof(T))->~T();
113 
114  memory.allocateBytes(count * sizeof(T));
115 
116  // default construct each object in the new region
117  for (uint32_t i = this->count; i < count; i++)
118  new(memory.rawData() + i * sizeof(T)) T();
119 
120  this->count = count;
121  }
122 
123  void push_back(const T& value)
124  {
125  if (count == memory.allocated() / sizeof(T))
126  reserve((memory.allocated() / sizeof(T) + 5) * 1.75f * sizeof(T));
127  new(memory.rawData() + count * sizeof(T)) T(value);
128  }
129 
130  template<typename... Args>
131  void emplace_back(Args&&... args)
132  {
133  if (count == memory.allocated() / sizeof(T))
134  reserve((memory.allocated() / sizeof(T) + 5) * 1.75f * sizeof(T));
135  new(memory.rawData() + count * sizeof(T)) T(std::forward<Args>(args)...);
136  }
137 
138  T& at(uint32_t index)
139  {
140  return *reinterpret_cast<T*>(memory.rawData() + index * sizeof(T));
141  }
142 
143  const T& at(uint32_t index) const
144  {
145  return const_cast<Vector<T>*>(this)->at(index);
146  }
147 
148  T& operator[](uint32_t index)
149  {
150  return at(index);
151  }
152 
153  const T& operator[](uint32_t index) const
154  {
155  return at(index);
156  }
157 
158  private:
159  uint32_t count;
160  Buffer memory;
161  };
162 }
Definition: Buffer.hpp:10
Definition: ObjectHandle.hpp:9
Definition: Buffer.hpp:40
Definition: Buffer.hpp:79
Definition: TypedHandle.hpp:9