pm.cc 8.14 KB
Newer Older
1
2
#include "pm.hh"
#include <fstream>
3
#include <glm/glm.hpp>
4
#include <iostream>
5
6
7
8
9
10
11
#include <mutex>
#include <typeindex>
#include <unordered_map>
#include "../low_level_api.hh"

namespace polymesh
{
12
13
14
15
16
17
static std::unordered_map<std::string, std::unique_ptr<detail::GenericAttributeSerializer>> sSerializers;

void detail::register_attribute_serializer(const std::string &identifier, std::unique_ptr<detail::GenericAttributeSerializer> ptr)
{
    sSerializers[identifier] = std::move(ptr);
}
18

19
20
template <class Tag>
std::pair<std::string, detail::GenericAttributeSerializer *> find_serializer_for(primitive_attribute_base<Tag> const &attr)
21
{
22
23
24
25
26
27
    for (auto const &pair : sSerializers)
    {
        if (pair.second->is_compatible_to(attr))
            return {pair.first, pair.second.get()};
    }
    return {{}, nullptr};
28
29
}

Christian Mattes's avatar
Christian Mattes committed
30
struct pm_header
31
32
{
    char pm[4] = {'P', 'M', 0, 0};
33
34
35
    int32_t num_vertices;
    int32_t num_halfedges;
    int32_t num_faces;
36

37
38
39
40
    int32_t num_vertex_attributes;
    int32_t num_halfedge_attributes;
    int32_t num_edge_attributes;
    int32_t num_face_attributes;
41
42
43
44

    bool valid() const { return pm[0] == 'P' && pm[1] == 'M' && pm[2] == 0 && pm[3] == 0; }
};

Christian Mattes's avatar
Christian Mattes committed
45
46
template <class tag>
static std::istream &read_index(std::istream &in, primitive_index<tag> &idx)
47
48
{
    int32_t val;
49
    in.read(reinterpret_cast<char *>(&val), sizeof(int32_t));
50
51
52
53
    idx.value = val;
    return in;
}

Christian Mattes's avatar
Christian Mattes committed
54
55
template <class tag>
static std::ostream &write_index(std::ostream &out, primitive_index<tag> const &idx)
56
{
57
    const int32_t val = idx.value;
58
59
60
61
62
63
    return out.write(reinterpret_cast<char const *>(&val), sizeof(int32_t));
}

static std::ostream &write_string(std::ostream &out, std::string const &text) { return out.write(text.c_str(), text.size() + 1); }
static std::istream &read_string(std::istream &in, std::string &text) { return std::getline(in, text, '\0'); }

64
65
static const std::string unregistered_type_name = "UNREGISTERED_TYPE";

Christian Mattes's avatar
Christian Mattes committed
66
67
template <class tag>
static std::ostream &storeAttributes(std::ostream &out, std::map<std::string, std::unique_ptr<primitive_attribute_base<tag>>> const &attrs)
68
69
70
{
    for (auto const &attr : attrs)
    {
71
72
        write_string(out, attr.first); // Attribute Name

73
74
75
76
77
78
79
80
        auto const &ser = find_serializer_for(*attr.second);
        if (ser.second)
        {
            write_string(out, ser.first);             // Attribute Type
            ser.second->serialize(out, *attr.second); // Attribute Data
        }
        else
        {
81
            write_string(out, unregistered_type_name);
82
83
84
85
86
87
            std::cout << "polymesh::write_pm: " << attr.first << " has unregistered type and is not going to be written." << std::endl;
        }
    }
    return out;
}

Christian Mattes's avatar
Christian Mattes committed
88
template <class tag>
89
90
static bool restoreAttributes(std::istream &in, Mesh const &mesh, attribute_collection &attrs, uint32_t count)
{
Christian Mattes's avatar
Christian Mattes committed
91
    using tag_ptr = tag *;
92
93
94
95
96
97
98

    for (uint32_t i = 0; i < count; i++)
    {
        std::string attrName, attrType;
        read_string(in, attrName);
        read_string(in, attrType);

99
100
101
        if (attrType == unregistered_type_name)
            continue;

102
103
104
        auto it = sSerializers.find(attrType);
        if (it != sSerializers.end())
        {
Christian Mattes's avatar
Christian Mattes committed
105
            it->second->deserialize(in, mesh, attrs, attrName, tag_ptr{});
106
107
108
109
110
111
112
113
114
        }
        else
        {
            std::cout << "polymesh::read_pm: " << attrName << " has unregistered type " << attrType << ", unable to restore remaining attributes." << std::endl;
            return false;
        }
    }

    return true;
115
116
117
118
119
120
121
122
123
}

void write_pm(std::ostream &out, const Mesh &mesh, const attribute_collection &attributes)
{
    auto ll = low_level_api(mesh);

    if (!mesh.is_compact())
        std::cout << "polymesh::write_pm: saving a non-compact mesh." << std::endl;

Christian Mattes's avatar
Christian Mattes committed
124
    pm_header header;
125
126
127
    header.num_vertices = mesh.all_vertices().size();
    header.num_halfedges = mesh.all_halfedges().size();
    header.num_faces = mesh.all_faces().size();
128
129
130
131
    header.num_vertex_attributes = attributes.vertex_attributes().size();
    header.num_halfedge_attributes = attributes.halfedge_attributes().size();
    header.num_edge_attributes = attributes.edge_attributes().size();
    header.num_face_attributes = attributes.face_attributes().size();
132
133
    out.write(reinterpret_cast<char *>(&header), sizeof(header));

134
135
136
137
138
    // Store mesh topology
    for (int i = 0; i < header.num_faces; ++i)
        write_index(out, ll.halfedge_of(face_index(i)));
    for (int i = 0; i < header.num_vertices; i++)
        write_index(out, ll.outgoing_halfedge_of(vertex_index(i)));
139
140
141

    for (int i = 0; i < header.num_halfedges; ++i)
        write_index(out, ll.to_vertex_of(halfedge_index(i)));
142
143
    for (int i = 0; i < header.num_halfedges; ++i)
        write_index(out, ll.face_of(halfedge_index(i)));
144
145
146
147
148
    for (int i = 0; i < header.num_halfedges; ++i)
        write_index(out, ll.next_halfedge_of(halfedge_index(i)));
    for (int i = 0; i < header.num_halfedges; ++i)
        write_index(out, ll.prev_halfedge_of(halfedge_index(i)));

149
150
151
152
153
    // Store attributes
    storeAttributes(out, attributes.vertex_attributes());
    storeAttributes(out, attributes.halfedge_attributes());
    storeAttributes(out, attributes.edge_attributes());
    storeAttributes(out, attributes.face_attributes());
154
155
156
157
}

bool read_pm(std::istream &input, Mesh &mesh, attribute_collection &attributes)
{
Christian Mattes's avatar
Christian Mattes committed
158
    pm_header header;
159
160
161
162
163
164
165
    input.read(reinterpret_cast<char *>(&header), sizeof(header));
    assert(header.valid() && "PM-File contains the wrong magic number!");

    mesh.clear();
    auto ll = low_level_api(mesh);
    ll.alloc_primitives(header.num_vertices, header.num_faces, header.num_halfedges);

166
167
168
169
    for (int i = 0; i < header.num_faces; ++i)
        read_index(input, ll.halfedge_of(face_index(i)));
    for (int i = 0; i < header.num_vertices; i++)
        read_index(input, ll.outgoing_halfedge_of(vertex_index(i)));
170
171
172

    for (int i = 0; i < header.num_halfedges; ++i)
        read_index(input, ll.to_vertex_of(halfedge_index(i)));
173
174
    for (int i = 0; i < header.num_halfedges; ++i)
        read_index(input, ll.face_of(halfedge_index(i)));
175
176
177
178
179
    for (int i = 0; i < header.num_halfedges; ++i)
        read_index(input, ll.next_halfedge_of(halfedge_index(i)));
    for (int i = 0; i < header.num_halfedges; ++i)
        read_index(input, ll.prev_halfedge_of(halfedge_index(i)));

Christian Mattes's avatar
Christian Mattes committed
180
181
182
183
184
185
    // Restore attributes
    return restoreAttributes<vertex_tag>(input, mesh, attributes, header.num_vertex_attributes)
           && restoreAttributes<halfedge_tag>(input, mesh, attributes, header.num_halfedge_attributes)
           && restoreAttributes<edge_tag>(input, mesh, attributes, header.num_edge_attributes)
           && restoreAttributes<face_tag>(input, mesh, attributes, header.num_face_attributes) //
           && !input.fail();
186
187
188
189
190
191
192
193
194
195
196
197
198
}

void write_pm(const std::string &filename, const Mesh &mesh, const attribute_collection &attributes)
{
    std::ofstream out(filename, std::ios::binary | std::ios::trunc);
    write_pm(out, mesh, attributes);
}

bool read_pm(const std::string &filename, Mesh &mesh, attribute_collection &attributes)
{
    std::ifstream in(filename, std::ios::binary);
    return read_pm(in, mesh, attributes);
}
199
200
201
202


#define REGISTER_TYPE(type) register_type<type>(#type)
static bool registered_default_types = []() {
203
    REGISTER_TYPE(bool);
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
    REGISTER_TYPE(float);
    REGISTER_TYPE(double);
    REGISTER_TYPE(int8_t);
    REGISTER_TYPE(int16_t);
    REGISTER_TYPE(int32_t);
    REGISTER_TYPE(int64_t);
    REGISTER_TYPE(uint8_t);
    REGISTER_TYPE(uint16_t);
    REGISTER_TYPE(uint32_t);
    REGISTER_TYPE(uint64_t);
    REGISTER_TYPE(glm::vec2);
    REGISTER_TYPE(glm::vec3);
    REGISTER_TYPE(glm::vec4);
    REGISTER_TYPE(glm::dvec2);
    REGISTER_TYPE(glm::dvec3);
    REGISTER_TYPE(glm::dvec4);
    REGISTER_TYPE(glm::ivec2);
    REGISTER_TYPE(glm::ivec3);
    REGISTER_TYPE(glm::ivec4);
    REGISTER_TYPE(glm::uvec2);
    REGISTER_TYPE(glm::uvec3);
    REGISTER_TYPE(glm::uvec4);
    REGISTER_TYPE(glm::mat2x2);
    REGISTER_TYPE(glm::mat2x3);
    REGISTER_TYPE(glm::mat2x4);
    REGISTER_TYPE(glm::mat3x2);
    REGISTER_TYPE(glm::mat3x3);
    REGISTER_TYPE(glm::mat3x4);
    REGISTER_TYPE(glm::mat4x2);
    REGISTER_TYPE(glm::mat4x3);
    REGISTER_TYPE(glm::mat4x4);
    register_type<std::string>("std::string", detail::string_serdes{});
    return true;
}();
238
}