Commit ec2bde01 authored by Christian Mattes's avatar Christian Mattes
Browse files

First PM version that can do custom attributes

parent baa18516
#pragma once
#include <iostream>
#include <memory>
#include <typeindex>
#include "../Mesh.hh"
#include "../attributes.hh"
namespace polymesh
......@@ -15,43 +17,42 @@ public:
virtual ~GenericAttributeSerializer() {}
/// can this attribute be (de)serialized by this serializer?
virtual bool isCompatibleTo(primitive_attribute_base<vertex_tag> const &attr) = 0;
virtual bool isCompatibleTo(primitive_attribute_base<halfedge_tag> const &attr) = 0;
virtual bool isCompatibleTo(primitive_attribute_base<edge_tag> const &attr) = 0;
virtual bool isCompatibleTo(primitive_attribute_base<face_tag> const &attr) = 0;
virtual bool is_compatible_to(primitive_attribute_base<vertex_tag> const &attr) = 0;
virtual bool is_compatible_to(primitive_attribute_base<halfedge_tag> const &attr) = 0;
virtual bool is_compatible_to(primitive_attribute_base<edge_tag> const &attr) = 0;
virtual bool is_compatible_to(primitive_attribute_base<face_tag> const &attr) = 0;
virtual void serialize(std::ostream &out, primitive_attribute_base<vertex_tag> const &attr) = 0;
virtual void serialize(std::ostream &out, primitive_attribute_base<halfedge_tag> const &attr) = 0;
virtual void serialize(std::ostream &out, primitive_attribute_base<edge_tag> const &attr) = 0;
virtual void serialize(std::ostream &out, primitive_attribute_base<face_tag> const &attr) = 0;
virtual void deserialize(std::istream &in, primitive_attribute_base<vertex_tag> &attr) = 0;
virtual void deserialize(std::istream &in, primitive_attribute_base<halfedge_tag> &attr) = 0;
virtual void deserialize(std::istream &in, primitive_attribute_base<edge_tag> &attr) = 0;
virtual void deserialize(std::istream &in, primitive_attribute_base<face_tag> &attr) = 0;
virtual std::type_index vertexAttributeType() = 0;
// pointer to tag as dummy parameter to allow deserialize to be used in templates over the tag type
virtual void deserialize(std::istream &in, Mesh const &mesh, attribute_collection &attrs, std::string const &name, vertex_tag *) = 0;
virtual void deserialize(std::istream &in, Mesh const &mesh, attribute_collection &attrs, std::string const &name, halfedge_tag *) = 0;
virtual void deserialize(std::istream &in, Mesh const &mesh, attribute_collection &attrs, std::string const &name, edge_tag *) = 0;
virtual void deserialize(std::istream &in, Mesh const &mesh, attribute_collection &attrs, std::string const &name, face_tag *) = 0;
};
template <typename T, typename SerDes>
class AttributeSerializer : GenericAttributeSerializer
template <typename T, typename serdes>
class AttributeSerializer final : public GenericAttributeSerializer
{
public:
AttributeSerializer(SerDes const& serdes) : mSerdes(serdes) {}
AttributeSerializer(serdes const &serializer) : mSerdes(serializer) {}
bool isCompatibleTo(primitive_attribute_base<vertex_tag> const &attr) override
bool is_compatible_to(primitive_attribute_base<vertex_tag> const &attr) override
{
return dynamic_cast<primitive_attribute<vertex_tag, T> const *>(&attr);
}
bool isCompatibleTo(primitive_attribute_base<halfedge_tag> const &attr) override
bool is_compatible_to(primitive_attribute_base<halfedge_tag> const &attr) override
{
return dynamic_cast<primitive_attribute<halfedge_tag, T> const *>(&attr);
}
bool isCompatibleTo(primitive_attribute_base<edge_tag> const &attr) override
bool is_compatible_to(primitive_attribute_base<edge_tag> const &attr) override
{
return dynamic_cast<primitive_attribute<edge_tag, T> const *>(&attr);
}
bool isCompatibleTo(primitive_attribute_base<face_tag> const &attr) override
bool is_compatible_to(primitive_attribute_base<face_tag> const &attr) override
{
return dynamic_cast<primitive_attribute<face_tag, T> const *>(&attr);
}
......@@ -62,19 +63,52 @@ public:
mSerdes.serialize(out, specific.data(), specific.size());
}
void deserialize(std::istream &in, primitive_attribute_base<vertex_tag> &attr) override
void serialize(std::ostream &out, primitive_attribute_base<halfedge_tag> const &attr) override
{
auto const &specific = dynamic_cast<primitive_attribute<halfedge_tag, T> const &>(attr);
mSerdes.serialize(out, specific.data(), specific.size());
}
void serialize(std::ostream &out, primitive_attribute_base<edge_tag> const &attr) override
{
auto const &specific = dynamic_cast<primitive_attribute<edge_tag, T> const &>(attr);
mSerdes.serialize(out, specific.data(), specific.size());
}
void serialize(std::ostream &out, primitive_attribute_base<face_tag> const &attr) override
{
auto &specific = dynamic_cast<primitive_attribute<vertex_tag, T> &>(attr);
mSerdes.deserialize(in, specific.data(), specific.size());
auto const &specific = dynamic_cast<primitive_attribute<face_tag, T> const &>(attr);
mSerdes.serialize(out, specific.data(), specific.size());
}
std::type_index vertexAttributeType() override {
return typeid (primitive_attribute<vertex_tag, T>);
void deserialize(std::istream &in, Mesh const &mesh, attribute_collection &attrs, std::string const &name, vertex_tag *) override
{
auto attr = mesh.vertices().make_attribute<T>();
mSerdes.deserialize(in, attr.data(), attr.size());
attrs[name] = attr;
}
void deserialize(std::istream &in, Mesh const &mesh, attribute_collection &attrs, std::string const &name, halfedge_tag *) override
{
auto attr = mesh.halfedges().make_attribute<T>();
mSerdes.deserialize(in, attr.data(), attr.size());
attrs[name] = attr;
}
void deserialize(std::istream &in, Mesh const &mesh, attribute_collection &attrs, std::string const &name, edge_tag *) override
{
auto attr = mesh.edges().make_attribute<T>();
mSerdes.deserialize(in, attr.data(), attr.size());
attrs[name] = attr;
}
void deserialize(std::istream &in, Mesh const &mesh, attribute_collection &attrs, std::string const &name, face_tag *) override
{
auto attr = mesh.faces().make_attribute<T>();
mSerdes.deserialize(in, attr.data(), attr.size());
attrs[name] = attr;
}
private:
SerDes mSerdes;
serdes mSerdes;
};
}
}
#include "pm.hh"
#include <iostream>
#include <fstream>
#include <iostream>
#include <mutex>
#include <typeindex>
#include <unordered_map>
......@@ -8,28 +8,35 @@
namespace polymesh
{
static std::unordered_map<std::string, std::unique_ptr<detail::GenericAttributeSerializer>> sSerializersByName;
static std::unordered_map<std::type_index, detail::GenericAttributeSerializer *> sSerializersByTypeIndex;
static std::mutex sSerializersMutex;
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);
}
void registerAttributeSerializer(const std::string &identifier, std::unique_ptr<detail::GenericAttributeSerializer> ptr)
template <class Tag>
std::pair<std::string, detail::GenericAttributeSerializer *> find_serializer_for(primitive_attribute_base<Tag> const &attr)
{
std::lock_guard<std::mutex> _(sSerializersMutex);
sSerializersByTypeIndex[ptr->vertexAttributeType()] = ptr.get();
sSerializersByName[identifier] = std::move(ptr);
for (auto const &pair : sSerializers)
{
if (pair.second->is_compatible_to(attr))
return {pair.first, pair.second.get()};
}
return {{}, nullptr};
}
struct PMHeader
{
char pm[4] = {'P', 'M', 0, 0};
uint32_t num_vertices;
uint32_t num_halfedges;
uint32_t num_faces;
int32_t num_vertices;
int32_t num_halfedges;
int32_t num_faces;
uint32_t num_vertex_attributes;
uint32_t num_halfedge_attributes;
uint32_t num_edge_attributes;
uint32_t num_face_attributes;
int32_t num_vertex_attributes;
int32_t num_halfedge_attributes;
int32_t num_edge_attributes;
int32_t num_face_attributes;
bool valid() const { return pm[0] == 'P' && pm[1] == 'M' && pm[2] == 0 && pm[3] == 0; }
};
......@@ -38,15 +45,65 @@ template <class Tag>
static std::istream &read_index(std::istream &in, primitive_index<Tag> &idx)
{
int32_t val;
in.read(reinterpret_cast<char*>(&val), sizeof(int32_t));
in.read(reinterpret_cast<char *>(&val), sizeof(int32_t));
idx.value = val;
return in;
}
template <class Tag>
static std::ostream& write_index(std::ostream& out, primitive_index<Tag> const& idx) {
static std::ostream &write_index(std::ostream &out, primitive_index<Tag> const &idx)
{
const int32_t val = idx.value;
return out.write(reinterpret_cast<char const*>(&val), sizeof(int32_t));
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'); }
template <class Tag>
static std::ostream &storeAttributes(std::ostream &out, std::map<std::string, std::unique_ptr<primitive_attribute_base<Tag>>> const &attrs)
{
for (auto const &attr : attrs)
{
auto const &ser = find_serializer_for(*attr.second);
if (ser.second)
{
write_string(out, attr.first); // Attribute Name
write_string(out, ser.first); // Attribute Type
ser.second->serialize(out, *attr.second); // Attribute Data
}
else
{
std::cout << "polymesh::write_pm: " << attr.first << " has unregistered type and is not going to be written." << std::endl;
}
}
return out;
}
template <class Tag>
static bool restoreAttributes(std::istream &in, Mesh const &mesh, attribute_collection &attrs, uint32_t count)
{
using TagPtr = Tag *;
for (uint32_t i = 0; i < count; i++)
{
std::string attrName, attrType;
read_string(in, attrName);
read_string(in, attrType);
auto it = sSerializers.find(attrType);
if (it != sSerializers.end())
{
it->second->deserialize(in, mesh, attrs, attrName, TagPtr{});
}
else
{
std::cout << "polymesh::read_pm: " << attrName << " has unregistered type " << attrType << ", unable to restore remaining attributes." << std::endl;
return false;
}
}
return true;
}
void write_pm(std::ostream &out, const Mesh &mesh, const attribute_collection &attributes)
......@@ -60,25 +117,32 @@ void write_pm(std::ostream &out, const Mesh &mesh, const attribute_collection &a
header.num_vertices = mesh.all_vertices().size();
header.num_halfedges = mesh.all_halfedges().size();
header.num_faces = mesh.all_faces().size();
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();
out.write(reinterpret_cast<char *>(&header), sizeof(header));
for (int i = 0; i < header.num_halfedges; ++i)
write_index(out, ll.face_of(halfedge_index(i)));
// 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)));
for (int i = 0; i < header.num_halfedges; ++i)
write_index(out, ll.to_vertex_of(halfedge_index(i)));
for (int i = 0; i < header.num_halfedges; ++i)
write_index(out, ll.face_of(halfedge_index(i)));
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)));
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)));
// Store attributes
storeAttributes(out, attributes.vertex_attributes());
storeAttributes(out, attributes.halfedge_attributes());
storeAttributes(out, attributes.edge_attributes());
storeAttributes(out, attributes.face_attributes());
}
bool read_pm(std::istream &input, Mesh &mesh, attribute_collection &attributes)
......@@ -91,23 +155,25 @@ bool read_pm(std::istream &input, Mesh &mesh, attribute_collection &attributes)
auto ll = low_level_api(mesh);
ll.alloc_primitives(header.num_vertices, header.num_faces, header.num_halfedges);
for (int i = 0; i < header.num_halfedges; ++i)
read_index(input, ll.face_of(halfedge_index(i)));
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)));
for (int i = 0; i < header.num_halfedges; ++i)
read_index(input, ll.to_vertex_of(halfedge_index(i)));
for (int i = 0; i < header.num_halfedges; ++i)
read_index(input, ll.face_of(halfedge_index(i)));
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)));
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)));
// Store attributes
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);
return !input.fail();
}
......@@ -123,5 +189,4 @@ bool read_pm(const std::string &filename, Mesh &mesh, attribute_collection &attr
std::ifstream in(filename, std::ios::binary);
return read_pm(in, mesh, attributes);
}
}
......@@ -24,17 +24,31 @@ namespace detail
template <typename T>
struct bytewise_serdes
{
void serialize(std::ostream &out, T const *data, size_t num_items) { out.write(static_cast<char const *>(data), num_items * sizeof(T)); }
void deserialize(std::istream &in, T *data, size_t num_items) { in.read(static_cast<char *>(data), num_items * sizeof(T)); }
void serialize(std::ostream &out, T const *data, size_t num_items) const { out.write(reinterpret_cast<char const *>(data), num_items * sizeof(T)); }
void deserialize(std::istream &in, T *data, size_t num_items) const { in.read(reinterpret_cast<char *>(data), num_items * sizeof(T)); }
};
void registerAttributeSerializer(std::string const &identifier, std::unique_ptr<detail::GenericAttributeSerializer> ptr);
struct string_serdes
{
void serialize(std::ostream &out, std::string const *strings, size_t num_items) const
{
for (size_t i = 0; i < num_items; i++)
out.write(strings[i].c_str(), strings[i].size() + 1);
}
void deserialize(std::istream &in, std::string *strings, size_t num_items) const
{
for (size_t i = 0; i < num_items; i++)
std::getline(in, strings[i], '\0');
}
};
void register_attribute_serializer(std::string const &identifier, std::unique_ptr<detail::GenericAttributeSerializer> ptr);
}
template <typename T, typename SerDes>
void registerType(std::string const &identifier, SerDes &&serializer = detail::bytewise_serdes<T>{})
template <typename T, typename serdes = detail::bytewise_serdes<T>>
void register_type(std::string const &identifier, serdes &&serializer = detail::bytewise_serdes<T>{})
{
auto ptr = std::make_unique<detail::AttributeSerializer<T, SerDes>>(serializer);
detail::registerAttributeSerializer(identifier, std::move(ptr));
auto ptr = std::make_unique<detail::AttributeSerializer<T, serdes>>(serializer);
detail::register_attribute_serializer(identifier, std::move(ptr));
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment