vsg: include/vsg/core/Array3D.h Source File

vsg 1.1.13 VulkanSceneGraph library

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