LCOV - code coverage report
Current view: top level - ezlibs - ezVdbWriter.hpp (source / functions) Coverage Total Hit
Test: Coverage (llvm-cov → lcov → genhtml) Lines: 85.7 % 321 275
Test Date: 2025-09-16 22:55:37 Functions: 53.1 % 113 60
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 78.8 % 66 52

             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
        

Generated by: LCOV version 2.0-1