vsg  1.0.4
VulkanSceneGraph library
Array3D.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_array3D(N, T) \
26  using N = Array3D<T>; \
27  template<> \
28  constexpr const char* type_name<N>() noexcept { return "vsg::" #N; }
29 
30 namespace vsg
31 {
32  template<typename T>
33  class Array3D : public Data
34  {
35  public:
36  using value_type = T;
39 
40  Array3D() :
41  _data(nullptr),
42  _width(0),
43  _height(0),
44  _depth(0) {}
45 
46  Array3D(const Array3D& rhs) :
47  Data(rhs.properties, sizeof(value_type)),
48  _data(nullptr),
49  _width(rhs._width),
50  _height(rhs._height),
51  _depth(rhs._depth)
52  {
53  if (_width != 0 && _height != 0 && _depth != 0)
54  {
55  _data = _allocate(_width * _height * _depth);
56  auto dest_v = _data;
57  for (auto& v : rhs) *(dest_v++) = v;
58  }
59  dirty();
60  }
61 
62  Array3D(uint32_t width, uint32_t height, uint32_t depth, Properties in_properties = {}) :
63  Data(in_properties, sizeof(value_type)),
64  _data(_allocate(width * height * depth)),
65  _width(width),
66  _height(height),
67  _depth(depth)
68  {
69  dirty();
70  }
71 
72  Array3D(uint32_t width, uint32_t height, uint32_t depth, value_type* data, Properties in_properties = {}) :
73  Data(in_properties, sizeof(value_type)),
74  _data(data),
75  _width(width),
76  _height(height),
77  _depth(depth) { dirty(); }
78 
79  Array3D(uint32_t width, uint32_t height, uint32_t depth, const value_type& value, Properties in_properties = {}) :
80  Data(in_properties, sizeof(value_type)),
81  _data(_allocate(width * height * depth)),
82  _width(width),
83  _height(height),
84  _depth(depth)
85  {
86  for (auto& v : *this) v = value;
87  dirty();
88  }
89 
90  Array3D(ref_ptr<Data> data, uint32_t offset, uint32_t stride, uint32_t width, uint32_t height, uint32_t depth, Properties in_properties = {}) :
91  Data(),
92  _data(nullptr),
93  _width(0),
94  _height(0),
95  _depth(0)
96  {
97  assign(data, offset, stride, width, height, depth, in_properties);
98  }
99 
100  template<typename... Args>
101  static ref_ptr<Array3D> create(Args... args)
102  {
103  return ref_ptr<Array3D>(new Array3D(args...));
104  }
105 
106  std::size_t sizeofObject() const noexcept override { return sizeof(Array3D); }
107  const char* className() const noexcept override { return type_name<Array3D>(); }
108  const std::type_info& type_info() const noexcept override { return typeid(*this); }
109  bool is_compatible(const std::type_info& type) const noexcept override { return typeid(Array3D) == type || Data::is_compatible(type); }
110 
111  // implementation provided by Visitor.h
112  void accept(Visitor& visitor) override;
113  void accept(ConstVisitor& visitor) const override;
114 
115  void read(Input& input) override
116  {
117  std::size_t original_size = size();
118 
119  Data::read(input);
120 
121  uint32_t w = input.readValue<uint32_t>("width");
122  uint32_t h = input.readValue<uint32_t>("height");
123  uint32_t d = input.readValue<uint32_t>("depth");
124 
125  if (auto data_storage = input.readObject<Data>("storage"))
126  {
127  uint32_t offset = input.readValue<uint32_t>("offset");
128  assign(data_storage, offset, properties.stride, w, h, d, properties);
129  return;
130  }
131 
132  if (input.matchPropertyName("data"))
133  {
134  std::size_t new_size = computeValueCountIncludingMipmaps(w, h, d, properties.maxNumMipmaps);
135 
136  if (_data) // if data already may be able to reuse it
137  {
138  if (original_size != new_size) // if existing data is a different size delete old, and create new
139  {
140  _delete();
141  _data = _allocate(new_size);
142  }
143  }
144  else // allocate space for data
145  {
146  _data = _allocate(new_size);
147  }
148 
149  properties.stride = sizeof(value_type);
150  _width = w;
151  _height = h;
152  _depth = d;
153  _storage = nullptr;
154 
155  if (_data) input.read(new_size, _data);
156 
157  dirty();
158  }
159  }
160 
161  void write(Output& output) const override
162  {
163  Data::write(output);
164 
165  output.writeValue<uint32_t>("width", _width);
166  output.writeValue<uint32_t>("height", _height);
167  output.writeValue<uint32_t>("depth", _depth);
168 
169  output.writeObject("storage", _storage);
170  if (_storage)
171  {
172  auto offset = (reinterpret_cast<uintptr_t>(_data) - reinterpret_cast<uintptr_t>(_storage->dataPointer()));
173  output.writeValue<uint32_t>("offset", offset);
174  return;
175  }
176 
177  output.writePropertyName("data");
178  output.write(valueCount(), _data);
179  output.writeEndOfLine();
180  }
181 
182  std::size_t size() const { return (properties.maxNumMipmaps <= 1) ? (static_cast<std::size_t>(_width) * _height * _depth) : computeValueCountIncludingMipmaps(_width, _height, _depth, properties.maxNumMipmaps); }
183 
184  bool available() const { return _data != nullptr; }
185  bool empty() const { return _data == nullptr; }
186 
187  void clear()
188  {
189  _delete();
190 
191  _width = 0;
192  _height = 0;
193  _depth = 0;
194  _data = nullptr;
195  _storage = nullptr;
196  }
197 
198  Array3D& operator=(const Array3D& rhs)
199  {
200  if (&rhs == this) return *this;
201 
202  clear();
203 
204  properties = rhs.properties;
205  _width = rhs._width;
206  _height = rhs._height;
207  _depth = rhs._depth;
208 
209  if (_width != 0 && _height != 0 && _depth != 0)
210  {
211  _data = _allocate(_width * _height * _depth);
212  auto dest_v = _data;
213  for (auto& v : rhs) *(dest_v++) = v;
214  }
215 
216  dirty();
217 
218  return *this;
219  }
220 
221  void assign(uint32_t width, uint32_t height, uint32_t depth, value_type* data, Properties in_properties = {})
222  {
223  _delete();
224 
225  properties = in_properties;
226  properties.stride = sizeof(value_type);
227  _width = width;
228  _height = height;
229  _depth = depth;
230  _data = data;
231  _storage = nullptr;
232 
233  dirty();
234  }
235 
236  void assign(ref_ptr<Data> storage, uint32_t offset, uint32_t stride, uint32_t width, uint32_t height, uint32_t depth, Properties in_properties = {})
237  {
238  _delete();
239 
240  _storage = storage;
241  properties = in_properties;
242  properties.stride = stride;
243  if (_storage && _storage->dataPointer())
244  {
245  _data = reinterpret_cast<value_type*>(reinterpret_cast<uint8_t*>(_storage->dataPointer()) + offset);
246  _width = width;
247  _height = height;
248  _depth = depth;
249  }
250  else
251  {
252  _data = nullptr;
253  _width = 0;
254  _height = 0;
255  _depth = 0;
256  }
257 
258  dirty();
259  }
260 
261  // 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.
262  // when the data is stored in a separate vsg::Data object then return nullptr and do not attempt to release data.
263  void* dataRelease() override
264  {
265  if (!_storage)
266  {
267  void* tmp = _data;
268  _data = nullptr;
269  _width = 0;
270  _height = 0;
271  _depth = 0;
272  return tmp;
273  }
274  else
275  {
276  return nullptr;
277  }
278  }
279 
280  std::size_t valueSize() const override { return sizeof(value_type); }
281  std::size_t valueCount() const override { return size(); }
282 
283  bool dataAvailable() const override { return available(); }
284  std::size_t dataSize() const override { return size() * properties.stride; }
285 
286  void* dataPointer() override { return _data; }
287  const void* dataPointer() const override { return _data; }
288 
289  void* dataPointer(std::size_t i) override { return data(i); }
290  const void* dataPointer(std::size_t i) const override { return data(i); }
291 
292  uint32_t dimensions() const override { return 3; }
293 
294  uint32_t width() const override { return _width; }
295  uint32_t height() const override { return _height; }
296  uint32_t depth() const override { return _depth; }
297 
298  value_type* data() { return _data; }
299  const value_type* data() const { return _data; }
300 
301  inline value_type* data(std::size_t i) { return reinterpret_cast<value_type*>(reinterpret_cast<uint8_t*>(_data) + i * properties.stride); }
302  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); }
303 
304  std::size_t index(uint32_t i, uint32_t j, uint32_t k) const noexcept { return static_cast<std::size_t>(k * _width * _height + j * _width + i); }
305 
306  value_type& operator[](std::size_t i) { return *data(i); }
307  const value_type& operator[](std::size_t i) const { return *data(i); }
308 
309  value_type& at(std::size_t i) { return *data(i); }
310  const value_type& at(std::size_t i) const { return *data(i); }
311 
312  value_type& operator()(uint32_t i, uint32_t j, uint32_t k) { return *data(index(i, j, k)); }
313  const value_type& operator()(uint32_t i, uint32_t j, uint32_t k) const { return *data(index(i, j, k)); }
314 
315  value_type& at(uint32_t i, uint32_t j, uint32_t k) { return *data(index(i, j, k)); }
316  const value_type& at(uint32_t i, uint32_t j, uint32_t k) const { return *data(index(i, j, k)); }
317 
318  void set(std::size_t i, const value_type& v) { *data(i) = v; }
319  void set(uint32_t i, uint32_t j, uint32_t k, const value_type& v) { *data(index(i, j, k)) = v; }
320 
321  Data* storage() { return _storage; }
322  const Data* storage() const { return _storage; }
323 
324  iterator begin() { return iterator{_data, properties.stride}; }
325  const_iterator begin() const { return const_iterator{_data, properties.stride}; }
326 
327  iterator end() { return iterator{data(_width * _height * _depth), properties.stride}; }
328  const_iterator end() const { return const_iterator{data(_width * _height * _depth), properties.stride}; }
329 
330  protected:
331  virtual ~Array3D()
332  {
333  _delete();
334  }
335 
336  value_type* _allocate(size_t size) const
337  {
338  if (size == 0)
339  return nullptr;
340  else if (properties.allocatorType == ALLOCATOR_TYPE_NEW_DELETE)
341  return new value_type[size];
342  else if (properties.allocatorType == ALLOCATOR_TYPE_MALLOC_FREE)
343  return new (std::malloc(sizeof(value_type) * size)) value_type[size];
344  else
345  return new (vsg::allocate(sizeof(value_type) * size, ALLOCATOR_AFFINITY_DATA)) value_type[size];
346  }
347 
348  void _delete()
349  {
350  if (!_storage && _data)
351  {
352  if (properties.allocatorType == ALLOCATOR_TYPE_NEW_DELETE)
353  delete[] _data;
354  else if (properties.allocatorType == ALLOCATOR_TYPE_MALLOC_FREE)
355  std::free(_data);
356  else if (properties.allocatorType != 0)
357  vsg::deallocate(_data);
358  }
359  }
360 
361  private:
362  value_type* _data;
363  uint32_t _width;
364  uint32_t _height;
365  uint32_t _depth;
366  ref_ptr<Data> _storage;
367  };
368 
369  VSG_array3D(byteArray3D, int8_t);
370  VSG_array3D(ubyteArray3D, uint8_t);
371  VSG_array3D(shortArray3D, int16_t);
372  VSG_array3D(ushortArray3D, uint16_t);
373  VSG_array3D(intArray3D, int32_t);
374  VSG_array3D(uintArray3D, uint32_t);
375  VSG_array3D(floatArray3D, float);
376  VSG_array3D(doubleArray3D, double);
377 
378  VSG_array3D(vec2Array3D, vec2);
379  VSG_array3D(vec3Array3D, vec3);
380  VSG_array3D(vec4Array3D, vec4);
381 
382  VSG_array3D(dvec2Array3D, dvec2);
383  VSG_array3D(dvec3Array3D, dvec3);
384  VSG_array3D(dvec4Array3D, dvec4);
385 
386  VSG_array3D(ubvec2Array3D, ubvec2);
387  VSG_array3D(ubvec3Array3D, ubvec3);
388  VSG_array3D(ubvec4Array3D, ubvec4);
389 
390  VSG_array3D(block64Array3D, block64);
391  VSG_array3D(block128Array3D, block128);
392 
393 } // namespace vsg
Definition: Array3D.h:34
const std::type_info & type_info() const noexcept override
return the std::type_info of this Object
Definition: Array3D.h:108
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