vsg  1.1.0
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  ref_ptr<Data> clone() const override
107  {
108  return ref_ptr<Array3D>(new Array3D(*this));
109  }
110 
111  size_t sizeofObject() const noexcept override { return sizeof(Array3D); }
112  const char* className() const noexcept override { return type_name<Array3D>(); }
113  const std::type_info& type_info() const noexcept override { return typeid(*this); }
114  bool is_compatible(const std::type_info& type) const noexcept override { return typeid(Array3D) == type || Data::is_compatible(type); }
115 
116  // implementation provided by Visitor.h
117  void accept(Visitor& visitor) override;
118  void accept(ConstVisitor& visitor) const override;
119 
120  void read(Input& input) override
121  {
122  size_t original_size = size();
123 
124  Data::read(input);
125 
126  uint32_t w = input.readValue<uint32_t>("width");
127  uint32_t h = input.readValue<uint32_t>("height");
128  uint32_t d = input.readValue<uint32_t>("depth");
129 
130  if (auto data_storage = input.readObject<Data>("storage"))
131  {
132  uint32_t offset = input.readValue<uint32_t>("offset");
133  assign(data_storage, offset, properties.stride, w, h, d, properties);
134  return;
135  }
136 
137  if (input.matchPropertyName("data"))
138  {
139  size_t new_size = computeValueCountIncludingMipmaps(w, h, d, properties.maxNumMipmaps);
140 
141  if (_data) // if data exists already may be able to reuse it
142  {
143  if (original_size != new_size) // if existing data is a different size delete old, and create new
144  {
145  _delete();
146  _data = _allocate(new_size);
147  }
148  }
149  else // allocate space for data
150  {
151  _data = _allocate(new_size);
152  }
153 
154  properties.stride = sizeof(value_type);
155  _width = w;
156  _height = h;
157  _depth = d;
158  _storage = nullptr;
159 
160  if (_data) input.read(new_size, _data);
161 
162  dirty();
163  }
164  }
165 
166  void write(Output& output) const override
167  {
168  Data::write(output);
169 
170  output.writeValue<uint32_t>("width", _width);
171  output.writeValue<uint32_t>("height", _height);
172  output.writeValue<uint32_t>("depth", _depth);
173 
174  output.writeObject("storage", _storage);
175  if (_storage)
176  {
177  auto offset = (reinterpret_cast<uintptr_t>(_data) - reinterpret_cast<uintptr_t>(_storage->dataPointer()));
178  output.writeValue<uint32_t>("offset", offset);
179  return;
180  }
181 
182  output.writePropertyName("data");
183  output.write(valueCount(), _data);
184  output.writeEndOfLine();
185  }
186 
187  size_t size() const { return (properties.maxNumMipmaps <= 1) ? (static_cast<size_t>(_width) * _height * _depth) : computeValueCountIncludingMipmaps(_width, _height, _depth, properties.maxNumMipmaps); }
188 
189  bool available() const { return _data != nullptr; }
190  bool empty() const { return _data == nullptr; }
191 
192  void clear()
193  {
194  _delete();
195 
196  _width = 0;
197  _height = 0;
198  _depth = 0;
199  _data = nullptr;
200  _storage = nullptr;
201  }
202 
203  Array3D& operator=(const Array3D& rhs)
204  {
205  if (&rhs == this) return *this;
206 
207  clear();
208 
209  properties = rhs.properties;
210  _width = rhs._width;
211  _height = rhs._height;
212  _depth = rhs._depth;
213 
214  if (_width != 0 && _height != 0 && _depth != 0)
215  {
216  _data = _allocate(_width * _height * _depth);
217  auto dest_v = _data;
218  for (auto& v : rhs) *(dest_v++) = v;
219  }
220 
221  dirty();
222 
223  return *this;
224  }
225 
226  void assign(uint32_t width, uint32_t height, uint32_t depth, value_type* data, Properties in_properties = {})
227  {
228  _delete();
229 
230  properties = in_properties;
231  properties.stride = sizeof(value_type);
232  _width = width;
233  _height = height;
234  _depth = depth;
235  _data = data;
236  _storage = nullptr;
237 
238  dirty();
239  }
240 
241  void assign(ref_ptr<Data> storage, uint32_t offset, uint32_t stride, uint32_t width, uint32_t height, uint32_t depth, Properties in_properties = {})
242  {
243  _delete();
244 
245  _storage = storage;
246  properties = in_properties;
247  properties.stride = stride;
248  if (_storage && _storage->dataPointer())
249  {
250  _data = reinterpret_cast<value_type*>(reinterpret_cast<uint8_t*>(_storage->dataPointer()) + offset);
251  _width = width;
252  _height = height;
253  _depth = depth;
254  }
255  else
256  {
257  _data = nullptr;
258  _width = 0;
259  _height = 0;
260  _depth = 0;
261  }
262 
263  dirty();
264  }
265 
266  // release the data so that ownership can be passed on, the local data pointer and size is set to 0 so that destruction of Array will not result in the data being deleted.
267  // if the data is stored in a separate vsg::Data object then return nullptr and do not attempt to release data.
268  void* dataRelease() override
269  {
270  if (!_storage)
271  {
272  void* tmp = _data;
273  _data = nullptr;
274  _width = 0;
275  _height = 0;
276  _depth = 0;
277  return tmp;
278  }
279  else
280  {
281  return nullptr;
282  }
283  }
284 
285  size_t valueSize() const override { return sizeof(value_type); }
286  size_t valueCount() const override { return size(); }
287 
288  bool dataAvailable() const override { return available(); }
289  size_t dataSize() const override { return size() * properties.stride; }
290 
291  void* dataPointer() override { return _data; }
292  const void* dataPointer() const override { return _data; }
293 
294  void* dataPointer(size_t i) override { return data(i); }
295  const void* dataPointer(size_t i) const override { return data(i); }
296 
297  uint32_t dimensions() const override { return 3; }
298 
299  uint32_t width() const override { return _width; }
300  uint32_t height() const override { return _height; }
301  uint32_t depth() const override { return _depth; }
302 
303  value_type* data() { return _data; }
304  const value_type* data() const { return _data; }
305 
306  inline value_type* data(size_t i) { return reinterpret_cast<value_type*>(reinterpret_cast<uint8_t*>(_data) + i * properties.stride); }
307  inline const value_type* data(size_t i) const { return reinterpret_cast<const value_type*>(reinterpret_cast<const uint8_t*>(_data) + i * properties.stride); }
308 
309  size_t index(uint32_t i, uint32_t j, uint32_t k) const noexcept { return static_cast<size_t>(k * _width * _height + j * _width + i); }
310 
311  value_type& operator[](size_t i) { return *data(i); }
312  const value_type& operator[](size_t i) const { return *data(i); }
313 
314  value_type& at(size_t i) { return *data(i); }
315  const value_type& at(size_t i) const { return *data(i); }
316 
317  value_type& operator()(uint32_t i, uint32_t j, uint32_t k) { return *data(index(i, j, k)); }
318  const value_type& operator()(uint32_t i, uint32_t j, uint32_t k) const { return *data(index(i, j, k)); }
319 
320  value_type& at(uint32_t i, uint32_t j, uint32_t k) { return *data(index(i, j, k)); }
321  const value_type& at(uint32_t i, uint32_t j, uint32_t k) const { return *data(index(i, j, k)); }
322 
323  void set(size_t i, const value_type& v) { *data(i) = v; }
324  void set(uint32_t i, uint32_t j, uint32_t k, const value_type& v) { *data(index(i, j, k)) = v; }
325 
326  Data* storage() { return _storage; }
327  const Data* storage() const { return _storage; }
328 
329  iterator begin() { return iterator{_data, properties.stride}; }
330  const_iterator begin() const { return const_iterator{_data, properties.stride}; }
331 
332  iterator end() { return iterator{data(_width * _height * _depth), properties.stride}; }
333  const_iterator end() const { return const_iterator{data(_width * _height * _depth), properties.stride}; }
334 
335  protected:
336  virtual ~Array3D()
337  {
338  _delete();
339  }
340 
341  value_type* _allocate(size_t size) const
342  {
343  if (size == 0)
344  return nullptr;
345  else if (properties.allocatorType == ALLOCATOR_TYPE_NEW_DELETE)
346  return new value_type[size];
347  else if (properties.allocatorType == ALLOCATOR_TYPE_MALLOC_FREE)
348  return new (std::malloc(sizeof(value_type) * size)) value_type[size];
349  else
350  return new (vsg::allocate(sizeof(value_type) * size, ALLOCATOR_AFFINITY_DATA)) value_type[size];
351  }
352 
353  void _delete()
354  {
355  if (!_storage && _data)
356  {
357  if (properties.allocatorType == ALLOCATOR_TYPE_NEW_DELETE)
358  delete[] _data;
359  else if (properties.allocatorType == ALLOCATOR_TYPE_MALLOC_FREE)
360  std::free(_data);
361  else if (properties.allocatorType != 0)
362  vsg::deallocate(_data);
363  }
364  }
365 
366  private:
367  value_type* _data;
368  uint32_t _width;
369  uint32_t _height;
370  uint32_t _depth;
371  ref_ptr<Data> _storage;
372  };
373 
374  VSG_array3D(byteArray3D, int8_t);
375  VSG_array3D(ubyteArray3D, uint8_t);
376  VSG_array3D(shortArray3D, int16_t);
377  VSG_array3D(ushortArray3D, uint16_t);
378  VSG_array3D(intArray3D, int32_t);
379  VSG_array3D(uintArray3D, uint32_t);
380  VSG_array3D(floatArray3D, float);
381  VSG_array3D(doubleArray3D, double);
382 
383  VSG_array3D(vec2Array3D, vec2);
384  VSG_array3D(vec3Array3D, vec3);
385  VSG_array3D(vec4Array3D, vec4);
386 
387  VSG_array3D(dvec2Array3D, dvec2);
388  VSG_array3D(dvec3Array3D, dvec3);
389  VSG_array3D(dvec4Array3D, dvec4);
390 
391  VSG_array3D(ubvec2Array3D, ubvec2);
392  VSG_array3D(ubvec3Array3D, ubvec3);
393  VSG_array3D(ubvec4Array3D, ubvec4);
394 
395  VSG_array3D(block64Array3D, block64);
396  VSG_array3D(block128Array3D, block128);
397 
398 } // 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:113
Definition: Data.h:110
Properties properties
properties of the data such as format, origin, stride, dataVariance etc.
Definition: Data.h:161
void dirty()
increment the ModifiedCount to signify the data has been modified
Definition: Data.h:196
Definition: ref_ptr.h:22
Definition: Data.h:116
AllocatorType allocatorType
hint as to how the data values may change during the lifetime of the vsg::Data.
Definition: Data.h:131
Definition: Data.h:66