vsg  1.0.4
VulkanSceneGraph library
Array2D.h
1 #pragma once
2 
3 /* <editor-fold desc="MIT License">
4 
5 Copyright(c) 2018 Robert Osfield
6 
7 Permission 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 
9 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10 
11 THE 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/core/Data.h>
16 
17 #include <vsg/maths/mat4.h>
18 #include <vsg/maths/vec2.h>
19 #include <vsg/maths/vec3.h>
20 #include <vsg/maths/vec4.h>
21 
22 #include <vsg/io/Input.h>
23 #include <vsg/io/Output.h>
24 
25 #define VSG_array2D(N, T) \
26  using N = Array2D<T>; \
27  template<> \
28  constexpr const char* type_name<N>() noexcept { return "vsg::" #N; }
29 
30 namespace vsg
31 {
32 
33  template<typename T>
34  class Array2D : public Data
35  {
36  public:
37  using value_type = T;
40 
41  Array2D() :
42  _data(nullptr),
43  _width(0),
44  _height(0) {}
45 
46  Array2D(const Array2D& rhs) :
47  Data(rhs.properties, sizeof(value_type)),
48  _data(nullptr),
49  _width(rhs._width),
50  _height(rhs._height)
51  {
52  if (_width != 0 && _height != 0)
53  {
54  _data = _allocate(_width * _height);
55  auto dest_v = _data;
56  for (auto& v : rhs) *(dest_v++) = v;
57  }
58  dirty();
59  }
60 
61  Array2D(uint32_t width, uint32_t height, Properties in_properties = {}) :
62  Data(in_properties, sizeof(value_type)),
63  _data(_allocate(width * height)),
64  _width(width),
65  _height(height) { dirty(); }
66 
67  Array2D(uint32_t width, uint32_t height, value_type* data, Properties in_properties = {}) :
68  Data(in_properties, sizeof(value_type)),
69  _data(data),
70  _width(width),
71  _height(height) { dirty(); }
72 
73  Array2D(uint32_t width, uint32_t height, const value_type& value, Properties in_properties = {}) :
74  Data(in_properties, sizeof(value_type)),
75  _data(_allocate(width * height)),
76  _width(width),
77  _height(height)
78  {
79  for (auto& v : *this) v = value;
80  dirty();
81  }
82 
83  Array2D(ref_ptr<Data> data, uint32_t offset, uint32_t stride, uint32_t width, uint32_t height, Properties in_properties = {}) :
84  Data(),
85  _data(nullptr),
86  _width(0),
87  _height(0)
88  {
89  assign(data, offset, stride, width, height, in_properties);
90  }
91 
92  template<typename... Args>
93  static ref_ptr<Array2D> create(Args... args)
94  {
95  return ref_ptr<Array2D>(new Array2D(args...));
96  }
97 
98  std::size_t sizeofObject() const noexcept override { return sizeof(Array2D); }
99  const char* className() const noexcept override { return type_name<Array2D>(); }
100  const std::type_info& type_info() const noexcept override { return typeid(*this); }
101  bool is_compatible(const std::type_info& type) const noexcept override { return typeid(Array2D) == type || Data::is_compatible(type); }
102 
103  // implementation provided by Visitor.h
104  void accept(Visitor& visitor) override;
105  void accept(ConstVisitor& visitor) const override;
106 
107  void read(Input& input) override
108  {
109  std::size_t original_size = size();
110 
111  Data::read(input);
112 
113  uint32_t w = input.readValue<uint32_t>("width");
114  uint32_t h = input.readValue<uint32_t>("height");
115 
116  if (auto data_storage = input.readObject<Data>("storage"))
117  {
118  uint32_t offset = input.readValue<uint32_t>("offset");
119  assign(data_storage, offset, properties.stride, w, h, properties);
120  return;
121  }
122 
123  if (input.matchPropertyName("data"))
124  {
125  std::size_t new_size = computeValueCountIncludingMipmaps(w, h, 1, properties.maxNumMipmaps);
126 
127  if (_data) // if data already may be able to reuse it
128  {
129  if (original_size != new_size) // if existing data is a different size delete old, and create new
130  {
131  _delete();
132  _data = _allocate(new_size);
133  }
134  }
135  else // allocate space for data
136  {
137  _data = _allocate(new_size);
138  }
139 
140  properties.stride = sizeof(value_type);
141  _width = w;
142  _height = h;
143  _storage = nullptr;
144 
145  if (_data) input.read(new_size, _data);
146 
147  dirty();
148  }
149  }
150 
151  void write(Output& output) const override
152  {
153  Data::write(output);
154 
155  output.writeValue<uint32_t>("width", _width);
156  output.writeValue<uint32_t>("height", _height);
157 
158  output.writeObject("storage", _storage);
159  if (_storage)
160  {
161  auto offset = (reinterpret_cast<uintptr_t>(_data) - reinterpret_cast<uintptr_t>(_storage->dataPointer()));
162  output.writeValue<uint32_t>("offset", offset);
163  return;
164  }
165 
166  output.writePropertyName("data");
167  output.write(valueCount(), _data);
168  output.writeEndOfLine();
169  }
170 
171  std::size_t size() const { return (properties.maxNumMipmaps <= 1) ? static_cast<std::size_t>(_width * _height) : computeValueCountIncludingMipmaps(_width, _height, 1, properties.maxNumMipmaps); }
172 
173  bool available() const { return _data != nullptr; }
174  bool empty() const { return _data == nullptr; }
175 
176  void clear()
177  {
178  _delete();
179 
180  _width = 0;
181  _height = 0;
182  _data = nullptr;
183  _storage = nullptr;
184  }
185 
186  Array2D& operator=(const Array2D& rhs)
187  {
188  if (&rhs == this) return *this;
189 
190  clear();
191 
192  properties = rhs.properties;
193  _width = rhs._width;
194  _height = rhs._height;
195 
196  if (_width != 0 && _height != 0)
197  {
198  _data = _allocate(_width * _height);
199  auto dest_v = _data;
200  for (auto& v : rhs) *(dest_v++) = v;
201  }
202 
203  dirty();
204 
205  return *this;
206  }
207 
208  void assign(uint32_t width, uint32_t height, value_type* data, Properties in_properties = {})
209  {
210  _delete();
211 
212  properties = in_properties;
213  properties.stride = sizeof(value_type);
214  _width = width;
215  _height = height;
216  _data = data;
217  _storage = nullptr;
218 
219  dirty();
220  }
221 
222  void assign(ref_ptr<Data> storage, uint32_t offset, uint32_t stride, uint32_t width, uint32_t height, Properties in_properties = {})
223  {
224  _delete();
225 
226  _storage = storage;
227  properties = in_properties;
228  properties.stride = stride;
229  if (_storage && _storage->dataPointer())
230  {
231  _data = reinterpret_cast<value_type*>(reinterpret_cast<uint8_t*>(_storage->dataPointer()) + offset);
232  _width = width;
233  _height = height;
234  }
235  else
236  {
237  _data = nullptr;
238  _width = 0;
239  _height = 0;
240  }
241 
242  dirty();
243  }
244 
245  // release the data so that ownership can be passed on, the local data pointer and size is set to 0 and destruction of Array will no result in the data being deleted.
246  // when the data is stored in a separate vsg::Data object then return nullptr and do not attempt to release data.
247  void* dataRelease() override
248  {
249  if (!_storage)
250  {
251  void* tmp = _data;
252  _data = nullptr;
253  _width = 0;
254  _height = 0;
255  return tmp;
256  }
257  else
258  {
259  return nullptr;
260  }
261  }
262 
263  std::size_t valueSize() const override { return sizeof(value_type); }
264  std::size_t valueCount() const override { return size(); }
265 
266  bool dataAvailable() const override { return available(); }
267  std::size_t dataSize() const override { return size() * properties.stride; }
268 
269  void* dataPointer() override { return _data; }
270  const void* dataPointer() const override { return _data; }
271 
272  void* dataPointer(std::size_t i) override { return data(i); }
273  const void* dataPointer(std::size_t i) const override { return data(i); }
274 
275  uint32_t dimensions() const override { return 2; }
276  uint32_t width() const override { return _width; }
277  uint32_t height() const override { return _height; }
278  uint32_t depth() const override { return 1; }
279 
280  value_type* data() { return _data; }
281  const value_type* data() const { return _data; }
282 
283  inline value_type* data(std::size_t i) { return reinterpret_cast<value_type*>(reinterpret_cast<uint8_t*>(_data) + i * properties.stride); }
284  inline const value_type* data(std::size_t i) const { return reinterpret_cast<const value_type*>(reinterpret_cast<const uint8_t*>(_data) + i * properties.stride); }
285 
286  std::size_t index(uint32_t i, uint32_t j) const noexcept { return static_cast<std::size_t>(j) * _width + i; }
287 
288  value_type& operator[](std::size_t i) { return *data(i); }
289  const value_type& operator[](std::size_t i) const { return *data(i); }
290 
291  value_type& at(std::size_t i) { return *data(i); }
292  const value_type& at(std::size_t i) const { return *data(i); }
293 
294  value_type& operator()(uint32_t i, uint32_t j) { return *data(index(i, j)); }
295  const value_type& operator()(uint32_t i, uint32_t j) const { return *data(index(i, j)); }
296 
297  value_type& at(uint32_t i, uint32_t j) { return *data(index(i, j)); }
298  const value_type& at(uint32_t i, uint32_t j) const { return *data(index(i, j)); }
299 
300  void set(std::size_t i, const value_type& v) { *data(i) = v; }
301  void set(uint32_t i, uint32_t j, const value_type& v) { *data(index(i, j)) = v; }
302 
303  Data* storage() { return _storage; }
304  const Data* storage() const { return _storage; }
305 
306  iterator begin() { return iterator{_data, properties.stride}; }
307  const_iterator begin() const { return const_iterator{_data, properties.stride}; }
308 
309  iterator end() { return iterator{data(_width * _height), properties.stride}; }
310  const_iterator end() const { return const_iterator{data(_width * _height), properties.stride}; }
311 
312  protected:
313  virtual ~Array2D()
314  {
315  _delete();
316  }
317 
318  value_type* _allocate(size_t size) const
319  {
320  if (size == 0)
321  return nullptr;
322  else if (properties.allocatorType == ALLOCATOR_TYPE_NEW_DELETE)
323  return new value_type[size];
324  else if (properties.allocatorType == ALLOCATOR_TYPE_MALLOC_FREE)
325  return new (std::malloc(sizeof(value_type) * size)) value_type[size];
326  else
327  return new (vsg::allocate(sizeof(value_type) * size, ALLOCATOR_AFFINITY_DATA)) value_type[size];
328  }
329 
330  void _delete()
331  {
332  if (!_storage && _data)
333  {
334  if (properties.allocatorType == ALLOCATOR_TYPE_NEW_DELETE)
335  delete[] _data;
336  else if (properties.allocatorType == ALLOCATOR_TYPE_MALLOC_FREE)
337  std::free(_data);
338  else if (properties.allocatorType != 0)
339  vsg::deallocate(_data);
340  }
341  }
342 
343  private:
344  value_type* _data;
345  uint32_t _width;
346  uint32_t _height;
347  ref_ptr<Data> _storage;
348  };
349 
350  VSG_array2D(byteArray2D, int8_t);
351  VSG_array2D(ubyteArray2D, uint8_t);
352  VSG_array2D(shortArray2D, int16_t);
353  VSG_array2D(ushortArray2D, uint16_t);
354  VSG_array2D(intArray2D, int32_t);
355  VSG_array2D(uintArray2D, uint32_t);
356  VSG_array2D(floatArray2D, float);
357  VSG_array2D(doubleArray2D, double);
358 
359  VSG_array2D(vec2Array2D, vec2);
360  VSG_array2D(vec3Array2D, vec3);
361  VSG_array2D(vec4Array2D, vec4);
362 
363  VSG_array2D(dvec2Array2D, dvec2);
364  VSG_array2D(dvec3Array2D, dvec3);
365  VSG_array2D(dvec4Array2D, dvec4);
366 
367  VSG_array2D(bvec2Array2D, bvec2);
368  VSG_array2D(bvec3Array2D, bvec3);
369  VSG_array2D(bvec4Array2D, bvec4);
370 
371  VSG_array2D(ubvec2Array2D, ubvec2);
372  VSG_array2D(ubvec3Array2D, ubvec3);
373  VSG_array2D(ubvec4Array2D, ubvec4);
374 
375  VSG_array2D(svec2Array2D, svec2);
376  VSG_array2D(svec3Array2D, svec3);
377  VSG_array2D(svec4Array2D, svec4);
378 
379  VSG_array2D(usvec2Array2D, usvec2);
380  VSG_array2D(usvec3Array2D, usvec3);
381  VSG_array2D(usvec4Array2D, usvec4);
382 
383  VSG_array2D(ivec2Array2D, ivec2);
384  VSG_array2D(ivec3Array2D, ivec3);
385  VSG_array2D(ivec4Array2D, ivec4);
386 
387  VSG_array2D(uivec2Array2D, uivec2);
388  VSG_array2D(uivec3Array2D, uivec3);
389  VSG_array2D(uivec4Array2D, uivec4);
390 
391  VSG_array2D(block64Array2D, block64);
392  VSG_array2D(block128Array2D, block128);
393 
394 } // namespace vsg
Definition: Array2D.h:35
const std::type_info & type_info() const noexcept override
return the std::type_info of this Object
Definition: Array2D.h:100
Definition: Data.h:104
Properties properties
properties of the data such as format, origin, stride, dataVariance etc.
Definition: Data.h:173
void dirty()
increment the ModifiedCount to signify the data has been modified
Definition: Data.h:206
Definition: ref_ptr.h:22
Definition: Data.h:110
AllocatorType allocatorType
hint as how the data values may change during the lifetime of the vsg::Data.
Definition: Data.h:125
Definition: Data.h:60