Branch data Line data Source code
1 : : #pragma once
2 : :
3 : : /*
4 : : MIT License
5 : :
6 : : Copyright (c) 2022-2024 Stephane Cuillerdier (aka aiekick)
7 : :
8 : : Permission is hereby granted, free of charge, to any person obtaining a copy
9 : : of this software and associated documentation files (the "Software"), to deal
10 : : in the Software without restriction, including without limitation the rights
11 : : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 : : copies of the Software, and to permit persons to whom the Software is
13 : : furnished to do so, subject to the following conditions:
14 : :
15 : : The above copyright notice and this permission notice shall be included in all
16 : : copies or substantial portions of the Software.
17 : :
18 : : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 : : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 : : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 : : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 : : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 : : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 : : SOFTWARE.
25 : : */
26 : :
27 : : // ezVdb is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
28 : :
29 : : #include <unordered_map>
30 : : #include <iostream>
31 : : #include <cassert>
32 : : #include <iomanip>
33 : : #include <cstdint>
34 : : #include <sstream>
35 : : #include <cstring>
36 : : #include <limits>
37 : : #include <string>
38 : : #include <vector>
39 : : #include <memory>
40 : : #include <array>
41 : : #include <map>
42 : :
43 : : #include "ezMath.hpp"
44 : :
45 : : namespace ez {
46 : : namespace file {
47 : : namespace vdb {
48 : :
49 : 120426 : static void write_ptr(FILE* fp, const void* data, size_t elementSize, size_t count = 1) {
50 : 120426 : fwrite(data, elementSize, count, fp);
51 : 120426 : }
52 : 41802 : static void write_ptr(FILE* fp, void* data, size_t elementSize, size_t count = 1) {
53 : 41802 : fwrite(data, elementSize, count, fp);
54 : 41802 : }
55 : :
56 : : template <typename T>
57 : 41192 : void write_data(FILE* fp, T data) {
58 : 41192 : write_ptr(fp, &data, sizeof(T));
59 : 41192 : }
60 : :
61 : : template <typename T>
62 : 600 : void write_data_arr(FILE* fp, T* data, size_t count) {
63 : 600 : write_ptr(fp, data, sizeof(T), count);
64 : 600 : }
65 : :
66 : : template <typename T>
67 : 120096 : void write_data_arr(FILE* fp, const T* data, size_t count) {
68 : 120096 : write_ptr(fp, data, sizeof(T), count);
69 : 120096 : }
70 : :
71 : 330 : static void write_string(FILE* fp, const std::string& str) {
72 : 330 : write_ptr(fp, str.data(), sizeof(uint8_t), str.size());
73 : 330 : }
74 : 60 : inline void write_vec3i(FILE* fp, const std::array<int32_t, 3>& data) {
75 : 60 : write_data_arr<int32_t>(fp, data.data(), 3);
76 : 60 : }
77 : :
78 : 320 : inline void write_name(FILE* fp, const std::string& name) {
79 : 320 : write_data<uint32_t>(fp, (uint32_t)name.size());
80 : 320 : write_string(fp, name);
81 : 320 : }
82 : :
83 : 60 : inline void write_meta_string(FILE* fp, const std::string& name, const std::string& str) {
84 : 60 : write_name(fp, name);
85 : 60 : write_name(fp, "string");
86 : 60 : write_name(fp, str);
87 : 60 : }
88 : :
89 : 0 : inline void write_meta_bool(FILE* fp, const std::string& name, bool flag) {
90 : 0 : write_name(fp, name);
91 : 0 : write_name(fp, "bool");
92 : 0 : write_data<uint32_t>(fp, 1); // one byte is used to store the bool
93 : 0 : write_data<uint8_t>(fp, flag ? 1 : 0);
94 : 0 : }
95 : :
96 : 40 : inline void write_meta_vec3i(FILE* fp, const std::string& name, const std::array<int32_t, 3>& data) {
97 : 40 : write_name(fp, name);
98 : 40 : write_name(fp, "vec3i");
99 : 40 : write_data<uint32_t>(fp, 12U); // 12 bytes (4 bytes * 3) are used to store the vec3i
100 : 40 : write_vec3i(fp, data);
101 : 40 : }
102 : :
103 : : class ATree {
104 : : protected:
105 : : dAABBCC m_Volume;
106 : : std::string m_Name;
107 : :
108 : : protected:
109 : : virtual bool addVoxel(uint32_t vX, uint32_t vY, uint32_t vZ, void* vDatas, size_t vByteSize, size_t vCount) = 0;
110 : :
111 : 1800000 : static uint32_t getBitIndex4(uint32_t vX, uint32_t vY, uint32_t vZ) {
112 : 1800000 : const auto& x = vX & (uint32_t)(4096 - 1);
113 : 1800000 : const auto& y = vY & (uint32_t)(4096 - 1);
114 : 1800000 : const auto& z = vZ & (uint32_t)(4096 - 1);
115 : 1800000 : uint32_t idx_3d[3] = {x >> 7, y >> 7, z >> 7};
116 : 1800000 : uint64_t idx = idx_3d[2] | (idx_3d[1] << 5) | (idx_3d[0] << 10);
117 : 1800000 : return static_cast<uint32_t>(idx);
118 : 1800000 : }
119 : :
120 : 1800000 : static uint32_t getBitIndex3(uint32_t vX, uint32_t vY, uint32_t vZ) {
121 : 1800000 : const auto& x = vX & (uint32_t)(128 - 1);
122 : 1800000 : const auto& y = vY & (uint32_t)(128 - 1);
123 : 1800000 : const auto& z = vZ & (uint32_t)(128 - 1);
124 : 1800000 : uint32_t idx_3d[3] = {x >> 3, y >> 3, z >> 3};
125 : 1800000 : uint64_t idx = idx_3d[2] | (idx_3d[1] << 4) | (idx_3d[0] << 8);
126 : 1800000 : return static_cast<uint32_t>(idx);
127 : 1800000 : }
128 : :
129 : 1800000 : static uint32_t getBitIndex0(uint32_t vX, uint32_t vY, uint32_t vZ) {
130 : 1800000 : const auto& x = vX & (uint32_t)(8 - 1);
131 : 1800000 : const auto& y = vY & (uint32_t)(8 - 1);
132 : 1800000 : const auto& z = vZ & (uint32_t)(8 - 1);
133 : 1800000 : uint32_t idx_3d[3] = {x >> 0, y >> 0, z >> 0};
134 : 1800000 : uint64_t idx = idx_3d[2] | (idx_3d[1] << 3) | (idx_3d[0] << 6);
135 : 1800000 : return static_cast<uint32_t>(idx);
136 : 1800000 : }
137 : :
138 : 80384 : static int32_t count_trailing_zeros(uint64_t value) {
139 : 80384 : int32_t count = 0;
140 [ + + ][ + - ]: 1996520 : while ((value & 1) == 0 && value != 0) {
141 : 1916136 : ++count;
142 : 1916136 : value >>= 1;
143 : 1916136 : }
144 : 80384 : return count;
145 : 80384 : }
146 : :
147 : : public:
148 : 20 : ATree(const std::string& vName) : m_Name(vName) {
149 : 20 : }
150 : 20 : virtual ~ATree() = default;
151 : :
152 : : virtual void write(FILE* vFp) = 0;
153 : : };
154 : :
155 : : template <typename TType, size_t TCount>
156 : : class VdbTree : public ATree {
157 : : private:
158 : : struct Node3 {
159 : : uint64_t mask[8] = {};
160 : : std::array<TType, TCount> data[512] = {}; // data
161 : : };
162 : :
163 : : struct Node4 {
164 : : uint64_t mask[64] = {};
165 : : std::map<uint32_t, Node3> nodes; // loc, node
166 : : };
167 : :
168 : : struct Node5 {
169 : : uint64_t mask[512] = {};
170 : : std::map<uint32_t, Node4> nodes; // loc, node
171 : : };
172 : :
173 : 180 : void writeNode4EmptyHeader(FILE* fp, Node4* node) {
174 : 180 : write_data_arr<uint64_t>(fp, node->mask, 64);
175 : 180 : static std::vector<uint64_t> mask_arr_uint64_empty(64); // we dont use a std::array for not increase the bin size
176 : 180 : write_data_arr<uint64_t>(fp, mask_arr_uint64_empty.data(), mask_arr_uint64_empty.size());
177 : 180 : write_data<uint8_t>(fp, 6);
178 : 180 : static std::vector<float> mask_arr_float_empty(4096);
179 : 180 : write_data_arr<float>(fp, mask_arr_float_empty.data(), mask_arr_float_empty.size());
180 : 180 : }
181 : :
182 : 20 : void writeNode5EmptyHeader(FILE* fp, Node5* node) {
183 : 20 : write_vec3i(fp, {0, 0, 0});
184 : 20 : write_data_arr<uint64_t>(fp, node->mask, 512);
185 : 20 : static std::vector<uint64_t> mask_arr_uint64_empty(512); // we dont use a std::array for not increase the bin size
186 : 20 : write_data_arr<uint64_t>(fp, mask_arr_uint64_empty.data(), mask_arr_uint64_empty.size());
187 : 20 : write_data<uint8_t>(fp, 6);
188 : 20 : static std::vector<float> mask_arr_float_empty(32768);
189 : 20 : write_data_arr<float>(fp, mask_arr_float_empty.data(), mask_arr_float_empty.size());
190 : 20 : }
191 : :
192 : 20 : void writeTree(FILE* fp) {
193 : 20 : write_data<uint32_t>(fp, 1);
194 : 20 : write_data<float>(fp, 0);
195 : 20 : write_data<uint32_t>(fp, 0);
196 : 20 : write_data<uint32_t>(fp, 1);
197 : 20 : auto& nodes5Ref = m_Nodes;
198 : 20 : writeNode5EmptyHeader(fp, &nodes5Ref);
199 : 20 : size_t word5_idx = 0;
200 [ + + ][ + + ]: 10240 : for (auto word5 : nodes5Ref.mask) {
201 : 10240 : const auto& base_bit_4_idx = ((uint32_t)word5_idx++) * 64;
202 [ + + ][ + + ]: 10420 : for (; word5 != 0; word5 &= word5 - 1) {
203 : 180 : const auto& bit_4_index = base_bit_4_idx + (uint32_t)count_trailing_zeros(word5);
204 : 180 : auto& nodes4Ref = nodes5Ref.nodes.at(bit_4_index);
205 : 180 : writeNode4EmptyHeader(fp, &nodes4Ref);
206 : 180 : size_t word4_idx = 0;
207 [ + + ][ + + ]: 11520 : for (auto word4 : nodes4Ref.mask) {
208 : 11520 : const auto& base_bit_3_idx = ((uint32_t)word4_idx++) * 64;
209 [ + + ][ + + ]: 51532 : for (; word4 != 0; word4 &= word4 - 1) {
210 : 40012 : const auto& bit_3_index = base_bit_3_idx + (uint32_t)count_trailing_zeros(word4);
211 : 40012 : const auto& nodes3Ref = nodes4Ref.nodes.at(bit_3_index);
212 : 40012 : write_data_arr<uint64_t>(fp, nodes3Ref.mask, 8);
213 : 40012 : }
214 : 11520 : }
215 : 180 : }
216 : 10240 : }
217 : 20 : word5_idx = 0;
218 [ + + ][ + + ]: 10240 : for (auto word5 : nodes5Ref.mask) {
219 : 10240 : const auto& base_bit_4_idx = ((uint32_t)word5_idx++) * 64;
220 [ + + ][ + + ]: 10420 : for (; word5 != 0; word5 &= word5 - 1) {
221 : 180 : const auto& bit_4_index = base_bit_4_idx + (uint32_t)count_trailing_zeros(word5);
222 : 180 : const auto& nodes4Ref = nodes5Ref.nodes.at(bit_4_index);
223 : 180 : size_t word4_idx = 0;
224 [ + + ][ + + ]: 11520 : for (auto word4 : nodes4Ref.mask) {
225 : 11520 : const auto& base_bit_3_idx = ((uint32_t)word4_idx++) * 64;
226 [ + + ][ + + ]: 51532 : for (; word4 != 0; word4 &= word4 - 1) {
227 : 40012 : const auto& bit_3_index = base_bit_3_idx + (uint32_t)count_trailing_zeros(word4);
228 : 40012 : const auto& nodes3Ref = nodes4Ref.nodes.at(bit_3_index);
229 : 40012 : write_data_arr<uint64_t>(fp, nodes3Ref.mask, 8);
230 : 40012 : write_data<uint8_t>(fp, 6);
231 : 40012 : write_data_arr<std::array<TType, TCount>>(fp, nodes3Ref.data, 512);
232 : 40012 : }
233 : 11520 : }
234 : 180 : }
235 : 10240 : }
236 : 20 : }
237 : :
238 : 20 : void writeMetadata(FILE* fp) {
239 : : // Number of entries
240 : 20 : write_data<uint32_t>(fp, 5);
241 : 20 : write_meta_string(fp, "class", "unknown");
242 : 20 : write_meta_string(fp, "file_compression", "none");
243 : 20 : write_meta_vec3i(fp, "file_bbox_max", {(int32_t)m_Volume.upperBound.x, (int32_t)m_Volume.upperBound.y, (int32_t)m_Volume.upperBound.z});
244 : 20 : write_meta_vec3i(fp, "file_bbox_min", {(int32_t)m_Volume.lowerBound.x, (int32_t)m_Volume.lowerBound.y, (int32_t)m_Volume.lowerBound.z});
245 : 20 : write_meta_string(fp, "name", m_Name);
246 : 20 : }
247 : :
248 : 20 : void writeTransform(FILE* fp) {
249 : 20 : write_name(fp, "UniformScaleTranslateMap");
250 : : // write Translation
251 : 20 : const auto& center = m_Volume.GetCenter();
252 : 20 : write_data<double>(fp, -center.x);
253 : 20 : write_data<double>(fp, -center.y);
254 : 20 : write_data<double>(fp, -center.z);
255 : : // write ScaleValues
256 : 20 : write_data<double>(fp, 1.0);
257 : 20 : write_data<double>(fp, 1.0);
258 : 20 : write_data<double>(fp, 1.0);
259 : : // write VoxelSize
260 : 20 : write_data<double>(fp, 1.0);
261 : 20 : write_data<double>(fp, 1.0);
262 : 20 : write_data<double>(fp, 1.0);
263 : : // write ScaleValuesInverse
264 : 20 : write_data<double>(fp, 1.0);
265 : 20 : write_data<double>(fp, 1.0);
266 : 20 : write_data<double>(fp, 1.0);
267 : : // write InvScaleSqr
268 : 20 : write_data<double>(fp, 1.0);
269 : 20 : write_data<double>(fp, 1.0);
270 : 20 : write_data<double>(fp, 1.0);
271 : : // write InvTwiceScale;
272 : 20 : write_data<double>(fp, 0.5);
273 : 20 : write_data<double>(fp, 0.5);
274 : 20 : write_data<double>(fp, 0.5);
275 : 20 : }
276 : :
277 : : // thoses functions must be specialized or derived
278 : 0 : virtual std::string getTypeName() {
279 : 0 : std::cout << "getTypeName is not specialized for your Type" << std::endl;
280 : 0 : assert(0);
281 : 0 : return "";
282 : 0 : }
283 : :
284 : : private:
285 : : Node5 m_Nodes;
286 : :
287 : : public:
288 : 20 : VdbTree(const std::string& vName) : ATree(vName) {
289 : 20 : }
290 : 20 : virtual ~VdbTree() = default;
291 : :
292 : 1800000 : bool addVoxel(uint32_t vX, uint32_t vY, uint32_t vZ, void* vDatas, size_t vByteSize, size_t vCount) override final {
293 [ + - ][ + - ]: 1800000 : if (vDatas != nullptr && vByteSize == sizeof(TType) && vCount == TCount) {
[ + - ][ + - ]
[ + - ][ + - ]
294 : 1800000 : m_Volume.Combine(ez::dvec3((float)vX, (float)vY, (float)vZ));
295 : 1800000 : const auto& bit_index_4 = getBitIndex4(vX, vY, vZ);
296 : 1800000 : const auto& bit_index_3 = getBitIndex3(vX, vY, vZ);
297 : 1800000 : const auto& bit_index_0 = getBitIndex0(vX, vY, vZ);
298 : 1800000 : auto& nodes4Ref = m_Nodes.nodes[bit_index_4];
299 : 1800000 : auto& nodes3Ref = nodes4Ref.nodes[bit_index_3];
300 : 1800000 : m_Nodes.mask[bit_index_4 >> 6] |= static_cast<uint64_t>(1) << (bit_index_4 & (64 - 1)); // active the voxel 4
301 : 1800000 : nodes4Ref.mask[bit_index_3 >> 6] |= static_cast<uint64_t>(1) << (bit_index_3 & (64 - 1)); // active the voxel 3
302 : 1800000 : nodes3Ref.mask[bit_index_0 >> 6] |= static_cast<uint64_t>(1) << (bit_index_0 & (64 - 1)); // active the voxel 0
303 : 1800000 : memcpy(&nodes3Ref.data[bit_index_0], vDatas, vByteSize * vCount);
304 : 1800000 : return true;
305 : 1800000 : }
306 : 0 : return false;
307 : 1800000 : }
308 : :
309 : 900000 : bool addVoxel(uint32_t vX, uint32_t vY, uint32_t vZ, const std::array<TType, TCount>& vDatas) {
310 : 900000 : return addVoxel(vX, vY, vZ, const_cast<TType*>(vDatas.data()), sizeof(TType), TCount);
311 : 900000 : }
312 : :
313 : 20 : void write(FILE* fp) override {
314 : 20 : write_name(fp, m_Name);
315 : 20 : write_name(fp, getTypeName());
316 : 20 : write_data<uint32_t>(fp, 0); // Instance parent
317 : 20 : uint64_t stream_pos = ftell(fp);
318 : 20 : write_data<uint64_t>(fp, stream_pos + sizeof(uint64_t) * 3); // grid pos
319 : 20 : write_data<uint64_t>(fp, 0); // block pos
320 : 20 : write_data<uint64_t>(fp, 0); // end pos
321 : 20 : write_data<uint32_t>(fp, 0); // compression
322 : 20 : writeMetadata(fp);
323 : 20 : writeTransform(fp);
324 : 20 : writeTree(fp);
325 : 20 : }
326 : : };
327 : :
328 : : template <typename TType>
329 : : class VdbScalarGrid : public VdbTree<TType, 1> {
330 : : protected:
331 : : std::string getTypeName() override {
332 : : std::cout << "getTypeName is not specialized for your Type" << std::endl;
333 : : assert(0);
334 : : return "";
335 : : }
336 : :
337 : : public:
338 : 10 : VdbScalarGrid(const std::string& vName) : VdbTree<TType, 1>(vName) {
339 : 10 : }
340 : 10 : virtual ~VdbScalarGrid() = default;
341 : 900000 : bool addVoxel(uint32_t vX, uint32_t vY, uint32_t vZ, const TType& vDatas) {
342 : 900000 : return VdbTree<TType, 1>::addVoxel(vX, vY, vZ, (void*)&vDatas, sizeof(TType), 1U);
343 : 900000 : }
344 : : };
345 : :
346 : : typedef VdbScalarGrid<float> VdbFloatGrid;
347 : : template <>
348 : 10 : inline std::string VdbFloatGrid::getTypeName() {
349 : 10 : return "Tree_float_5_4_3";
350 : 10 : }
351 : :
352 : : typedef VdbScalarGrid<double> VdbDoubleGrid;
353 : : template <>
354 : 0 : inline std::string VdbDoubleGrid::getTypeName() {
355 : 0 : return "Tree_double_5_4_3";
356 : 0 : }
357 : :
358 : : template <typename TType>
359 : : class VdbVec3Grid : public VdbTree<TType, 3> {
360 : : protected:
361 : : std::string getTypeName() override {
362 : : std::cout << "getTypeName is not specialized for your Type" << std::endl;
363 : : assert(0);
364 : : return "";
365 : : }
366 : :
367 : : public:
368 : 10 : VdbVec3Grid(const std::string& vName) : VdbTree<TType, 3>(vName) {
369 : 10 : }
370 : 10 : virtual ~VdbVec3Grid() = default;
371 : 900000 : bool addVoxel(uint32_t vX, uint32_t vY, uint32_t vZ, const TType& v0, const TType& v1, const TType& v2) {
372 : 900000 : return VdbTree<TType, 3>::addVoxel(vX, vY, vZ, {v0, v1, v2});
373 : 900000 : }
374 : : };
375 : :
376 : : typedef VdbVec3Grid<float> VdbVec3sGrid;
377 : : template <>
378 : 10 : inline std::string VdbVec3sGrid::getTypeName() {
379 : 10 : return "Tree_vec3s_5_4_3";
380 : 10 : }
381 : :
382 : : typedef VdbVec3Grid<double> VdbVec3dGrid;
383 : : template <>
384 : 0 : inline std::string VdbVec3dGrid::getTypeName() {
385 : 0 : return "Tree_vec3d_5_4_3";
386 : 0 : }
387 : :
388 : : typedef VdbVec3Grid<int32_t> VdbVec3iGrid;
389 : : template <>
390 : 0 : inline std::string VdbVec3iGrid::getTypeName() {
391 : 0 : return "Tree_vec3i_5_4_3";
392 : 0 : }
393 : :
394 : : typedef VdbVec3Grid<uint32_t> VdbVec3uiGrid;
395 : : template <>
396 : 0 : inline std::string VdbVec3uiGrid::getTypeName() {
397 : 0 : return "Tree_vec3ui_5_4_3";
398 : 0 : }
399 : :
400 : : typedef uint32_t KeyFrame;
401 : : typedef uint32_t LayerId;
402 : :
403 : : class Writer {
404 : : private:
405 : : typedef std::unordered_map<LayerId, std::unique_ptr<ATree>> LayerContainer;
406 : : std::unordered_map<KeyFrame, LayerContainer> m_Trees;
407 : : KeyFrame m_CurrentKeyFrame = 0U;
408 : : FILE* m_file = nullptr;
409 : : int32_t m_LastError = 0;
410 : :
411 : : public:
412 : : template <typename TTtree>
413 : 20 : TTtree& getLayer(uint32_t vLayerId, const std::string& vLayerName) {
414 : 20 : auto& key = m_Trees[m_CurrentKeyFrame];
415 [ + - ][ + - ]: 20 : if (key.find(vLayerId) == key.end()) {
416 : 20 : key[vLayerId] = std::unique_ptr<TTtree>(new TTtree(vLayerName));
417 : 20 : }
418 : 20 : return static_cast<TTtree&>(*(key.at(vLayerId).get()));
419 : 20 : }
420 : :
421 : 10 : Writer& setKeyFrame(uint32_t vKeyFrame) {
422 : 10 : m_CurrentKeyFrame = vKeyFrame;
423 : 10 : return *this;
424 : 10 : }
425 : :
426 : 1 : Writer& save(const std::string& vFilePathName) {
427 [ + - ]: 1 : if (!vFilePathName.empty()) {
428 : 1 : auto dot_p = vFilePathName.find_last_of('.');
429 [ + - ]: 1 : if (dot_p != std::string::npos) {
430 : 1 : auto base_file_path_name = vFilePathName.substr(0, dot_p);
431 : 1 : size_t idx = 1;
432 [ + + ]: 10 : for (auto& vdb : m_Trees) {
433 : 10 : std::stringstream str;
434 [ + - ]: 10 : if (m_Trees.size() > 1) {
435 : 10 : str << base_file_path_name << "_" << std::setfill('0') << std::setw(4) << idx++ << ".vdb"; // many frames
436 : 10 : } else {
437 : 0 : str << base_file_path_name << ".vdb";
438 : 0 : }
439 [ + - ]: 10 : if (openFileForWriting(str.str())) {
440 : 10 : writeVdb(m_file, vdb.second);
441 : 10 : closeFile();
442 : 10 : } else {
443 : 0 : std::cout << "Error, cant write to the file " << str.str() << std::endl;
444 : 0 : }
445 : 10 : }
446 : 1 : }
447 : 1 : }
448 : 1 : return *this;
449 : 1 : }
450 : :
451 : : // common grid types
452 : 10 : VdbFloatGrid& getFloatLayer(uint32_t vLayerId, const std::string& vLayerName) {
453 : 10 : return getLayer<VdbFloatGrid>(vLayerId, vLayerName);
454 : 10 : }
455 : 0 : VdbDoubleGrid& getDoubleLayer(uint32_t vLayerId, const std::string& vLayerName) {
456 : 0 : return getLayer<VdbDoubleGrid>(vLayerId, vLayerName);
457 : 0 : }
458 : 10 : VdbVec3sGrid& getVec3sLayer(uint32_t vLayerId, const std::string& vLayerName) {
459 : 10 : return getLayer<VdbVec3sGrid>(vLayerId, vLayerName);
460 : 10 : }
461 : 0 : VdbVec3dGrid& getVec3dLayer(uint32_t vLayerId, const std::string& vLayerName) {
462 : 0 : return getLayer<VdbVec3dGrid>(vLayerId, vLayerName);
463 : 0 : }
464 : 0 : VdbVec3iGrid& getVec3iLayer(uint32_t vLayerId, const std::string& vLayerName) {
465 : 0 : return getLayer<VdbVec3iGrid>(vLayerId, vLayerName);
466 : 0 : }
467 : 0 : VdbVec3uiGrid& getVec3uiLayer(uint32_t vLayerId, const std::string& vLayerName) {
468 : 0 : return getLayer<VdbVec3uiGrid>(vLayerId, vLayerName);
469 : 0 : }
470 : :
471 : : private:
472 : 10 : static void writeVdb(FILE* fp, const LayerContainer& vTrees) {
473 : 10 : std::array<uint8_t, 8> header = {0x20, 0x42, 0x44, 0x56, 0x0, 0x0, 0x0, 0x0};
474 : 10 : write_ptr(fp, header.data(), sizeof(uint8_t), header.size());
475 : 10 : write_data<uint32_t>(fp, 224);
476 : 10 : write_data<uint32_t>(fp, 8); // major openvdb 8
477 : 10 : write_data<uint32_t>(fp, 1); // minor openvdb 8.1
478 : 10 : write_data<uint8_t>(fp, 0);
479 : 10 : write_string(fp, "00000000-0000-0000-0000-000000000000");
480 : 10 : write_data<uint32_t>(fp, 0);
481 : 10 : write_data<uint32_t>(fp, (uint32_t)vTrees.size());
482 [ + + ]: 20 : for (auto& tree : vTrees) {
483 : 20 : tree.second->write(fp);
484 : 20 : }
485 : 10 : }
486 : :
487 : 10 : bool openFileForWriting(const std::string& vFilePathName) {
488 : : #if _MSC_VER
489 : : m_LastError = fopen_s(&m_file, vFilePathName.c_str(), "wb");
490 : : #else
491 : 10 : m_file = fopen(vFilePathName.c_str(), "wb");
492 [ + - ]: 10 : m_LastError = m_file ? 0 : errno;
493 : 10 : #endif
494 : 10 : return (m_LastError == 0);
495 : 10 : }
496 : :
497 : 10 : void closeFile() {
498 : 10 : fclose(m_file);
499 : 10 : }
500 : :
501 : 0 : long getFilePos() const {
502 : 0 : return ftell(m_file);
503 : 0 : }
504 : :
505 : 0 : void setFilePos(const long& vPos) {
506 : 0 : fseek(m_file, vPos, SEEK_SET);
507 : 0 : }
508 : : };
509 : :
510 : : } // namespace vdb
511 : : } // namespace file
512 : : } // namespace ez
|